Skip to content

Commit 634e10e

Browse files
ulugbeknaCopilot
andauthored
automations: fix: remove delete action from run history rows (#333567)
automations: feat: remove delete action from run history rows Temporarily hide the Delete affordance from Automation run-history rows (both inline toolbar and context menu) while the AHP run-deletion protocol is not yet available. Archive/Unarchive, Stop, and read/unread actions remain unchanged. Ordinary Sessions surfaces are unaffected. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 962fd6a6-f98e-4fe8-a288-bb3d8c257df3
1 parent 28abcdd commit 634e10e

2 files changed

Lines changed: 10 additions & 222 deletions

File tree

src/vs/sessions/contrib/sessions/browser/views/automationsView.ts

Lines changed: 1 addition & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,13 @@ import { IActionViewItemService } from '../../../../../platform/actions/browser/
5050
import { ChatSessionArchiveActionWording, ChatSessionArchiveActionWordingSettingId, getChatSessionArchiveActionPresentation, getChatSessionArchiveActionWording } from '../../../../../platform/chat/common/sessionArchiveActions.js';
5151
import { BaseActionViewItem, IActionViewItemOptions } from '../../../../../base/browser/ui/actionbar/actionViewItems.js';
5252
import { IAction } from '../../../../../base/common/actions.js';
53-
import { AutomationsCustomViewFocusContext, AutomationsHasItemsContext, SessionIsArchivedContext, SessionIsReadContext, SessionSupportsDeleteContext, SessionSupportsRenameContext } from '../../../../common/contextkeys.js';
53+
import { AutomationsCustomViewFocusContext, AutomationsHasItemsContext, SessionIsArchivedContext, SessionIsReadContext, SessionSupportsRenameContext } from '../../../../common/contextkeys.js';
5454
import { SessionsFlatList, SessionItemStatusContext } from './sessionsList.js';
5555
import { AUTOMATIONS_CUSTOM_VIEW_ID } from '../automationsConstants.js';
5656
import { ARCHIVE_SESSION_COMMAND_ID, MARK_SESSION_READ_COMMAND_ID, MARK_SESSION_UNREAD_COMMAND_ID, RENAME_SESSION_COMMAND_ID, UNARCHIVE_SESSION_COMMAND_ID } from '../../../../common/sessionCommands.js';
5757

5858
const $ = DOM.$;
5959
const STOP_AUTOMATION_RUN_SESSION_COMMAND_ID = 'sessions.automations.stopRunSession';
60-
const DELETE_AUTOMATION_RUN_SESSION_COMMAND_ID = 'sessions.automations.deleteRunSession';
6160
const AutomationCardCanDeleteContext = new RawContextKey<boolean>('sessionsAutomationCardCanDelete', false);
6261
const AutomationCardCanDisableContext = new RawContextKey<boolean>('sessionsAutomationCardCanDisable', false);
6362

@@ -870,9 +869,6 @@ class AutomationHistorySection extends Disposable {
870869
case ARCHIVE_SESSION_COMMAND_ID:
871870
await this.sessionsManagementService.archiveSession(session);
872871
return true;
873-
case DELETE_AUTOMATION_RUN_SESSION_COMMAND_ID:
874-
await this.confirmDeleteRunSession(run, session, this.getAutomationName(run));
875-
return true;
876872
default:
877873
return false;
878874
}
@@ -912,54 +908,6 @@ class AutomationHistorySection extends Disposable {
912908
}
913909
}
914910

915-
private async confirmDeleteRunSession(run: IAutomationRun, session: ISession, automationName: string): Promise<void> {
916-
// Capture focus before the confirmation dialog moves it.
917-
const hadFocus = this.container.contains(DOM.getActiveElement());
918-
const confirmed = await this.dialogService.confirm({
919-
message: localize('confirmDeleteAutomationRunSession', "Delete the session for \"{0}\"?", automationName),
920-
detail: localize('confirmDeleteAutomationRunSessionDetail', "This will permanently delete the session and remove this item from run history. This action cannot be undone."),
921-
primaryButton: localize('delete', "Delete"),
922-
});
923-
if (!confirmed.confirmed) {
924-
return;
925-
}
926-
const focusRunId = hadFocus ? this.getFocusRunIdAfterDeletion(run.id) : undefined;
927-
try {
928-
await this.sessionsManagementService.deleteSession(session);
929-
} catch (error) {
930-
this.clearPendingFocus();
931-
this.logService.error('[AutomationsCards] Failed to delete automation run session', error);
932-
await this.dialogService.error(
933-
localize('automationRunSessionDeleteFailed', "Failed to delete the automation run session."),
934-
getErrorMessage(error),
935-
);
936-
return;
937-
}
938-
if (hadFocus) {
939-
this.pendingFocusRunId = focusRunId;
940-
this.shouldRestoreFocus = true;
941-
}
942-
try {
943-
await this.automationService.deleteRun(run.id);
944-
this.restoreFocusAfterRender();
945-
status(localize('automationRunSessionDeletedStatus', "Deleted the session for {0}", automationName));
946-
} catch (error) {
947-
this.restoreFocusAfterRender();
948-
this.logService.error('[AutomationsCards] Failed to remove deleted automation run from history', error);
949-
await this.dialogService.error(
950-
localize('automationRunHistoryDeleteFailed', "The session was deleted, but its run history item could not be removed."),
951-
getErrorMessage(error),
952-
);
953-
}
954-
}
955-
956-
private getFocusRunIdAfterDeletion(runId: string): string | undefined {
957-
const index = this.renderedFocusableRunIds.indexOf(runId);
958-
return index >= 0
959-
? this.renderedFocusableRunIds[index + 1] ?? this.renderedFocusableRunIds[index - 1]
960-
: undefined;
961-
}
962-
963911
private restoreFocusAfterRender(): void {
964912
if (!this.shouldRestoreFocus) {
965913
return;
@@ -1250,22 +1198,6 @@ function registerAutomationHistoryItemActions(archiveWording: ChatSessionArchive
12501198
SessionItemStatusContext.isEqualTo(SessionStatus.NeedsInput),
12511199
),
12521200
}),
1253-
MenuRegistry.appendMenuItem(Menus.AutomationsHistoryItem, {
1254-
command: {
1255-
id: DELETE_AUTOMATION_RUN_SESSION_COMMAND_ID,
1256-
title: localize('deleteAutomationRunSessionAction', "Delete"),
1257-
icon: Codicon.trash,
1258-
},
1259-
group: 'navigation',
1260-
order: 3,
1261-
when: ContextKeyExpr.and(
1262-
SessionSupportsDeleteContext,
1263-
ContextKeyExpr.or(
1264-
SessionItemStatusContext.isEqualTo(SessionStatus.Completed),
1265-
SessionItemStatusContext.isEqualTo(SessionStatus.Error),
1266-
),
1267-
),
1268-
}),
12691201
MenuRegistry.appendMenuItem(Menus.AutomationsHistoryItemContext, {
12701202
command: {
12711203
id: MARK_SESSION_READ_COMMAND_ID,
@@ -1311,21 +1243,6 @@ function registerAutomationHistoryItemActions(archiveWording: ChatSessionArchive
13111243
order: 2,
13121244
when: SessionIsArchivedContext,
13131245
}),
1314-
MenuRegistry.appendMenuItem(Menus.AutomationsHistoryItemContext, {
1315-
command: {
1316-
id: DELETE_AUTOMATION_RUN_SESSION_COMMAND_ID,
1317-
title: localize('deleteAutomationRunSessionContextAction', "Delete"),
1318-
},
1319-
group: '2_delete',
1320-
order: 1,
1321-
when: ContextKeyExpr.and(
1322-
SessionSupportsDeleteContext,
1323-
ContextKeyExpr.or(
1324-
SessionItemStatusContext.isEqualTo(SessionStatus.Completed),
1325-
SessionItemStatusContext.isEqualTo(SessionStatus.Error),
1326-
),
1327-
),
1328-
}),
13291246
);
13301247
}
13311248

src/vs/sessions/contrib/sessions/test/browser/automationsView.test.ts

Lines changed: 9 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -1506,17 +1506,13 @@ suite('AutomationsCardsWidget', () => {
15061506
'vs.actions.separator',
15071507
'sessionsViewPane.renameSession',
15081508
'sessionsViewPane.archiveSession',
1509-
'vs.actions.separator',
1510-
'sessions.automations.deleteRunSession',
15111509
],
15121510
archiveLabel: 'Archive',
15131511
readActionIds: [
15141512
MARK_SESSION_UNREAD_COMMAND_ID,
15151513
'vs.actions.separator',
15161514
'sessionsViewPane.renameSession',
15171515
'sessionsViewPane.archiveSession',
1518-
'vs.actions.separator',
1519-
'sessions.automations.deleteRunSession',
15201516
],
15211517
commandCalls: [{
15221518
commandId: MARK_SESSION_READ_COMMAND_ID,
@@ -1597,34 +1593,6 @@ suite('AutomationsCardsWidget', () => {
15971593
});
15981594
});
15991595

1600-
test('history context menu deletion uses the run-only deletion flow', async () => {
1601-
const { automationService, contextMenuService, dialogService, sessionsManagementService, widget } = setup();
1602-
automationService.setAutomations([automation()]);
1603-
automationService.setRuns([run()]);
1604-
dialogService.confirmResult = { confirmed: true };
1605-
await waitForSessionActions();
1606-
const row = widget.element.querySelector<HTMLElement>('.automations-run-session-list .session-item');
1607-
assert.ok(row);
1608-
1609-
dispatchContextMenu(row);
1610-
const delegate = contextMenuService.delegate;
1611-
const deleteAction = delegate?.getActions().find(action => action.id === 'sessions.automations.deleteRunSession');
1612-
assert.ok(deleteAction);
1613-
await delegate?.actionRunner?.run(deleteAction, delegate.getActionsContext?.());
1614-
await automationService.deleteRunCompleted.p;
1615-
delegate?.onHide?.(false);
1616-
1617-
assert.deepStrictEqual({
1618-
deleteSessionCalls: sessionsManagementService.deleteSessionCalls,
1619-
deleteRunCalls: automationService.deleteRunCalls,
1620-
historyItemStillVisible: !!widget.element.querySelector('.automations-run-session-list .session-item'),
1621-
}, {
1622-
deleteSessionCalls: 1,
1623-
deleteRunCalls: 1,
1624-
historyItemStillVisible: false,
1625-
});
1626-
});
1627-
16281596
test('stops an active run without opening its session', async () => {
16291597
const { automationService, sessionsManagementService, sessionsService, widget } = setup();
16301598
sessionsManagementService.sessionStatus.set(SessionStatus.InProgress, undefined);
@@ -1672,37 +1640,6 @@ suite('AutomationsCardsWidget', () => {
16721640
});
16731641
});
16741642

1675-
test('deleting a run session confirms the permanent deletion without opening it', async () => {
1676-
const { automationService, dialogService, sessionsManagementService, sessionsService, widget } = setup();
1677-
automationService.setAutomations([automation()]);
1678-
automationService.setRuns([run()]);
1679-
dialogService.confirmResult = { confirmed: true };
1680-
await waitForSessionActions();
1681-
1682-
const deleteButton = getSessionAction(widget, 'Delete');
1683-
assert.ok(deleteButton);
1684-
deleteButton.click();
1685-
await automationService.deleteRunCompleted.p;
1686-
1687-
assert.deepStrictEqual({
1688-
confirmation: dialogService.confirmations[0],
1689-
deleteSessionCalls: sessionsManagementService.deleteSessionCalls,
1690-
deleteRunCalls: automationService.deleteRunCalls,
1691-
openCalls: sessionsService.openCalls,
1692-
historyItemStillVisible: !!widget.element.querySelector('.automations-run-session-list .session-item'),
1693-
}, {
1694-
confirmation: {
1695-
message: 'Delete the session for "Daily review"?',
1696-
detail: 'This will permanently delete the session and remove this item from run history. This action cannot be undone.',
1697-
primaryButton: 'Delete',
1698-
},
1699-
deleteSessionCalls: 1,
1700-
deleteRunCalls: 1,
1701-
openCalls: 0,
1702-
historyItemStillVisible: false,
1703-
});
1704-
});
1705-
17061643
test('archives a run session without opening it and hides the action', async () => {
17071644
const { automationService, sessionsManagementService, sessionsService, widget } = setup();
17081645
automationService.setAutomations([automation()]);
@@ -1718,93 +1655,27 @@ suite('AutomationsCardsWidget', () => {
17181655
archived: sessionsManagementService.archived.map(session => session.sessionId),
17191656
openCalls: sessionsService.openCalls,
17201657
archiveButtonVisible: !!getSessionAction(widget, 'Archive'),
1721-
deleteButtonVisible: !!getSessionAction(widget, 'Delete'),
17221658
}, {
17231659
archived: ['test/session-1'],
17241660
openCalls: 0,
17251661
archiveButtonVisible: false,
1726-
deleteButtonVisible: true,
1727-
});
1728-
});
1729-
1730-
test('deleting the focused run moves focus to the next run', async () => {
1731-
const { automationService, dialogService, widget } = setup();
1732-
automationService.setAutomations([automation()]);
1733-
automationService.setRuns([
1734-
run(),
1735-
run({ id: 'run-2', sessionResource: SECOND_SESSION_RESOURCE }),
1736-
]);
1737-
dialogService.confirmResult = { confirmed: true };
1738-
await waitForSessionActions();
1739-
1740-
const deleteButton = getSessionAction(widget, 'Delete');
1741-
assert.ok(deleteButton);
1742-
const list = widget.element.querySelector<HTMLElement>('.automations-run-session-list .monaco-list');
1743-
assert.ok(list);
1744-
list.focus();
1745-
deleteButton.click();
1746-
await automationService.deleteRunCompleted.p;
1747-
const remainingRow = widget.element.querySelector<HTMLElement>('.automations-run-session-list .monaco-list-row');
1748-
1749-
assert.deepStrictEqual({
1750-
historyItemCount: widget.element.querySelectorAll('.automations-run-session-list .session-item').length,
1751-
focusedNextRun: remainingRow?.classList.contains('focused'),
1752-
}, {
1753-
historyItemCount: 1,
1754-
focusedNextRun: true,
1755-
});
1756-
});
1757-
1758-
test('canceling run session deletion keeps the session', async () => {
1759-
const { automationService, dialogService, sessionsManagementService, widget } = setup();
1760-
automationService.setAutomations([automation()]);
1761-
automationService.setRuns([run()]);
1762-
await waitForSessionActions();
1763-
1764-
getSessionAction(widget, 'Delete')?.click();
1765-
await Promise.resolve();
1766-
1767-
assert.deepStrictEqual({
1768-
confirmations: dialogService.confirmations.length,
1769-
deleteSessionCalls: sessionsManagementService.deleteSessionCalls,
1770-
deleteButtonStillVisible: !!getSessionAction(widget, 'Delete'),
1771-
}, {
1772-
confirmations: 1,
1773-
deleteSessionCalls: 0,
1774-
deleteButtonStillVisible: true,
17751662
});
17761663
});
17771664

1778-
test('keeps run history when session deletion fails', async () => {
1779-
const { automationService, dialogService, sessionsManagementService, widget } = setup();
1665+
test('does not expose delete action on run history rows', async () => {
1666+
const { automationService, contextMenuService, widget } = setup();
17801667
automationService.setAutomations([automation()]);
17811668
automationService.setRuns([run()]);
1782-
dialogService.confirmResult = { confirmed: true };
1783-
sessionsManagementService.deleteError = new Error('delete failed');
17841669
await waitForSessionActions();
17851670

1786-
getSessionAction(widget, 'Delete')?.click();
1787-
await dialogService.errorCalled.p;
1788-
1789-
assert.deepStrictEqual({
1790-
deleteRunCalls: automationService.deleteRunCalls,
1791-
historyItemStillVisible: !!widget.element.querySelector('.automations-run-session-list .session-item'),
1792-
error: dialogService.errors,
1793-
}, {
1794-
deleteRunCalls: 0,
1795-
historyItemStillVisible: true,
1796-
error: [{ message: 'Failed to delete the automation run session.', detail: 'delete failed' }],
1797-
});
1798-
});
1799-
1800-
test('does not expose session deletion when the provider does not support it', async () => {
1801-
const { automationService, sessionsManagementService, widget } = setup();
1802-
sessionsManagementService.setSupportsDelete(false);
1803-
automationService.setAutomations([automation()]);
1804-
automationService.setRuns([run()]);
1805-
await waitForSessionActions();
1671+
assert.strictEqual(getSessionAction(widget, 'Delete'), undefined, 'delete absent from toolbar');
18061672

1807-
assert.strictEqual(getSessionAction(widget, 'Delete'), undefined);
1673+
const row = widget.element.querySelector<HTMLElement>('.automations-run-session-list .session-item');
1674+
assert.ok(row);
1675+
dispatchContextMenu(row);
1676+
const actionIds = (contextMenuService.delegate?.getActions() ?? []).map(a => a.id);
1677+
contextMenuService.delegate?.onHide?.(false);
1678+
assert.ok(!actionIds.includes('sessions.automations.deleteRunSession'), 'delete absent from context menu');
18081679
});
18091680

18101681
test('edit conflict is reported to the user', async () => {

0 commit comments

Comments
 (0)