Skip to content

Commit a841dc6

Browse files
fix: improve UX for activate/deactivate all actions
1 parent f51b6a4 commit a841dc6

File tree

3 files changed

+137
-17
lines changed

3 files changed

+137
-17
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@ All notable changes to the "promptitude" extension will be documented in this fi
77
### Changed
88

99
- Renamed "chatmodes" to "agents" throughout the UI to align with VS Code's current terminology
10+
- Improved "Activate All" and "Deactivate All" operations to show progress notifications with individual prompt status.
1011

1112
### Fixed
1213

1314
- Fixed UI bugs including Windows path handling, activate/deactivate button behavior, and cross-platform compatibility issues
1415
- Fixed prompt details view not opening for inactive prompts on Windows by correctly resolving repository storage paths
16+
- Fixed "Activate All" to properly create symlinks for all prompts instead of just updating state.
17+
- Fixed "Deactivate All" to efficiently remove all symlinks directly instead of looping through individual toggles, eliminating unnecessary counting behavior.
18+
- Fixed issue where prompts that were active before "Activate All" would be in a broken state after "Deactivate All".
19+
- Fixed prompt details view not refreshing when "Deactivate All" is clicked while viewing an active prompt.
1520

1621
## [1.5.0] - 2025-11-12
1722

src/syncManager.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1079,13 +1079,13 @@ export class SyncManager {
10791079

10801080
try {
10811081
const repoPath = this.getRepositoryPath(repositoryUrl);
1082-
this.logger.debug(`Repository storage path: ${repoPath}`);
1082+
this.logger.info(`Repository storage path: ${repoPath}`);
10831083

10841084
const sourcePath = this.fileSystem.joinPath(repoPath, promptPath);
1085-
this.logger.debug(`Source file path: ${sourcePath}`);
1085+
this.logger.info(`Source file path: ${sourcePath}`);
10861086

10871087
const sourceExists = await this.fileSystem.fileExists(sourcePath);
1088-
this.logger.debug(`Source file exists: ${sourceExists}`);
1088+
this.logger.info(`Source file exists: ${sourceExists}`);
10891089

10901090
if (!sourceExists) {
10911091
const errorMsg = `Source file does not exist: ${sourcePath}`;
@@ -1095,12 +1095,13 @@ export class SyncManager {
10951095

10961096
// Generate unique workspace name if there are conflicts
10971097
const workspaceName = await this.getUniqueWorkspaceName(promptPath, repositoryUrl);
1098-
this.logger.debug(`Workspace name: ${workspaceName}`);
1098+
this.logger.info(`Workspace name: ${workspaceName}`);
10991099

11001100
// Create target path directly in User/prompts/ (no subdirectories)
11011101
const promptsDir = this.config.getPromptsDirectory();
1102+
this.logger.info(`Prompts directory: ${promptsDir}`);
11021103
const targetPath = this.fileSystem.joinPath(promptsDir, workspaceName);
1103-
this.logger.debug(`Target path: ${targetPath}`);
1104+
this.logger.info(`Target path: ${targetPath}`);
11041105

11051106
await this.createPromptSymlink(sourcePath, targetPath);
11061107
this.logger.info(`✅ Successfully activated prompt: ${promptPath} as ${workspaceName}`);

src/ui/promptCommands.ts

Lines changed: 126 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -192,12 +192,75 @@ export class PromptCommandManager {
192192
}
193193
}
194194

195-
private selectAll(): void {
195+
private async selectAll(): Promise<void> {
196196
try {
197-
this.treeProvider.selectAll();
198-
const count = this.treeProvider.getSelectedPrompts().length;
199-
vscode.window.showInformationMessage(`Activated ${count} prompts`);
200-
this.logger.debug(`Activated all prompts (${count} total)`);
197+
if (!this.syncManager) {
198+
vscode.window.showErrorMessage('SyncManager not available');
199+
return;
200+
}
201+
202+
// Get all prompts that are currently inactive
203+
const allPrompts = this.treeProvider.getAllPrompts();
204+
const inactivePrompts = allPrompts.filter(p => !p.active);
205+
206+
if (inactivePrompts.length === 0) {
207+
vscode.window.showInformationMessage('All prompts are already activated');
208+
return;
209+
}
210+
211+
// Use withProgress for proper loading indicator
212+
await vscode.window.withProgress({
213+
location: vscode.ProgressLocation.Notification,
214+
title: `Activating ${inactivePrompts.length} prompts`,
215+
cancellable: false
216+
}, async (progress) => {
217+
if (!this.syncManager) {
218+
throw new Error('SyncManager not available');
219+
}
220+
221+
// Activate all inactive prompts by creating symlinks
222+
let successCount = 0;
223+
const errors: string[] = [];
224+
225+
for (let i = 0; i < inactivePrompts.length; i++) {
226+
const prompt = inactivePrompts[i];
227+
progress.report({
228+
increment: (100 / inactivePrompts.length),
229+
message: `${i + 1}/${inactivePrompts.length}: ${prompt.name}`
230+
});
231+
232+
try {
233+
if (!prompt.repositoryUrl) {
234+
errors.push(`${prompt.name}: No repository URL`);
235+
continue;
236+
}
237+
238+
const workspaceName = await this.syncManager.activatePrompt(prompt.name, prompt.repositoryUrl);
239+
prompt.workspaceName = workspaceName;
240+
prompt.active = true;
241+
successCount++;
242+
243+
// Update details view if this prompt is currently being viewed
244+
this.webviewProvider.updateSelectionStatus(prompt);
245+
} catch (error) {
246+
const errorMsg = error instanceof Error ? error.message : String(error);
247+
errors.push(`${prompt.name}: ${errorMsg}`);
248+
this.logger.warn(`Failed to activate ${prompt.name}: ${errorMsg}`);
249+
}
250+
}
251+
252+
this.treeProvider.refresh();
253+
254+
if (successCount === inactivePrompts.length) {
255+
vscode.window.showInformationMessage(`✅ Activated all ${successCount} prompts`);
256+
} else if (successCount > 0) {
257+
vscode.window.showWarningMessage(`⚠️ Activated ${successCount}/${inactivePrompts.length} prompts. ${errors.length} failed.`);
258+
} else {
259+
vscode.window.showErrorMessage(`❌ Failed to activate prompts: ${errors.join(', ')}`);
260+
}
261+
262+
this.logger.debug(`Activated ${successCount}/${inactivePrompts.length} prompts`);
263+
});
201264
} catch (error) {
202265
this.logger.error(`Failed to activate all prompts: ${error}`);
203266
vscode.window.showErrorMessage(`Failed to activate all prompts: ${error}`);
@@ -206,16 +269,67 @@ export class PromptCommandManager {
206269

207270
private async deselectAll(): Promise<void> {
208271
try {
209-
// Get all currently selected prompts before deselecting
210-
const selected = [...this.treeProvider.getSelectedPrompts()];
272+
if (!this.syncManager) {
273+
vscode.window.showErrorMessage('SyncManager not available');
274+
return;
275+
}
276+
277+
// Get all currently selected prompts
278+
const activePrompts = this.treeProvider.getSelectedPrompts();
211279

212-
// Deactivate each prompt using toggleSelection to ensure symlinks are removed
213-
for (const prompt of selected) {
214-
await this.toggleSelection(prompt);
280+
if (activePrompts.length === 0) {
281+
vscode.window.showInformationMessage('No prompts are currently activated');
282+
return;
215283
}
216284

217-
vscode.window.showInformationMessage('All prompts deactivated');
218-
this.logger.debug('Deactivated all prompts');
285+
// Use withProgress for proper loading indicator
286+
await vscode.window.withProgress({
287+
location: vscode.ProgressLocation.Notification,
288+
title: `Deactivating ${activePrompts.length} prompts`,
289+
cancellable: false
290+
}, async (progress) => {
291+
if (!this.syncManager) {
292+
throw new Error('SyncManager not available');
293+
}
294+
295+
// Deactivate all prompts efficiently by removing symlinks directly
296+
let successCount = 0;
297+
const errors: string[] = [];
298+
299+
for (let i = 0; i < activePrompts.length; i++) {
300+
const prompt = activePrompts[i];
301+
progress.report({
302+
increment: (100 / activePrompts.length),
303+
message: `${i + 1}/${activePrompts.length}: ${prompt.name}`
304+
});
305+
306+
try {
307+
const nameToDeactivate = prompt.workspaceName || prompt.name;
308+
await this.syncManager.deactivatePrompt(nameToDeactivate);
309+
prompt.active = false;
310+
successCount++;
311+
312+
// Update details view if this prompt is currently being viewed
313+
this.webviewProvider.updateSelectionStatus(prompt);
314+
} catch (error) {
315+
const errorMsg = error instanceof Error ? error.message : String(error);
316+
errors.push(`${prompt.name}: ${errorMsg}`);
317+
this.logger.warn(`Failed to deactivate ${prompt.name}: ${errorMsg}`);
318+
}
319+
}
320+
321+
this.treeProvider.refresh();
322+
323+
if (successCount === activePrompts.length) {
324+
vscode.window.showInformationMessage(`✅ Deactivated all ${successCount} prompts`);
325+
} else if (successCount > 0) {
326+
vscode.window.showWarningMessage(`⚠️ Deactivated ${successCount}/${activePrompts.length} prompts. ${errors.length} failed.`);
327+
} else {
328+
vscode.window.showErrorMessage(`❌ Failed to deactivate prompts: ${errors.join(', ')}`);
329+
}
330+
331+
this.logger.debug(`Deactivated ${successCount}/${activePrompts.length} prompts`);
332+
});
219333
} catch (error) {
220334
this.logger.error(`Failed to deactivate all prompts: ${error}`);
221335
vscode.window.showErrorMessage(`Failed to deactivate all prompts: ${error}`);

0 commit comments

Comments
 (0)