bug fixes

This commit is contained in:
Sourabh Jain 2025-04-10 13:43:45 +05:30
parent 2014dcd03d
commit d6c0edf20d
7 changed files with 105 additions and 48 deletions

View File

@ -257,6 +257,7 @@ export class Areas {
public static ShareDialog: string = "Share Access Dialog";
public static Notebook: string = "Notebook";
public static Copilot: string = "Copilot";
public static CloudShell: string = "Cloud Shell";
}
export class HttpHeaders {

View File

@ -17,7 +17,6 @@ export const CloudShellTerminalComponent: React.FC<CloudShellTerminalComponentPr
const terminalRef = useRef(null); // Reference for terminal container
const xtermRef = useRef(null); // Reference for XTerm instance
const socketRef = useRef(null); // Reference for WebSocket
const fitAddon = new FitAddon();
useEffect(() => {
// Initialize XTerm instance
@ -34,18 +33,33 @@ export const CloudShellTerminalComponent: React.FC<CloudShellTerminalComponentPr
scrollback: 1000
});
const fitAddon = new FitAddon();
term.loadAddon(fitAddon);
fitAddon.fit(); // Fit the terminal to the container size
// Attach terminal to the DOM
if (terminalRef.current) {
term.open(terminalRef.current);
xtermRef.current = term;
}
setTimeout(() => {
fitAddon.fit();
}, 0);
// Adjust terminal size on window resize
const handleResize = () => fitAddon.fit();
window.addEventListener('resize', handleResize);
// Use ResizeObserver instead of window resize
const resizeObserver = new ResizeObserver(() => {
const container = terminalRef.current;
if (
container &&
container.offsetWidth > 0 &&
container.offsetHeight > 0
) {
try {
fitAddon.fit();
} catch (e) {
console.warn("Fit failed on resize:", e);
}
}
});
resizeObserver.observe(terminalRef.current);
socketRef.current = startCloudShellTerminal(term, props.shellType);
@ -55,10 +69,11 @@ export const CloudShellTerminalComponent: React.FC<CloudShellTerminalComponentPr
if (socketRef.current && socketRef.current.readyState && socketRef.current.readyState === WebSocket.OPEN) {
socketRef.current.close(); // Close WebSocket connection
}
window.removeEventListener('resize', handleResize);
if (resizeObserver && terminalRef.current) {
resizeObserver.unobserve(terminalRef.current);
}
term.dispose(); // Clean up XTerm instance
};
}, []);
return <div ref={terminalRef} style={{ width: "100%", height: "500px"}} />;

View File

@ -3,8 +3,12 @@
* Core functionality for CloudShell terminal management
*/
import { getErrorMessage, getErrorStack } from "Common/ErrorHandlingUtils";
import { Terminal } from "xterm";
import { Areas } from "../../../Common/Constants";
import { TerminalKind } from "../../../Contracts/ViewModels";
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../../../UserContext";
import {
authorizeSession,
@ -14,7 +18,7 @@ import {
registerCloudShellProvider,
verifyCloudShellProviderRegistration
} from "./Data/CloudShellClient";
import { START_MARKER, AbstractShellHandler } from "./ShellTypes/AbstractShellHandler";
import { AbstractShellHandler, START_MARKER } from "./ShellTypes/AbstractShellHandler";
import { ShellTypeHandlerFactory } from "./ShellTypes/ShellTypeFactory";
import { AttachAddon } from "./Utils/AttachAddOn";
import { askConfirmation, wait } from "./Utils/CommonUtils";
@ -37,42 +41,72 @@ const MAX_PING_COUNT = 20 * 60; // 20 minutes (60 seconds/minute)
export const startCloudShellTerminal =
async (terminal: Terminal, shellType: TerminalKind): Promise<WebSocket> => {
await ensureCloudShellProviderRegistered();
const startKey = TelemetryProcessor.traceStart(Action.CloudShellTerminalSession, {
shellType: TerminalKind[shellType],
dataExplorerArea: Areas.CloudShell
});
const resolvedRegion = determineCloudShellRegion();
// Ask for user consent for region
const consentGranted = await askConfirmation(terminal, formatWarningMessage("This shell might be in a different region than the database region. Do you want to proceed?"));
if (!consentGranted) {
return null; // Exit if user declined
try {
await ensureCloudShellProviderRegistered();
const resolvedRegion = determineCloudShellRegion();
// Ask for user consent for region
const consentGranted = await askConfirmation(terminal, formatWarningMessage("This shell might be in a different region than the database region. Do you want to proceed?"));
// Track user decision
TelemetryProcessor.trace(Action.CloudShellUserConsent,
consentGranted ? ActionModifiers.Success : ActionModifiers.Cancel,
{ dataExplorerArea: Areas.CloudShell }
);
if (!consentGranted) {
return null; // Exit if user declined
}
terminal.writeln(formatInfoMessage("Connecting to CloudShell....."));
let sessionDetails: {
socketUri?: string;
provisionConsoleResponse?: any;
targetUri?: string;
};
sessionDetails = await provisionCloudShellSession(resolvedRegion, terminal);
if (!sessionDetails.socketUri) {
terminal.writeln(formatErrorMessage("Failed to establish a connection. Please try again later."));
return null;
}
// Get the shell handler for this type
const shellHandler = await ShellTypeHandlerFactory.getHandler(shellType);
// Configure WebSocket connection with shell-specific commands
const socket = await establishTerminalConnection(
terminal,
shellHandler,
sessionDetails.socketUri,
sessionDetails.provisionConsoleResponse,
sessionDetails.targetUri
);
TelemetryProcessor.traceSuccess(Action.CloudShellTerminalSession, {
shellType: TerminalKind[shellType],
dataExplorerArea: Areas.CloudShell,
region: resolvedRegion
}, startKey);
return socket;
}
catch (err) {
TelemetryProcessor.traceFailure(Action.CloudShellTerminalSession, {
shellType: TerminalKind[shellType],
dataExplorerArea: Areas.CloudShell,
error: getErrorMessage(error),
errorStack: getErrorStack(error)
}, startKey);
terminal.writeln(formatInfoMessage("Connecting to CloudShell....."));
let sessionDetails: {
socketUri?: string;
provisionConsoleResponse?: any;
targetUri?: string;
};
sessionDetails = await provisionCloudShellSession(resolvedRegion, terminal);
if (!sessionDetails.socketUri) {
terminal.writeln(formatErrorMessage("Failed to establish a connection. Please try again later."));
return null;
}
// Get the shell handler for this type
const shellHandler = await ShellTypeHandlerFactory.getHandler(shellType);
// Configure WebSocket connection with shell-specific commands
const socket = await establishTerminalConnection(
terminal,
shellHandler,
sessionDetails.socketUri,
sessionDetails.provisionConsoleResponse,
sessionDetails.targetUri
);
return socket;
terminal.writeln(formatErrorMessage(`Failed with error.${getErrorMessage(error)}`));
}
};
/**

View File

@ -1,4 +1,5 @@
export const START_MARKER = `echo "START INITIALIZATION" > /dev/null`;
export const DISABLE_HISTORY = `set +o history`;
export abstract class AbstractShellHandler {
@ -14,6 +15,7 @@ export abstract class AbstractShellHandler {
const allCommands = [
START_MARKER,
DISABLE_HISTORY,
...setupCommands,
connectionCommand
];

View File

@ -33,7 +33,7 @@ export class PostgresShellHandler extends AbstractShellHandler {
}
public getConnectionCommand(): string {
return `psql 'read -p "Enter Database Name: " dbname && read -p "Enter Username: " username && host=${this.getEndpoint()} port=5432 dbname=$dbname user=$username sslmode=require'`;
return `read -p "Enter Database Name: " dbname && read -p "Enter Username: " username && psql -h "${this.getEndpoint()}" -p 5432 -d "$dbname" -U "$username" --set=sslmode=require`;
}
public getTerminalSuppressedData(): string {

View File

@ -83,11 +83,14 @@ export class AttachAddon implements ITerminalAddon {
this._allowTerminalWrite = false;
terminal.write(`Preparing ${this._shellHandler.getShellName()} environment...\r\n`);
}
if (this._allowTerminalWrite &&
this._shellHandler?.getTerminalSuppressedData() &&
this._shellHandler?.getTerminalSuppressedData().length > 0 &&
!data.includes(this._shellHandler?.getTerminalSuppressedData())) {
terminal.write(data);
if (this._allowTerminalWrite) {
const suppressedData = this._shellHandler?.getTerminalSuppressedData();
const hasSuppressedData = suppressedData && suppressedData.length > 0;
if (!hasSuppressedData || !data.includes(suppressedData)) {
terminal.write(data);
}
}
if (data.includes(this._shellHandler.getConnectionCommand())) {

View File

@ -143,6 +143,8 @@ export enum Action {
ReadPersistedTabState,
SavePersistedTabState,
DeletePersistedTabState,
CloudShellUserConsent,
CloudShellTerminalSession
}
export const ActionModifiers = {