Keep sidebar task order stable

This commit is contained in:
Haitao Pan 2026-05-27 10:37:16 +08:00
parent 83b776ccb0
commit eaca7e0f7d
4 changed files with 76 additions and 23 deletions

View File

@ -642,12 +642,7 @@ extension AppControllerDesktopThreadSessions on AppController {
byKey[currentKey] = assistantSessionSummaryForInternal(currentKey);
}
final items = byKey.values.toList(growable: true)
..sort(
(left, right) =>
(right.updatedAtMs ?? 0).compareTo(left.updatedAtMs ?? 0),
);
return items;
return byKey.values.toList(growable: false);
}
List<GatewaySessionSummary> archivedAssistantSessionsInternal() {

View File

@ -386,9 +386,6 @@ extension AppControllerDesktopThreadStorage on AppController {
items.add(assistantSessionSummaryForInternal(currentSessionKey));
}
items.sort((left, right) {
return (right.updatedAtMs ?? 0).compareTo(left.updatedAtMs ?? 0);
});
return items;
}

View File

@ -117,8 +117,61 @@ void main() {
findsNothing,
);
});
testWidgets('sidebar keeps the supplied task order when selection changes', (
tester,
) async {
const firstTitle = '先显示任务';
const selectedTitle = '当前选择任务';
const lastTitle = '后显示任务';
await _pumpSidebar(
tester,
items: const <SidebarTaskItem>[
SidebarTaskItem(
sessionKey: 'first-task',
title: firstTitle,
preview: '第一项',
updatedAtMs: 1000,
executionTarget: AssistantExecutionTarget.gateway,
isCurrent: false,
pending: false,
),
SidebarTaskItem(
sessionKey: 'selected-task',
title: selectedTitle,
preview: '被选中的第二项',
updatedAtMs: 3000,
executionTarget: AssistantExecutionTarget.gateway,
isCurrent: true,
pending: false,
),
SidebarTaskItem(
sessionKey: 'last-task',
title: lastTitle,
preview: '第三项',
updatedAtMs: 2000,
executionTarget: AssistantExecutionTarget.gateway,
isCurrent: false,
pending: false,
),
],
);
expect(
_textTop(tester, firstTitle),
lessThan(_textTop(tester, selectedTitle)),
);
expect(
_textTop(tester, selectedTitle),
lessThan(_textTop(tester, lastTitle)),
);
});
}
double _textTop(WidgetTester tester, String text) =>
tester.getTopLeft(find.text(text)).dy;
Future<void> _pumpSidebar(
WidgetTester tester, {
required List<SidebarTaskItem> items,

View File

@ -349,7 +349,7 @@ void main() {
});
test(
'switching sessions does not refresh task ordering timestamp',
'assistant task list keeps repository order when tasks update',
() async {
final localHome = await Directory.systemTemp.createTemp(
'xworkmate-stable-task-selection-home-',
@ -365,33 +365,41 @@ void main() {
addTearDown(controller.dispose);
controller.resolvedUserHomeDirectoryInternal = localHome.path;
const newerTask = 'draft:newer-task';
const olderTask = 'draft:older-task';
const newerUpdatedAtMs = 2000.0;
const olderUpdatedAtMs = 1000.0;
const firstTask = 'draft:first-task';
const secondTask = 'draft:second-task';
const firstUpdatedAtMs = 1000.0;
const secondUpdatedAtMs = 2000.0;
controller.upsertTaskThreadInternal(
newerTask,
firstTask,
executionTarget: AssistantExecutionTarget.gateway,
messageViewMode: AssistantMessageViewMode.rendered,
updatedAtMs: newerUpdatedAtMs,
updatedAtMs: firstUpdatedAtMs,
);
controller.upsertTaskThreadInternal(
olderTask,
secondTask,
executionTarget: AssistantExecutionTarget.gateway,
messageViewMode: AssistantMessageViewMode.rendered,
updatedAtMs: olderUpdatedAtMs,
updatedAtMs: secondUpdatedAtMs,
);
await controller.switchSession(olderTask);
await controller.switchSession(secondTask);
controller.upsertTaskThreadInternal(
secondTask,
executionTarget: AssistantExecutionTarget.gateway,
messageViewMode: AssistantMessageViewMode.rendered,
updatedAtMs: 3000,
);
expect(controller.currentSessionKey, olderTask);
expect(controller.currentSessionKey, secondTask);
expect(
controller.requireTaskThreadForSessionInternal(olderTask).updatedAtMs,
olderUpdatedAtMs,
controller
.requireTaskThreadForSessionInternal(secondTask)
.updatedAtMs,
3000,
);
expect(
controller.assistantSessions.map((item) => item.key).take(2),
<String>[newerTask, olderTask],
<String>[firstTask, secondTask],
);
},
);