diff --git a/packages/vscode-ide-companion/src/services/authStateManager.ts b/packages/vscode-ide-companion/src/services/authStateManager.ts index 9614cae6..566a4afb 100644 --- a/packages/vscode-ide-companion/src/services/authStateManager.ts +++ b/packages/vscode-ide-companion/src/services/authStateManager.ts @@ -21,7 +21,6 @@ export class AuthStateManager { private static context: vscode.ExtensionContext | null = null; private static readonly AUTH_STATE_KEY = 'qwen.authState'; private static readonly AUTH_CACHE_DURATION = 24 * 60 * 60 * 1000; // 24 hours - //TODO: private constructor() {} /** diff --git a/packages/vscode-ide-companion/src/webview/App.tsx b/packages/vscode-ide-companion/src/webview/App.tsx index 23860c47..4b51d6b6 100644 --- a/packages/vscode-ide-companion/src/webview/App.tsx +++ b/packages/vscode-ide-companion/src/webview/App.tsx @@ -646,8 +646,7 @@ export const App: React.FC = () => {
{!hasContent ? ( @@ -655,12 +654,17 @@ export const App: React.FC = () => { <> {/* Render all messages and tool calls */} {renderMessages()} - {messageHandling.isWaitingForResponse && - messageHandling.loadingMessage && ( - - )} + {/* Flow-in persistent slot: keeps a small constant height so toggling */} + {/* the waiting message doesn't change list height to zero. When */} + {/* active, render the waiting message inline (not fixed). */} +
+ {messageHandling.isWaitingForResponse && + messageHandling.loadingMessage && ( + + )} +
diff --git a/packages/vscode-ide-companion/src/webview/PanelManager.ts b/packages/vscode-ide-companion/src/webview/PanelManager.ts index 72c7fa7b..44f1a6ec 100644 --- a/packages/vscode-ide-companion/src/webview/PanelManager.ts +++ b/packages/vscode-ide-companion/src/webview/PanelManager.ts @@ -201,8 +201,17 @@ export class PanelManager { */ revealPanel(preserveFocus: boolean = true): void { if (this.panel) { - // Reveal without forcing a specific column to avoid reflowing groups. - this.panel.reveal(undefined, preserveFocus); + // Prefer revealing in the currently tracked group to avoid reflowing groups. + const trackedColumn = ( + this.panelTab as unknown as { + group?: { viewColumn?: vscode.ViewColumn }; + } + )?.group?.viewColumn as vscode.ViewColumn | undefined; + const targetColumn: vscode.ViewColumn = + trackedColumn ?? + this.panelGroupViewColumn ?? + vscode.window.tabGroups.activeTabGroup.viewColumn; + this.panel.reveal(targetColumn, preserveFocus); } } @@ -236,7 +245,7 @@ export class PanelManager { group?: { viewColumn?: vscode.ViewColumn }; } )?.group?.viewColumn; - if (groupViewColumn != null) { + if (groupViewColumn !== null) { this.panelGroupViewColumn = groupViewColumn as vscode.ViewColumn; } } catch { @@ -257,7 +266,7 @@ export class PanelManager { this.panel.onDidDispose( () => { // Capture the group we intend to clean up before we clear fields - const targetColumn = + const targetColumn: vscode.ViewColumn | null = // Prefer the group from the captured tab if available (( this.panelTab as unknown as { @@ -266,7 +275,7 @@ export class PanelManager { )?.group?.viewColumn as vscode.ViewColumn | undefined) ?? // Fall back to our last-known group column this.panelGroupViewColumn ?? - undefined; + null; this.panel = null; this.panelTab = null; @@ -275,18 +284,19 @@ export class PanelManager { // After VS Code updates its tab model, check if that group is now // empty (and typically locked for Qwen). If so, close the group to // avoid leaving an empty locked column when the user closes Qwen. - if (targetColumn != null) { + if (targetColumn !== null) { + const column: vscode.ViewColumn = targetColumn; setTimeout(async () => { try { const groups = vscode.window.tabGroups.all; - const group = groups.find((g) => g.viewColumn === targetColumn); + const group = groups.find((g) => g.viewColumn === column); // If the group that hosted Qwen is now empty, close it to avoid // leaving an empty locked column around. VS Code's stable API // does not expose the lock state on TabGroup, so we only check // for emptiness here. if (group && group.tabs.length === 0) { // Focus the group we want to close - await this.focusGroupByColumn(targetColumn); + await this.focusGroupByColumn(column); // Try closeGroup first; fall back to removeActiveEditorGroup try { await vscode.commands.executeCommand( diff --git a/packages/vscode-ide-companion/src/webview/components/messages/Waiting/WaitingMessage.tsx b/packages/vscode-ide-companion/src/webview/components/messages/Waiting/WaitingMessage.tsx index fceeaaa8..68aceac8 100644 --- a/packages/vscode-ide-companion/src/webview/components/messages/Waiting/WaitingMessage.tsx +++ b/packages/vscode-ide-companion/src/webview/components/messages/Waiting/WaitingMessage.tsx @@ -65,20 +65,10 @@ export const WaitingMessage: React.FC = ({ }, [phrases]); return ( -
+
{/* Use the same left status icon (pseudo-element) style as assistant-message-container */} -
- +
+ {phrases[index]}
diff --git a/packages/vscode-ide-companion/src/webview/styles/App.css b/packages/vscode-ide-companion/src/webview/styles/App.css index 888c4ce3..e4ce12ea 100644 --- a/packages/vscode-ide-companion/src/webview/styles/App.css +++ b/packages/vscode-ide-companion/src/webview/styles/App.css @@ -47,9 +47,15 @@ --app-input-highlight: var(--app-qwen-theme); /* Code Highlighting */ - --app-code-background: var(--vscode-textCodeBlock-background, rgba(0, 0, 0, 0.05)); - --app-link-foreground: var(--vscode-textLink-foreground, #007ACC); - --app-link-active-foreground: var(--vscode-textLink-activeForeground, #005A9E); + --app-code-background: var( + --vscode-textCodeBlock-background, + rgba(0, 0, 0, 0.05) + ); + --app-link-foreground: var(--vscode-textLink-foreground, #007acc); + --app-link-active-foreground: var( + --vscode-textLink-activeForeground, + #005a9e + ); /* List Styles */ --app-list-hover-background: var(--vscode-list-hoverBackground); @@ -167,7 +173,8 @@ button { } @keyframes pulse { - 0%, 100% { + 0%, + 100% { opacity: 1; } 50% { @@ -176,7 +183,9 @@ button { } @keyframes typingPulse { - 0%, 60%, 100% { + 0%, + 60%, + 100% { transform: scale(0.7); opacity: 0.6; } @@ -251,7 +260,8 @@ button { /* Animation for in-progress status (used by pseudo bullets and spinners) */ @keyframes pulse { - 0%, 100% { + 0%, + 100% { opacity: 1; } 50% {