mirror of
https://github.com/QwenLM/qwen-code.git
synced 2025-12-19 09:33:53 +00:00
feat(vscode-ide-companion): implement manual login via /login command
BREAKING CHANGE: Login is no longer automatic when opening webview Changes: - Remove auto-login on webview open and restore - Add /login slash command for manual authentication - Add VSCode progress notification during login process - Add warning notification when user tries to chat without login - Implement pending message auto-retry after successful login - Add NotLoggedInMessage component (for future use) - Improve InfoBanner close button styling consistency User flow: 1. Open webview - no automatic login 2. Type /login or select from completion menu to login 3. Show "Logging in to Qwen Code..." progress notification 4. After login, show success message and auto-retry pending messages 5. If user tries to chat without login, show warning with "Login Now" button 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -378,7 +378,42 @@ export const App: React.FC = () => {
|
||||
const inputElement = inputFieldRef.current;
|
||||
const currentText = inputElement.textContent || '';
|
||||
|
||||
if (item.type === 'file') {
|
||||
if (item.type === 'command') {
|
||||
// Handle /login command directly
|
||||
if (item.label === '/login') {
|
||||
// Clear input field
|
||||
inputElement.textContent = '';
|
||||
setInputText('');
|
||||
// Close completion
|
||||
completion.closeCompletion();
|
||||
// Send login command to extension
|
||||
vscode.postMessage({
|
||||
type: 'login',
|
||||
data: {},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// For other commands, replace entire input with command
|
||||
inputElement.textContent = item.label + ' ';
|
||||
setInputText(item.label + ' ');
|
||||
|
||||
// Move cursor to end
|
||||
setTimeout(() => {
|
||||
const range = document.createRange();
|
||||
const sel = window.getSelection();
|
||||
if (inputElement.firstChild) {
|
||||
range.setStart(inputElement.firstChild, (item.label + ' ').length);
|
||||
range.collapse(true);
|
||||
} else {
|
||||
range.selectNodeContents(inputElement);
|
||||
range.collapse(false);
|
||||
}
|
||||
sel?.removeAllRanges();
|
||||
sel?.addRange(range);
|
||||
inputElement.focus();
|
||||
}, 10);
|
||||
} else if (item.type === 'file') {
|
||||
// Store file reference mapping
|
||||
const filePath = (item.value as string) || item.label;
|
||||
fileReferenceMap.current.set(item.label, filePath);
|
||||
@@ -441,32 +476,12 @@ export const App: React.FC = () => {
|
||||
inputElement.focus();
|
||||
}, 10);
|
||||
}
|
||||
} else if (item.type === 'command') {
|
||||
// Replace entire input with command
|
||||
inputElement.textContent = item.label + ' ';
|
||||
setInputText(item.label + ' ');
|
||||
|
||||
// Move cursor to end
|
||||
setTimeout(() => {
|
||||
const range = document.createRange();
|
||||
const sel = window.getSelection();
|
||||
if (inputElement.firstChild) {
|
||||
range.setStart(inputElement.firstChild, (item.label + ' ').length);
|
||||
range.collapse(true);
|
||||
} else {
|
||||
range.selectNodeContents(inputElement);
|
||||
range.collapse(false);
|
||||
}
|
||||
sel?.removeAllRanges();
|
||||
sel?.addRange(range);
|
||||
inputElement.focus();
|
||||
}, 10);
|
||||
}
|
||||
|
||||
// Close completion
|
||||
completion.closeCompletion();
|
||||
},
|
||||
[completion],
|
||||
[completion, vscode],
|
||||
);
|
||||
|
||||
// Handle attach context button click (Cmd/Ctrl + /)
|
||||
@@ -642,6 +657,7 @@ export const App: React.FC = () => {
|
||||
// Listen for messages from extension
|
||||
const handleMessage = (event: MessageEvent) => {
|
||||
const message = event.data;
|
||||
// console.log('[App] Received message from extension:', message.type, message);
|
||||
|
||||
switch (message.type) {
|
||||
case 'conversationLoaded': {
|
||||
@@ -714,6 +730,18 @@ export const App: React.FC = () => {
|
||||
setIsWaitingForResponse(false);
|
||||
break;
|
||||
|
||||
// case 'notLoggedIn':
|
||||
// // Show not logged in message with login button
|
||||
// console.log('[App] Received notLoggedIn message:', message.data);
|
||||
// setIsStreaming(false);
|
||||
// setIsWaitingForResponse(false);
|
||||
// setNotLoggedInMessage(
|
||||
// (message.data as { message: string })?.message ||
|
||||
// 'Please login to start chatting.',
|
||||
// );
|
||||
// console.log('[App] Set notLoggedInMessage to:', (message.data as { message: string })?.message);
|
||||
// break;
|
||||
|
||||
case 'permissionRequest':
|
||||
// Show permission dialog
|
||||
handlePermissionRequest(message.data);
|
||||
@@ -987,6 +1015,21 @@ export const App: React.FC = () => {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this is a /login command
|
||||
if (inputText.trim() === '/login') {
|
||||
// Clear input field
|
||||
setInputText('');
|
||||
if (inputFieldRef.current) {
|
||||
inputFieldRef.current.textContent = '';
|
||||
}
|
||||
// Send login command to extension
|
||||
vscode.postMessage({
|
||||
type: 'login',
|
||||
data: {},
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Set waiting state with random loading message
|
||||
setIsWaitingForResponse(true);
|
||||
setLoadingMessage(getRandomLoadingMessage());
|
||||
@@ -1380,6 +1423,24 @@ export const App: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Not Logged In Message with Login Button - COMMENTED OUT */}
|
||||
{/* {notLoggedInMessage && (
|
||||
<>
|
||||
{console.log('[App] Rendering NotLoggedInMessage with message:', notLoggedInMessage)}
|
||||
<NotLoggedInMessage
|
||||
message={notLoggedInMessage}
|
||||
onLoginClick={() => {
|
||||
setNotLoggedInMessage(null);
|
||||
vscode.postMessage({
|
||||
type: 'login',
|
||||
data: {},
|
||||
});
|
||||
}}
|
||||
onDismiss={() => setNotLoggedInMessage(null)}
|
||||
/>
|
||||
</>
|
||||
)} */}
|
||||
|
||||
{isStreaming && currentStreamContent && (
|
||||
<div className="message assistant streaming">
|
||||
<div className="message-content">
|
||||
|
||||
Reference in New Issue
Block a user