agent-ecosystem/src/renderer/components/team/members/MemberList.tsx
iliya fa244052e8 feat: improve team management and logging functionality
- Added background polling timer stop during service shutdown to prevent hanging.
- Enhanced IPC handlers by importing and utilizing renderer log handlers for better logging.
- Updated team-related services to handle member provisioning more robustly, including validation for empty member arrays.
- Implemented timeout handling for file system operations to improve reliability.
- Improved UI components to reflect solo team status and provide clearer feedback on member counts.

Made-with: Cursor
2026-03-03 23:00:55 +02:00

90 lines
3 KiB
TypeScript

import { buildMemberColorMap } from '@renderer/utils/memberHelpers';
import { MemberCard } from './MemberCard';
import type { TaskStatusCounts } from '@renderer/utils/pathNormalize';
import type { LeadActivityState, ResolvedTeamMember, TeamTaskWithKanban } from '@shared/types';
interface MemberListProps {
members: ResolvedTeamMember[];
memberTaskCounts?: Map<string, TaskStatusCounts>;
taskMap?: Map<string, TeamTaskWithKanban>;
pendingRepliesByMember?: Record<string, number>;
isTeamAlive?: boolean;
isTeamProvisioning?: boolean;
leadActivity?: LeadActivityState;
onMemberClick?: (member: ResolvedTeamMember) => void;
onSendMessage?: (member: ResolvedTeamMember) => void;
onAssignTask?: (member: ResolvedTeamMember) => void;
onOpenTask?: (task: TeamTaskWithKanban) => void;
}
export const MemberList = ({
members,
memberTaskCounts,
taskMap,
pendingRepliesByMember,
isTeamAlive,
isTeamProvisioning,
leadActivity,
onMemberClick,
onSendMessage,
onAssignTask,
onOpenTask,
}: MemberListProps): React.JSX.Element => {
const activeMembers = members
.filter((m) => !m.removedAt)
.sort((a, b) => {
if (a.agentType === 'team-lead') return -1;
if (b.agentType === 'team-lead') return 1;
return 0;
});
const removedMembers = members.filter((m) => m.removedAt);
const colorMap = buildMemberColorMap(members);
if (members.length === 0) {
return (
<div className="rounded-md border border-[var(--color-border)] p-4 text-sm text-[var(--color-text-muted)]">
Solo team lead only
</div>
);
}
const renderCard = (member: ResolvedTeamMember, isRemoved: boolean): React.JSX.Element => {
const currentTask =
member.currentTaskId && taskMap ? (taskMap.get(member.currentTaskId) ?? null) : null;
const awaitingReply = Boolean(pendingRepliesByMember?.[member.name]);
return (
<MemberCard
key={member.name}
member={member}
memberColor={colorMap.get(member.name) ?? 'blue'}
taskCounts={memberTaskCounts?.get(member.name.toLowerCase())}
isTeamAlive={isTeamAlive}
isTeamProvisioning={isTeamProvisioning}
leadActivity={member.agentType === 'team-lead' ? leadActivity : undefined}
currentTask={isRemoved ? null : currentTask}
isAwaitingReply={isRemoved ? false : awaitingReply}
isRemoved={isRemoved}
onOpenTask={currentTask && !isRemoved ? () => onOpenTask?.(currentTask) : undefined}
onClick={() => onMemberClick?.(member)}
onSendMessage={() => onSendMessage?.(member)}
onAssignTask={() => onAssignTask?.(member)}
/>
);
};
return (
<div className="flex flex-col">
{activeMembers.map((member) => renderCard(member, false))}
{removedMembers.length > 0 && (
<>
<div className="mt-2 text-[10px] text-[var(--color-text-muted)]">
Removed ({removedMembers.length})
</div>
{removedMembers.map((member) => renderCard(member, true))}
</>
)}
</div>
);
};