agent-ecosystem/src/renderer/components/chat/ChatHistoryItem.tsx
iliya a30727d3b0 feat: enhance team file handling and logging improvements
- Added support for a new worker in the team file system to list teams, improving performance and reliability in team management.
- Introduced event loop lag monitoring in various IPC handlers to track and log slow operations, enhancing observability.
- Implemented caching for CLI installation status to reduce redundant calls and improve responsiveness.
- Updated project and team data services to include total session counts, optimizing data handling and performance.
- Enhanced error handling and logging across multiple services to provide clearer insights into performance issues and failures.

Made-with: Cursor
2026-03-03 22:00:11 +02:00

144 lines
4.7 KiB
TypeScript

import React from 'react';
import {
getHighlightProps,
HIGHLIGHT_CLASSES,
isPresetColorKey,
type TriggerColor,
} from '@shared/constants/triggerColors';
import { AIChatGroup } from './AIChatGroup';
import { CompactBoundary } from './CompactBoundary';
import { SystemChatGroup } from './SystemChatGroup';
import { UserChatGroup } from './UserChatGroup';
import type { ChatItem } from '@renderer/types/groups';
interface ChatHistoryItemProps {
readonly item: ChatItem;
readonly highlightedGroupId: string | null;
readonly highlightToolUseId?: string;
readonly isSearchHighlight: boolean;
readonly isNavigationHighlight: boolean;
readonly highlightColor?: TriggerColor;
/** Whether this item just appeared (triggers enter animation) */
readonly isNew?: boolean;
readonly registerChatItemRef: (groupId: string) => (el: HTMLElement | null) => void;
readonly registerAIGroupRef: (groupId: string) => (el: HTMLElement | null) => void;
/** Register ref for individual tool items (for precise scroll targeting) */
readonly registerToolRef: (toolId: string, el: HTMLElement | null) => void;
}
/**
* Get highlight class/style based on type: search (yellow), navigation (blue), error (custom color)
*/
function getHighlight(
isHighlighted: boolean,
isSearchHighlight: boolean,
isNavigationHighlight: boolean,
highlightColor?: TriggerColor
): { className: string; style?: React.CSSProperties } {
if (!isHighlighted) return { className: 'ring-0 bg-transparent' };
if (isSearchHighlight) return { className: 'ring-2 ring-yellow-500/30 bg-yellow-500/5' };
if (isNavigationHighlight) return { className: 'ring-2 ring-blue-500/30 bg-blue-500/5' };
const key = highlightColor ?? 'red';
if (isPresetColorKey(key)) return { className: HIGHLIGHT_CLASSES[key] };
return getHighlightProps(key);
}
/**
* Renders a single chat history item (user, system, ai, or compact).
*/
const ChatHistoryItemInner = ({
item,
highlightedGroupId,
highlightToolUseId,
isSearchHighlight,
isNavigationHighlight,
highlightColor,
isNew,
registerChatItemRef,
registerAIGroupRef,
registerToolRef,
}: ChatHistoryItemProps): JSX.Element | null => {
const enterClass = isNew ? 'chat-message-enter-animate' : '';
const transitionStyle: React.CSSProperties = { transitionDuration: '3000ms' };
switch (item.type) {
case 'user': {
const isHighlighted = highlightedGroupId === item.group.id;
const hl = getHighlight(
isHighlighted,
isSearchHighlight,
isNavigationHighlight,
highlightColor
);
return (
<div
ref={registerChatItemRef(item.group.id)}
className={`rounded-lg transition-all ease-out ${hl.className} ${enterClass}`}
style={{ ...transitionStyle, ...(hl.style ?? {}) }}
>
<UserChatGroup userGroup={item.group} />
</div>
);
}
case 'system': {
const isHighlighted = highlightedGroupId === item.group.id;
const hl = getHighlight(
isHighlighted,
isSearchHighlight,
isNavigationHighlight,
highlightColor
);
return (
<div
ref={registerChatItemRef(item.group.id)}
className={`rounded-lg transition-all ease-out ${hl.className} ${enterClass}`}
style={{ ...transitionStyle, ...(hl.style ?? {}) }}
>
<SystemChatGroup systemGroup={item.group} />
</div>
);
}
case 'ai': {
const isHighlighted = highlightedGroupId === item.group.id;
// Pass highlightToolUseId to ALL AI groups (when not search highlight)
// Each group will check if it contains the tool and expand accordingly
// Allowed during navigation highlights so context panel tool deep-linking works
const toolUseIdForGroup = !isSearchHighlight ? highlightToolUseId : undefined;
const hl = getHighlight(
isHighlighted,
isSearchHighlight,
isNavigationHighlight,
highlightColor
);
return (
<div
ref={registerAIGroupRef(item.group.id)}
className={`rounded-lg transition-all ease-out ${hl.className} ${enterClass}`}
style={{ ...transitionStyle, ...(hl.style ?? {}) }}
>
<AIChatGroup
aiGroup={item.group}
highlightToolUseId={toolUseIdForGroup}
highlightColor={highlightColor}
registerToolRef={registerToolRef}
/>
</div>
);
}
case 'compact':
return isNew ? (
<div className={enterClass}>
<CompactBoundary compactGroup={item.group} />
</div>
) : (
<CompactBoundary compactGroup={item.group} />
);
default:
return null;
}
};
export const ChatHistoryItem = React.memo(ChatHistoryItemInner);