perf(renderer): reduce team page render work
This commit is contained in:
parent
b8e1958db8
commit
c7af5cd891
3 changed files with 53 additions and 12 deletions
|
|
@ -10,6 +10,7 @@ import { cn } from '@renderer/lib/utils';
|
||||||
import { markTaskUnread } from '@renderer/services/commentReadStorage';
|
import { markTaskUnread } from '@renderer/services/commentReadStorage';
|
||||||
import { useStore } from '@renderer/store';
|
import { useStore } from '@renderer/store';
|
||||||
import { getCurrentProvisioningProgressForTeam } from '@renderer/store/slices/teamSlice';
|
import { getCurrentProvisioningProgressForTeam } from '@renderer/store/slices/teamSlice';
|
||||||
|
import { buildMemberColorMap } from '@renderer/utils/memberHelpers';
|
||||||
import { normalizePath } from '@renderer/utils/pathNormalize';
|
import { normalizePath } from '@renderer/utils/pathNormalize';
|
||||||
import { projectColor } from '@renderer/utils/projectColor';
|
import { projectColor } from '@renderer/utils/projectColor';
|
||||||
import {
|
import {
|
||||||
|
|
@ -212,6 +213,7 @@ interface GlobalTaskRowProps {
|
||||||
onRenameComplete: (teamName: string, taskId: string, newSubject: string) => void;
|
onRenameComplete: (teamName: string, taskId: string, newSubject: string) => void;
|
||||||
onRenameCancel: () => void;
|
onRenameCancel: () => void;
|
||||||
getDisplaySubject: TaskDisplaySubjectResolver;
|
getDisplaySubject: TaskDisplaySubjectResolver;
|
||||||
|
ownerColorName?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const GlobalTaskRow = memo(function GlobalTaskRow({
|
const GlobalTaskRow = memo(function GlobalTaskRow({
|
||||||
|
|
@ -232,6 +234,7 @@ const GlobalTaskRow = memo(function GlobalTaskRow({
|
||||||
onRenameComplete,
|
onRenameComplete,
|
||||||
onRenameCancel,
|
onRenameCancel,
|
||||||
getDisplaySubject,
|
getDisplaySubject,
|
||||||
|
ownerColorName,
|
||||||
}: GlobalTaskRowProps): React.JSX.Element {
|
}: GlobalTaskRowProps): React.JSX.Element {
|
||||||
const taskRenamingKey = `${task.teamName}:${task.id}`;
|
const taskRenamingKey = `${task.teamName}:${task.id}`;
|
||||||
const effectiveRenamingKey = renamingKey === taskRenamingKey ? renamingKey : null;
|
const effectiveRenamingKey = renamingKey === taskRenamingKey ? renamingKey : null;
|
||||||
|
|
@ -278,6 +281,7 @@ const GlobalTaskRow = memo(function GlobalTaskRow({
|
||||||
onRenameComplete={onRenameComplete}
|
onRenameComplete={onRenameComplete}
|
||||||
onRenameCancel={onRenameCancel}
|
onRenameCancel={onRenameCancel}
|
||||||
getDisplaySubject={getDisplaySubject}
|
getDisplaySubject={getDisplaySubject}
|
||||||
|
ownerColorName={ownerColorName}
|
||||||
/>
|
/>
|
||||||
</AnimatedHeightReveal>
|
</AnimatedHeightReveal>
|
||||||
</TaskContextMenu>
|
</TaskContextMenu>
|
||||||
|
|
@ -493,6 +497,25 @@ export const GlobalTaskList = memo(function GlobalTaskList({
|
||||||
teams,
|
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 => {
|
const setGroupingMode = (mode: TaskGroupingMode): void => {
|
||||||
setGroupingModeState(mode);
|
setGroupingModeState(mode);
|
||||||
saveGroupingMode(mode);
|
saveGroupingMode(mode);
|
||||||
|
|
@ -839,6 +862,7 @@ export const GlobalTaskList = memo(function GlobalTaskList({
|
||||||
isNew={isNewTask(task)}
|
isNew={isNewTask(task)}
|
||||||
showTeamName
|
showTeamName
|
||||||
teamOffline={offlineTeamNames.has(task.teamName)}
|
teamOffline={offlineTeamNames.has(task.teamName)}
|
||||||
|
ownerColorName={getOwnerColorName(task)}
|
||||||
renamingKey={renamingTaskKey}
|
renamingKey={renamingTaskKey}
|
||||||
onTogglePin={handleToggleTaskPin}
|
onTogglePin={handleToggleTaskPin}
|
||||||
onToggleArchive={handleToggleTaskArchive}
|
onToggleArchive={handleToggleTaskArchive}
|
||||||
|
|
@ -942,6 +966,7 @@ export const GlobalTaskList = memo(function GlobalTaskList({
|
||||||
isNew={isNewTask(task)}
|
isNew={isNewTask(task)}
|
||||||
showTeamName
|
showTeamName
|
||||||
teamOffline={offlineTeamNames.has(task.teamName)}
|
teamOffline={offlineTeamNames.has(task.teamName)}
|
||||||
|
ownerColorName={getOwnerColorName(task)}
|
||||||
renamingKey={renamingTaskKey}
|
renamingKey={renamingTaskKey}
|
||||||
onTogglePin={handleToggleTaskPin}
|
onTogglePin={handleToggleTaskPin}
|
||||||
onToggleArchive={handleToggleTaskArchive}
|
onToggleArchive={handleToggleTaskArchive}
|
||||||
|
|
@ -1023,6 +1048,7 @@ export const GlobalTaskList = memo(function GlobalTaskList({
|
||||||
hideTeamName
|
hideTeamName
|
||||||
hideProjectName
|
hideProjectName
|
||||||
teamOffline={offlineTeamNames.has(task.teamName)}
|
teamOffline={offlineTeamNames.has(task.teamName)}
|
||||||
|
ownerColorName={getOwnerColorName(task)}
|
||||||
renamingKey={renamingTaskKey}
|
renamingKey={renamingTaskKey}
|
||||||
onTogglePin={handleToggleTaskPin}
|
onTogglePin={handleToggleTaskPin}
|
||||||
onToggleArchive={handleToggleTaskArchive}
|
onToggleArchive={handleToggleTaskArchive}
|
||||||
|
|
@ -1121,6 +1147,7 @@ export const GlobalTaskList = memo(function GlobalTaskList({
|
||||||
isArchived={taskLocalState.isArchived(task.teamName, task.id)}
|
isArchived={taskLocalState.isArchived(task.teamName, task.id)}
|
||||||
isNew={isNewTask(task)}
|
isNew={isNewTask(task)}
|
||||||
teamOffline={offlineTeamNames.has(task.teamName)}
|
teamOffline={offlineTeamNames.has(task.teamName)}
|
||||||
|
ownerColorName={getOwnerColorName(task)}
|
||||||
renamingKey={renamingTaskKey}
|
renamingKey={renamingTaskKey}
|
||||||
onTogglePin={handleToggleTaskPin}
|
onTogglePin={handleToggleTaskPin}
|
||||||
onToggleArchive={handleToggleTaskArchive}
|
onToggleArchive={handleToggleTaskArchive}
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,7 @@ interface SidebarTaskItemProps {
|
||||||
onRenameCancel?: () => void;
|
onRenameCancel?: () => void;
|
||||||
/** Returns a custom display subject if the task was renamed locally */
|
/** Returns a custom display subject if the task was renamed locally */
|
||||||
getDisplaySubject?: (task: GlobalTask) => string | undefined;
|
getDisplaySubject?: (task: GlobalTask) => string | undefined;
|
||||||
|
ownerColorName?: string | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SidebarTaskItem = memo(function SidebarTaskItem({
|
export const SidebarTaskItem = memo(function SidebarTaskItem({
|
||||||
|
|
@ -91,11 +92,17 @@ export const SidebarTaskItem = memo(function SidebarTaskItem({
|
||||||
onRenameComplete,
|
onRenameComplete,
|
||||||
onRenameCancel,
|
onRenameCancel,
|
||||||
getDisplaySubject,
|
getDisplaySubject,
|
||||||
|
ownerColorName,
|
||||||
}: SidebarTaskItemProps): React.JSX.Element {
|
}: SidebarTaskItemProps): React.JSX.Element {
|
||||||
const { t } = useAppTranslation('team');
|
const { t } = useAppTranslation('team');
|
||||||
const { t: tCommon } = useAppTranslation('common');
|
const { t: tCommon } = useAppTranslation('common');
|
||||||
const openGlobalTaskDetail = useStore((s) => s.openGlobalTaskDetail);
|
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 unreadCount = useUnreadCommentCount(task.teamName, task.id, task.comments);
|
||||||
const { isLight } = useTheme();
|
const { isLight } = useTheme();
|
||||||
|
|
||||||
|
|
@ -142,12 +149,17 @@ export const SidebarTaskItem = memo(function SidebarTaskItem({
|
||||||
);
|
);
|
||||||
const dateLabel = updatedLabel ?? formatTaskDate(task.createdAt, tCommon('tasks.date.yesterday'));
|
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(() => {
|
const ownerColorSet = useMemo(() => {
|
||||||
if (!teamMembers || !task.owner) return null;
|
const colorName = resolvedOwnerColorName;
|
||||||
const colorMap = buildMemberColorMap(teamMembers);
|
|
||||||
const colorName = colorMap.get(task.owner);
|
|
||||||
return colorName ? getTeamColorSet(colorName) : null;
|
return colorName ? getTeamColorSet(colorName) : null;
|
||||||
}, [teamMembers, task.owner]);
|
}, [resolvedOwnerColorName]);
|
||||||
|
|
||||||
const ownerTextColor = useMemo(() => {
|
const ownerTextColor = useMemo(() => {
|
||||||
if (!ownerColorSet) return undefined;
|
if (!ownerColorSet) return undefined;
|
||||||
|
|
|
||||||
|
|
@ -357,8 +357,16 @@ const LeadThoughtItem = memo(
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
const wrapper = wrapperRef.current;
|
const wrapper = wrapperRef.current;
|
||||||
|
if (!wrapper) return;
|
||||||
|
|
||||||
|
if (!shouldAnimateOnMount) {
|
||||||
|
initialAnimationCompletedRef.current = true;
|
||||||
|
resetWrapperStyles();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const content = contentRef.current;
|
const content = contentRef.current;
|
||||||
if (!wrapper || !content) return;
|
if (!content) return;
|
||||||
|
|
||||||
const applyTransition = (targetHeight: number): void => {
|
const applyTransition = (targetHeight: number): void => {
|
||||||
wrapper.style.transition = [
|
wrapper.style.transition = [
|
||||||
|
|
@ -406,12 +414,6 @@ const LeadThoughtItem = memo(
|
||||||
const previousHeight = previousHeightRef.current;
|
const previousHeight = previousHeightRef.current;
|
||||||
previousHeightRef.current = nextHeight;
|
previousHeightRef.current = nextHeight;
|
||||||
|
|
||||||
if (!shouldAnimateOnMount) {
|
|
||||||
initialAnimationCompletedRef.current = true;
|
|
||||||
resetWrapperStyles();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (previousHeight === null) {
|
if (previousHeight === null) {
|
||||||
if (nextHeight > 0 && animateFromZero) {
|
if (nextHeight > 0 && animateFromZero) {
|
||||||
animateHeight(nextHeight, 0, 0);
|
animateHeight(nextHeight, 0, 0);
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue