perf(renderer): reduce team page render work

This commit is contained in:
777genius 2026-05-31 01:45:57 +03:00
parent 38ea035fb5
commit 2d8966a6a6
3 changed files with 53 additions and 12 deletions

View file

@ -10,6 +10,7 @@ import { cn } from '@renderer/lib/utils';
import { markTaskUnread } from '@renderer/services/commentReadStorage';
import { useStore } from '@renderer/store';
import { getCurrentProvisioningProgressForTeam } from '@renderer/store/slices/teamSlice';
import { buildMemberColorMap } from '@renderer/utils/memberHelpers';
import { normalizePath } from '@renderer/utils/pathNormalize';
import { projectColor } from '@renderer/utils/projectColor';
import {
@ -212,6 +213,7 @@ interface GlobalTaskRowProps {
onRenameComplete: (teamName: string, taskId: string, newSubject: string) => void;
onRenameCancel: () => void;
getDisplaySubject: TaskDisplaySubjectResolver;
ownerColorName?: string | null;
}
const GlobalTaskRow = memo(function GlobalTaskRow({
@ -232,6 +234,7 @@ const GlobalTaskRow = memo(function GlobalTaskRow({
onRenameComplete,
onRenameCancel,
getDisplaySubject,
ownerColorName,
}: GlobalTaskRowProps): React.JSX.Element {
const taskRenamingKey = `${task.teamName}:${task.id}`;
const effectiveRenamingKey = renamingKey === taskRenamingKey ? renamingKey : null;
@ -278,6 +281,7 @@ const GlobalTaskRow = memo(function GlobalTaskRow({
onRenameComplete={onRenameComplete}
onRenameCancel={onRenameCancel}
getDisplaySubject={getDisplaySubject}
ownerColorName={ownerColorName}
/>
</AnimatedHeightReveal>
</TaskContextMenu>
@ -493,6 +497,25 @@ export const GlobalTaskList = memo(function GlobalTaskList({
teams,
]);
const memberColorByTeam = useMemo(() => {
const result = new Map<string, Map<string, string>>();
for (const team of teams) {
if (team.members && team.members.length > 0) {
result.set(team.teamName, buildMemberColorMap(team.members));
}
}
return result;
}, [teams]);
const getOwnerColorName = useCallback(
(task: GlobalTask): string | null | undefined => {
if (!task.owner) return null;
const teamColorMap = memberColorByTeam.get(task.teamName);
return teamColorMap ? (teamColorMap.get(task.owner) ?? null) : undefined;
},
[memberColorByTeam]
);
const setGroupingMode = (mode: TaskGroupingMode): void => {
setGroupingModeState(mode);
saveGroupingMode(mode);
@ -839,6 +862,7 @@ export const GlobalTaskList = memo(function GlobalTaskList({
isNew={isNewTask(task)}
showTeamName
teamOffline={offlineTeamNames.has(task.teamName)}
ownerColorName={getOwnerColorName(task)}
renamingKey={renamingTaskKey}
onTogglePin={handleToggleTaskPin}
onToggleArchive={handleToggleTaskArchive}
@ -942,6 +966,7 @@ export const GlobalTaskList = memo(function GlobalTaskList({
isNew={isNewTask(task)}
showTeamName
teamOffline={offlineTeamNames.has(task.teamName)}
ownerColorName={getOwnerColorName(task)}
renamingKey={renamingTaskKey}
onTogglePin={handleToggleTaskPin}
onToggleArchive={handleToggleTaskArchive}
@ -1023,6 +1048,7 @@ export const GlobalTaskList = memo(function GlobalTaskList({
hideTeamName
hideProjectName
teamOffline={offlineTeamNames.has(task.teamName)}
ownerColorName={getOwnerColorName(task)}
renamingKey={renamingTaskKey}
onTogglePin={handleToggleTaskPin}
onToggleArchive={handleToggleTaskArchive}
@ -1121,6 +1147,7 @@ export const GlobalTaskList = memo(function GlobalTaskList({
isArchived={taskLocalState.isArchived(task.teamName, task.id)}
isNew={isNewTask(task)}
teamOffline={offlineTeamNames.has(task.teamName)}
ownerColorName={getOwnerColorName(task)}
renamingKey={renamingTaskKey}
onTogglePin={handleToggleTaskPin}
onToggleArchive={handleToggleTaskArchive}

View file

@ -79,6 +79,7 @@ interface SidebarTaskItemProps {
onRenameCancel?: () => void;
/** Returns a custom display subject if the task was renamed locally */
getDisplaySubject?: (task: GlobalTask) => string | undefined;
ownerColorName?: string | null;
}
export const SidebarTaskItem = memo(function SidebarTaskItem({
@ -91,11 +92,17 @@ export const SidebarTaskItem = memo(function SidebarTaskItem({
onRenameComplete,
onRenameCancel,
getDisplaySubject,
ownerColorName,
}: SidebarTaskItemProps): React.JSX.Element {
const { t } = useAppTranslation('team');
const { t: tCommon } = useAppTranslation('common');
const openGlobalTaskDetail = useStore((s) => s.openGlobalTaskDetail);
const teamMembers = useStore(useShallow((s) => s.teamByName[task.teamName]?.members));
const shouldResolveOwnerColorFromStore = ownerColorName === undefined;
const teamMembers = useStore(
useShallow((s) =>
shouldResolveOwnerColorFromStore ? s.teamByName[task.teamName]?.members : undefined
)
);
const unreadCount = useUnreadCommentCount(task.teamName, task.id, task.comments);
const { isLight } = useTheme();
@ -142,12 +149,17 @@ export const SidebarTaskItem = memo(function SidebarTaskItem({
);
const dateLabel = updatedLabel ?? formatTaskDate(task.createdAt, tCommon('tasks.date.yesterday'));
const resolvedOwnerColorName = useMemo(() => {
if (!task.owner) return null;
if (!shouldResolveOwnerColorFromStore) return ownerColorName;
if (!teamMembers) return null;
return buildMemberColorMap(teamMembers).get(task.owner) ?? null;
}, [ownerColorName, shouldResolveOwnerColorFromStore, task.owner, teamMembers]);
const ownerColorSet = useMemo(() => {
if (!teamMembers || !task.owner) return null;
const colorMap = buildMemberColorMap(teamMembers);
const colorName = colorMap.get(task.owner);
const colorName = resolvedOwnerColorName;
return colorName ? getTeamColorSet(colorName) : null;
}, [teamMembers, task.owner]);
}, [resolvedOwnerColorName]);
const ownerTextColor = useMemo(() => {
if (!ownerColorSet) return undefined;

View file

@ -357,8 +357,16 @@ const LeadThoughtItem = memo(
useLayoutEffect(() => {
const wrapper = wrapperRef.current;
if (!wrapper) return;
if (!shouldAnimateOnMount) {
initialAnimationCompletedRef.current = true;
resetWrapperStyles();
return;
}
const content = contentRef.current;
if (!wrapper || !content) return;
if (!content) return;
const applyTransition = (targetHeight: number): void => {
wrapper.style.transition = [
@ -406,12 +414,6 @@ const LeadThoughtItem = memo(
const previousHeight = previousHeightRef.current;
previousHeightRef.current = nextHeight;
if (!shouldAnimateOnMount) {
initialAnimationCompletedRef.current = true;
resetWrapperStyles();
return;
}
if (previousHeight === null) {
if (nextHeight > 0 && animateFromZero) {
animateHeight(nextHeight, 0, 0);