Skip to content

Commit 065bc77

Browse files
committed
Add manage credentials command
Replace debug-only coder.debug.listDeployments with user-facing coder.manageCredentials command. Includes "Remove All" option with confirmation dialog when multiple deployments are stored.
1 parent b9da49b commit 065bc77

File tree

3 files changed

+79
-42
lines changed

3 files changed

+79
-42
lines changed

package.json

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -288,9 +288,9 @@
288288
"icon": "$(search)"
289289
},
290290
{
291-
"command": "coder.debug.listDeployments",
292-
"title": "List Stored Deployments",
293-
"category": "Coder Debug"
291+
"command": "coder.manageCredentials",
292+
"title": "Manage Stored Credentials",
293+
"category": "Coder"
294294
}
295295
],
296296
"menus": {
@@ -352,8 +352,7 @@
352352
"when": "false"
353353
},
354354
{
355-
"command": "coder.debug.listDeployments",
356-
"when": "coder.devMode"
355+
"command": "coder.manageCredentials"
357356
}
358357
],
359358
"view/title": [

src/commands.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,78 @@ export class Commands {
243243
await this.performLogin();
244244
}
245245

246+
/**
247+
* Manage stored credentials for all deployments.
248+
* Shows a list of deployments with options to remove individual or all credentials.
249+
*/
250+
public async manageCredentials(): Promise<void> {
251+
try {
252+
const hostnames = await this.secretsManager.getKnownSafeHostnames();
253+
if (hostnames.length === 0) {
254+
vscode.window.showInformationMessage("No stored credentials.");
255+
return;
256+
}
257+
258+
const items: Array<{
259+
label: string;
260+
description: string;
261+
hostname: string | undefined;
262+
}> = hostnames.map((hostname) => ({
263+
label: `$(key) ${hostname}`,
264+
description: "Remove stored credentials",
265+
hostname,
266+
}));
267+
268+
// Only show "Remove All" when there are multiple deployments
269+
if (hostnames.length > 1) {
270+
items.push({
271+
label: "$(trash) Remove All",
272+
description: `Remove credentials for all ${hostnames.length} deployments`,
273+
hostname: undefined,
274+
});
275+
}
276+
277+
const selected = await vscode.window.showQuickPick(items, {
278+
title: "Manage Stored Credentials",
279+
placeHolder: "Select a deployment to remove",
280+
});
281+
282+
if (!selected) {
283+
return;
284+
}
285+
286+
if (selected.hostname) {
287+
await this.secretsManager.clearAllAuthData(selected.hostname);
288+
vscode.window.showInformationMessage(
289+
`Removed credentials for ${selected.hostname}`,
290+
);
291+
} else {
292+
const confirm = await vscodeProposed.window.showWarningMessage(
293+
`Remove ${hostnames.length} Credentials`,
294+
{
295+
useCustom: true,
296+
modal: true,
297+
detail: `This will remove credentials for: ${hostnames.join(", ")}\n\nYou'll need to log in again to access them.`,
298+
},
299+
"Remove All",
300+
);
301+
if (confirm === "Remove All") {
302+
await Promise.all(
303+
hostnames.map((h) => this.secretsManager.clearAllAuthData(h)),
304+
);
305+
vscode.window.showInformationMessage(
306+
"Removed credentials for all deployments",
307+
);
308+
}
309+
}
310+
} catch (error: unknown) {
311+
this.logger.error("Failed to manage stored credentials", error);
312+
vscode.window.showErrorMessage(
313+
"Failed to manage stored credentials. Storage may be corrupted.",
314+
);
315+
}
316+
}
317+
246318
/**
247319
* Create a new workspace for the currently logged-in deployment.
248320
*

src/extension.ts

Lines changed: 3 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,9 @@ export async function activate(ctx: vscode.ExtensionContext): Promise<void> {
244244
vscode.commands.registerCommand("coder.searchAllWorkspaces", async () =>
245245
showTreeViewSearch(ALL_WORKSPACES_TREE_ID),
246246
),
247-
vscode.commands.registerCommand("coder.debug.listDeployments", () =>
248-
listStoredDeployments(serviceContainer),
247+
vscode.commands.registerCommand(
248+
"coder.manageCredentials",
249+
commands.manageCredentials.bind(commands),
249250
),
250251
);
251252

@@ -387,38 +388,3 @@ async function showTreeViewSearch(id: string): Promise<void> {
387388
await vscode.commands.executeCommand(`${id}.focus`);
388389
await vscode.commands.executeCommand("list.find");
389390
}
390-
391-
async function listStoredDeployments(
392-
serviceContainer: ServiceContainer,
393-
): Promise<void> {
394-
const secretsManager = serviceContainer.getSecretsManager();
395-
const output = serviceContainer.getLogger();
396-
397-
try {
398-
const hostnames = await secretsManager.getKnownSafeHostnames();
399-
if (hostnames.length === 0) {
400-
vscode.window.showInformationMessage("No deployments stored.");
401-
return;
402-
}
403-
404-
const selected = await vscode.window.showQuickPick(
405-
hostnames.map((hostname) => ({
406-
label: hostname,
407-
description: "Click to forget",
408-
})),
409-
{ placeHolder: "Select a deployment to forget" },
410-
);
411-
412-
if (selected) {
413-
await secretsManager.clearAllAuthData(selected.label);
414-
vscode.window.showInformationMessage(
415-
`Cleared auth data for ${selected.label}`,
416-
);
417-
}
418-
} catch (error: unknown) {
419-
output.error("Failed to list stored deployments", error);
420-
vscode.window.showErrorMessage(
421-
"Failed to list stored deployments. Storage may be corrupted.",
422-
);
423-
}
424-
}

0 commit comments

Comments
 (0)