Skip to content

Commit

Permalink
fix(vscode): improve ux for update token. (#3631)
Browse files Browse the repository at this point in the history
  • Loading branch information
icycodes authored Dec 29, 2024
1 parent e864fd6 commit 3760583
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 42 deletions.
9 changes: 9 additions & 0 deletions clients/vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@
"title": "Connect to Server...",
"category": "Tabby"
},
{
"command": "tabby.updateToken",
"title": "Update Token...",
"category": "Tabby"
},
{
"command": "tabby.openSettings",
"title": "Open Settings",
Expand Down Expand Up @@ -160,6 +165,10 @@
"command": "tabby.inlineCompletion.trigger",
"when": "tabby.inlineCompletionTriggerMode === 'manual' && !editorHasSelection && !inlineSuggestionsVisible"
},
{
"command": "tabby.updateToken",
"when": "tabby.status === 'unauthorized'"
},
{
"command": "tabby.openTabbyAgentSettings",
"when": "!isWeb"
Expand Down
15 changes: 14 additions & 1 deletion clients/vscode/src/ContextVariables.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,21 @@ export class ContextVariables {
private readonly client: Client,
private readonly config: Config,
) {
this.status = client.status.current?.status;
this.client.status.on("didChange", () => {
this.status = client.status.current?.status;
});

this.chatEnabled = this.client.chat.isAvailable;
this.inlineCompletionTriggerMode = config.inlineCompletionTriggerMode;
this.client.chat.on("didChangeAvailability", (params: boolean) => {
this.chatEnabled = params;
});

this.inlineCompletionTriggerMode = config.inlineCompletionTriggerMode;
this.config.on("updated", () => {
this.inlineCompletionTriggerMode = config.inlineCompletionTriggerMode;
});

this.updateChatEditResolving();
window.onDidChangeTextEditorSelection((params) => {
if (params.textEditor === window.activeTextEditor) {
Expand Down Expand Up @@ -50,6 +57,12 @@ export class ContextVariables {
this.chatEditResolving = false;
}

set status(value: string | undefined) {
commands.executeCommand("setContext", "tabby.status", value);
}

// FIXME(@icycodes): context variables should not have getters

get chatEnabled(): boolean {
return this.chatEnabledValue;
}
Expand Down
3 changes: 1 addition & 2 deletions clients/vscode/src/chat/webview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -453,7 +453,6 @@ export class ChatWebview {

private checkStatusAndLoadContent() {
const statusInfo = this.lspClient.status.current;
console.log("statusInfo", statusInfo);
const error = this.checkStatusInfo(statusInfo);
if (error) {
this.currentConfig = undefined;
Expand Down Expand Up @@ -517,7 +516,7 @@ export class ChatWebview {
}

if (statusInfo.status === "unauthorized") {
return "Your token is invalid.<br/><a href='command:tabby.connectToServer'><b>Connect To Server</b></a>";
return "Your token is invalid.<br/><a href='command:tabby.updateToken'><b>Update Token</b></a>";
}

if (statusInfo.status === "disconnected") {
Expand Down
71 changes: 47 additions & 24 deletions clients/vscode/src/commands/commandPalette.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { commands, window, Command, QuickPick, QuickPickItem, QuickPickItemKind,
import { State as LanguageClientState } from "vscode-languageclient";
import { Client } from "../lsp/Client";
import { Config } from "../Config";
import { isBrowser } from "../env";

const MENU_ITEM_INDENT_SPACING = " ";

Expand All @@ -21,25 +22,32 @@ export class CommandPalette {
quickPick.title = "Tabby Command Palette";
const items: CommandPaletteItem[] = [];

items.push({ label: "status", kind: QuickPickItemKind.Separator }, this.itemForStatus(), {
label: "settings",
kind: QuickPickItemKind.Separator,
});

// Status section
const status = this.client.status.current?.status;
items.push(
{
label: "status",
kind: QuickPickItemKind.Separator,
},
this.itemForStatus(),
);

this.client.status.on("didChange", () => {
items[1] = this.itemForStatus();
quickPick.items = items;
});

// Features section
const validStatuses = ["ready", "readyForAutoTrigger", "readyForManualTrigger"];
if (validStatuses.includes(this.client.status.current?.status || "")) {
if (status !== undefined && validStatuses.includes(status)) {
const iconPath = this.config.inlineCompletionTriggerMode === "automatic" ? new ThemeIcon("check") : undefined;
const labelPrefix = iconPath ? "" : MENU_ITEM_INDENT_SPACING;

items.push(
{ label: "enable/disable features", kind: QuickPickItemKind.Separator },
{
label: "enable/disable features",
kind: QuickPickItemKind.Separator,
},
{
label: labelPrefix + "Code Completion",
detail: MENU_ITEM_INDENT_SPACING + "Toggle between automatic and manual completion mode",
Expand All @@ -62,32 +70,47 @@ export class CommandPalette {

// Settings section
items.push(
{ label: "settings", kind: QuickPickItemKind.Separator },
{
label: "settings",
kind: QuickPickItemKind.Separator,
},
{
label: "Connect to Server",
command: "tabby.connectToServer",
iconPath: new ThemeIcon("plug"),
},
{
label: "Settings",
command: "tabby.openSettings",
iconPath: new ThemeIcon("settings"),
},
{
);
if (status === "unauthorized") {
items.push({
label: "Update Token",
command: "tabby.updateToken",
iconPath: new ThemeIcon("key"),
});
}
items.push({
label: "Settings",
command: "tabby.openSettings",
iconPath: new ThemeIcon("settings"),
});
if (!isBrowser) {
items.push({
label: "Agent Settings",
command: "tabby.openTabbyAgentSettings",
iconPath: new ThemeIcon("tools"),
},
{
label: "Show Logs",
command: "tabby.outputPanel.focus",
iconPath: new ThemeIcon("output"),
},
);
});
}
items.push({
label: "Show Logs",
command: "tabby.outputPanel.focus",
iconPath: new ThemeIcon("output"),
});

// Help section
items.push(
{ label: "help & support", kind: QuickPickItemKind.Separator },
{
label: "help & support",
kind: QuickPickItemKind.Separator,
},
{
label: "Help",
description: "Open online documentation",
Expand Down Expand Up @@ -136,8 +159,8 @@ export class CommandPalette {
case "unauthorized": {
return {
label: `${STATUS_PREFIX}Unauthorized`,
description: "Update the settings to connect to Tabby Server",
command: "tabby.connectToServer",
description: "Update your token to connect to Tabby Server",
command: "tabby.updateToken",
};
}
case "disconnected": {
Expand Down
43 changes: 30 additions & 13 deletions clients/vscode/src/commands/connectToServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,12 @@ export class ConnectToServerWidget {
private config: Config,
) {}

/**
* Show the widget to connect to a Tabby Server:
* 1. Input the URL of the Tabby Server, show the recent server list for quick selection.
* 2. If no token saved for the server, ask for the token.
* 3. Ensure the connection to the server.
*/
async show(): Promise<void> {
return new Promise((resolve) => {
const quickPick = this.quickPick;
Expand All @@ -46,6 +52,7 @@ export class ConnectToServerWidget {
title: "Enter your token",
placeHolder: "auth_" + "*".repeat(32),
password: true,
ignoreFocusOut: true,
});
if (token == undefined) {
// User canceled
Expand Down Expand Up @@ -81,14 +88,25 @@ export class ConnectToServerWidget {
});
}

private async updateToken(): Promise<void> {
/**
* Show the widget to update the token for the current server:
* 1. Ask for the new token.
* 2. Ensure the connection to the server.
*/
async showUpdateTokenWidget(): Promise<void> {
const serverRecords = this.config.serverRecords;
const endpoint = this.config.serverEndpoint;

if (endpoint == "") {
// Should not reach here
throw new Error("This method should not be called when using the config from Tabby Agent Settings.");
}

const token = await window.showInputBox({
title: "Your token is invalid. Please update your token",
placeHolder: "auth_" + "*".repeat(32),
password: true,
ignoreFocusOut: true,
});
if (token == undefined) {
// User canceled
Expand Down Expand Up @@ -119,9 +137,9 @@ export class ConnectToServerWidget {
modal: true,
detail: statusInfo.helpMessage,
},
"Retry",
"Select Server",
);
if (selected == "Retry") {
if (selected == "Select Server") {
const newWidget = new ConnectToServerWidget(this.client, this.config);
await newWidget.show();
}
Expand All @@ -142,7 +160,7 @@ export class ConnectToServerWidget {
"Update Token",
);
if (selected == "Update Token") {
await this.updateToken();
await this.showUpdateTokenWidget();
}
}
}
Expand All @@ -159,15 +177,14 @@ export class ConnectToServerWidget {
label: endpoint,
description: isCurrent ? "Current" : "",
iconPath: new ThemeIcon("server"),
buttons:
isCurrent || endpoint == defaultEndpoint
? []
: [
{
iconPath: new ThemeIcon("settings-remove"),
tooltip: "Remove from Recent Server List",
},
],
buttons: isCurrent
? []
: [
{
iconPath: new ThemeIcon("settings-remove"),
tooltip: "Remove from Recent Server List",
},
],
endpoint,
...record,
};
Expand Down
22 changes: 20 additions & 2 deletions clients/vscode/src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ export class Commands {
await this.config.updateInlineCompletionTriggerMode(target);
},
connectToServer: async (endpoint?: string | undefined) => {
if (endpoint) {
this.config.updateServerEndpoint(endpoint);
if (endpoint !== undefined) {
await this.config.updateServerEndpoint(endpoint);
} else {
const widget = new ConnectToServerWidget(this.client, this.config);
widget.show();
Expand All @@ -76,6 +76,24 @@ export class Commands {
reconnectToServer: async () => {
await this.client.status.fetchAgentStatusInfo({ recheckConnection: true });
},
updateToken: async (token?: string | undefined) => {
const endpoint = this.config.serverEndpoint;
if (token) {
if (endpoint == "") {
return;
}
const serverRecords = this.config.serverRecords;
serverRecords.set(endpoint, { token, updatedAt: Date.now() });
await this.config.updateServerRecords(serverRecords);
} else {
if (endpoint == "") {
await commands.executeCommand("tabby.openTabbyAgentSettings");
} else {
const widget = new ConnectToServerWidget(this.client, this.config);
widget.showUpdateTokenWidget();
}
}
},
openSettings: () => {
commands.executeCommand("workbench.action.openSettings", "@ext:TabbyML.vscode-tabby");
},
Expand Down

0 comments on commit 3760583

Please sign in to comment.