perf(renderer): memoize active task summary data
This commit is contained in:
parent
34c2215c31
commit
477d18d798
1 changed files with 38 additions and 26 deletions
|
|
@ -1,4 +1,4 @@
|
||||||
import { memo, type ReactNode, useState } from 'react';
|
import { memo, type ReactNode, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import { useAppTranslation } from '@features/localization/renderer';
|
import { useAppTranslation } from '@features/localization/renderer';
|
||||||
import { CARD_BG, CARD_BORDER_STYLE, CARD_ICON_MUTED } from '@renderer/constants/cssVariables';
|
import { CARD_BG, CARD_BORDER_STYLE, CARD_ICON_MUTED } from '@renderer/constants/cssVariables';
|
||||||
|
|
@ -46,33 +46,45 @@ export const ActiveTasksBlock = memo(function ActiveTasksBlock({
|
||||||
const { t } = useAppTranslation('team');
|
const { t } = useAppTranslation('team');
|
||||||
const { isLight } = useTheme();
|
const { isLight } = useTheme();
|
||||||
const [collapsed, setCollapsed] = useState(defaultCollapsed);
|
const [collapsed, setCollapsed] = useState(defaultCollapsed);
|
||||||
const colorMap = buildMemberColorMap(members);
|
|
||||||
const avatarMap = buildMemberAvatarMap(members);
|
|
||||||
const taskMap = new Map(tasks.map((t) => [t.id, t]));
|
|
||||||
|
|
||||||
const entries: ActivityEntry[] = [];
|
const colorMap = useMemo(() => buildMemberColorMap(members), [members]);
|
||||||
|
const avatarMap = useMemo(() => buildMemberAvatarMap(members), [members]);
|
||||||
// Members working on tasks
|
const entries = useMemo<ActivityEntry[]>(() => {
|
||||||
const workingMemberNames = new Set<string>();
|
const taskMap = new Map(tasks.map((task) => [task.id, task]));
|
||||||
for (const m of members) {
|
const reviewTaskByReviewer = new Map<string, TeamTaskWithKanban>();
|
||||||
if (!m.currentTaskId) continue;
|
for (const task of tasks) {
|
||||||
const task = taskMap.get(m.currentTaskId);
|
if (!task.reviewer || getTeamTaskWorkflowColumn(task) !== 'review') continue;
|
||||||
// Defense-in-depth: hide stale currentTaskId until backend refresh clears it.
|
if (!reviewTaskByReviewer.has(task.reviewer)) {
|
||||||
if (!isDisplayableCurrentTask(task)) continue;
|
reviewTaskByReviewer.set(task.reviewer, task);
|
||||||
workingMemberNames.add(m.name);
|
}
|
||||||
entries.push({ member: m, task, taskId: m.currentTaskId, kind: 'working' });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Members reviewing tasks (only if not already shown as working)
|
|
||||||
for (const m of members) {
|
|
||||||
if (workingMemberNames.has(m.name)) continue;
|
|
||||||
const reviewTask = tasks.find(
|
|
||||||
(t) => t.reviewer === m.name && getTeamTaskWorkflowColumn(t) === 'review'
|
|
||||||
);
|
|
||||||
if (reviewTask) {
|
|
||||||
entries.push({ member: m, task: reviewTask, taskId: reviewTask.id, kind: 'reviewing' });
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
const nextEntries: ActivityEntry[] = [];
|
||||||
|
const workingMemberNames = new Set<string>();
|
||||||
|
for (const member of members) {
|
||||||
|
if (!member.currentTaskId) continue;
|
||||||
|
const task = taskMap.get(member.currentTaskId);
|
||||||
|
// Defense-in-depth: hide stale currentTaskId until backend refresh clears it.
|
||||||
|
if (!isDisplayableCurrentTask(task)) continue;
|
||||||
|
workingMemberNames.add(member.name);
|
||||||
|
nextEntries.push({ member, task, taskId: member.currentTaskId, kind: 'working' });
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const member of members) {
|
||||||
|
if (workingMemberNames.has(member.name)) continue;
|
||||||
|
const reviewTask = reviewTaskByReviewer.get(member.name);
|
||||||
|
if (reviewTask) {
|
||||||
|
nextEntries.push({
|
||||||
|
member,
|
||||||
|
task: reviewTask,
|
||||||
|
taskId: reviewTask.id,
|
||||||
|
kind: 'reviewing',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nextEntries;
|
||||||
|
}, [members, tasks]);
|
||||||
|
|
||||||
if (entries.length === 0) return null;
|
if (entries.length === 0) return null;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue