perf(renderer): compare kanban task dependencies
This commit is contained in:
parent
ad2f602cba
commit
ad6a7b1998
2 changed files with 88 additions and 1 deletions
|
|
@ -242,6 +242,55 @@ describe('KanbanTaskCard comment badge pulse', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('skips rerender when an unrelated taskMap entry changes', async () => {
|
||||
const memberColorMap = new Map([['alice', 'blue']]);
|
||||
const { root } = await renderTaskCard({
|
||||
task: { ...baseTask, blockedBy: [], blocks: [], comments: [] },
|
||||
taskMap: new Map([['other-task', { ...baseTask, id: 'other-task', subject: 'Other task' }]]),
|
||||
memberColorMap,
|
||||
});
|
||||
|
||||
unreadCommentCountMock.calls = 0;
|
||||
await rerenderTaskCard(root, {
|
||||
task: { ...baseTask, blockedBy: [], blocks: [], comments: [] },
|
||||
taskMap: new Map([
|
||||
['other-task', { ...baseTask, id: 'other-task', subject: 'Updated unrelated task' }],
|
||||
]),
|
||||
memberColorMap,
|
||||
});
|
||||
|
||||
expect(unreadCommentCountMock.calls).toBe(0);
|
||||
|
||||
await act(async () => {
|
||||
root.unmount();
|
||||
await flushReact();
|
||||
});
|
||||
});
|
||||
|
||||
it('rerenders when a displayed dependency task changes', async () => {
|
||||
const memberColorMap = new Map([['alice', 'blue']]);
|
||||
const blockedTask = { ...baseTask, id: 'dep-1', displayId: 'dep1', subject: 'Dependency A' };
|
||||
const { root } = await renderTaskCard({
|
||||
task: { ...baseTask, blockedBy: ['dep-1'], blocks: [], comments: [] },
|
||||
taskMap: new Map([['dep-1', blockedTask]]),
|
||||
memberColorMap,
|
||||
});
|
||||
|
||||
unreadCommentCountMock.calls = 0;
|
||||
await rerenderTaskCard(root, {
|
||||
task: { ...baseTask, blockedBy: ['dep-1'], blocks: [], comments: [] },
|
||||
taskMap: new Map([['dep-1', { ...blockedTask, subject: 'Dependency B', status: 'done' }]]),
|
||||
memberColorMap,
|
||||
});
|
||||
|
||||
expect(unreadCommentCountMock.calls).toBeGreaterThan(0);
|
||||
|
||||
await act(async () => {
|
||||
root.unmount();
|
||||
await flushReact();
|
||||
});
|
||||
});
|
||||
|
||||
it('rerenders when a hidden task field changes so click handlers stay current', async () => {
|
||||
const taskMap = new Map();
|
||||
const memberColorMap = new Map([['alice', 'blue']]);
|
||||
|
|
|
|||
|
|
@ -108,6 +108,44 @@ function areKanbanTaskStatesEqual(
|
|||
);
|
||||
}
|
||||
|
||||
function getTaskDependencyIds(task: TeamTaskWithKanban): string[] {
|
||||
return [...(task.blockedBy ?? []), ...(task.blocks ?? [])].filter((id) => id.length > 0);
|
||||
}
|
||||
|
||||
function getDependencyTaskSignature(task: TeamTask | undefined): string {
|
||||
if (!task) return '';
|
||||
const kanbanTask = task as Partial<TeamTaskWithKanban>;
|
||||
return [
|
||||
task.id,
|
||||
task.displayId ?? '',
|
||||
task.subject,
|
||||
task.status,
|
||||
task.reviewState ?? '',
|
||||
kanbanTask.kanbanColumn ?? '',
|
||||
].join('\u001f');
|
||||
}
|
||||
|
||||
function areTaskMapDependenciesEqual(
|
||||
prevTask: TeamTaskWithKanban,
|
||||
nextTask: TeamTaskWithKanban,
|
||||
prevTaskMap: Map<string, TeamTask>,
|
||||
nextTaskMap: Map<string, TeamTask>
|
||||
): boolean {
|
||||
const dependencyIds = new Set([
|
||||
...getTaskDependencyIds(prevTask),
|
||||
...getTaskDependencyIds(nextTask),
|
||||
]);
|
||||
for (const taskId of dependencyIds) {
|
||||
if (
|
||||
getDependencyTaskSignature(prevTaskMap.get(taskId)) !==
|
||||
getDependencyTaskSignature(nextTaskMap.get(taskId))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function createCommentPulseState(
|
||||
taskKey: string,
|
||||
comments: readonly TaskComment[],
|
||||
|
|
@ -682,7 +720,7 @@ export const KanbanTaskCard = memo(
|
|||
areKanbanTaskStatesEqual(prev.kanbanTaskState, next.kanbanTaskState) &&
|
||||
prev.hasReviewers === next.hasReviewers &&
|
||||
prev.compact === next.compact &&
|
||||
prev.taskMap === next.taskMap &&
|
||||
areTaskMapDependenciesEqual(prev.task, next.task, prev.taskMap, next.taskMap) &&
|
||||
prev.memberColorMap === next.memberColorMap &&
|
||||
prev.hasLiveTaskLogs === next.hasLiveTaskLogs &&
|
||||
prev.onRequestReview === next.onRequestReview &&
|
||||
|
|
|
|||
Loading…
Reference in a new issue