mirror of
https://github.com/Azure/cosmos-explorer.git
synced 2025-04-14 21:58:14 +01:00
bug fixes
This commit is contained in:
parent
2014dcd03d
commit
d6c0edf20d
@ -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 {
|
||||
|
@ -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"}} />;
|
||||
|
@ -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)}`));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
];
|
||||
|
@ -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 {
|
||||
|
@ -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())) {
|
||||
|
@ -143,6 +143,8 @@ export enum Action {
|
||||
ReadPersistedTabState,
|
||||
SavePersistedTabState,
|
||||
DeletePersistedTabState,
|
||||
CloudShellUserConsent,
|
||||
CloudShellTerminalSession
|
||||
}
|
||||
|
||||
export const ActionModifiers = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user