feat(vscode-ide-companion): 改进消息排序和显示逻辑

- 添加时间戳支持,确保消息按时间顺序排列
- 更新工具调用处理逻辑,自动添加和保留时间戳
- 修改消息渲染逻辑,将所有类型的消息合并排序后统一渲染
- 优化完成的工具调用显示,修复显示顺序问题
- 调整进行中的工具调用显示,统一到消息流中展示
- 移除重复的计划展示逻辑,避免最新块重复出现
- 重构消息处理和渲染代码,提高可维护性
This commit is contained in:
yiliang114
2025-11-28 09:55:06 +08:00
parent dc340daf8b
commit 9cc48f12da
44 changed files with 2445 additions and 767 deletions

View File

@@ -0,0 +1,72 @@
/**
* @license
* Copyright 2025 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
import React from 'react';
export interface CheckboxDisplayProps {
checked?: boolean;
indeterminate?: boolean;
disabled?: boolean;
className?: string;
style?: React.CSSProperties;
title?: string;
}
/**
* Display-only checkbox styled via Tailwind classes.
* - Renders a custom-looking checkbox using appearance-none and pseudo-elements.
* - Supports indeterminate (middle) state using the DOM property and a data- attribute.
* - Intended for read-only display (disabled by default).
*/
export const CheckboxDisplay: React.FC<CheckboxDisplayProps> = ({
checked = false,
indeterminate = false,
disabled = true,
className = '',
style,
title,
}) => {
const ref = React.useRef<HTMLInputElement | null>(null);
React.useEffect(() => {
const el = ref.current;
if (!el) {
return;
}
el.indeterminate = !!indeterminate;
if (indeterminate) {
el.setAttribute('data-indeterminate', 'true');
} else {
el.removeAttribute('data-indeterminate');
}
}, [indeterminate, checked]);
return (
<input
ref={ref}
type="checkbox"
disabled={disabled}
checked={checked}
readOnly
aria-checked={indeterminate ? 'mixed' : checked}
title={title}
style={style}
className={[
// Base box style (equivalent to .q)
'q appearance-none m-[2px] shrink-0 w-4 h-4 relative rounded-[2px] box-border',
'border border-[var(--app-input-border)] bg-[var(--app-input-background)] text-[var(--app-primary-foreground)]',
'inline-flex items-center justify-center',
// Checked visual state
'checked:opacity-70 checked:text-[#74c991]',
// Checkmark / indeterminate symbol via pseudo-element
'after:absolute after:left-1/2 after:top-1/2 after:-translate-x-1/2 after:-translate-y-1/2 after:opacity-0 after:pointer-events-none after:antialiased',
'checked:after:content-["\\2713"] checked:after:text-[0.9em] checked:after:opacity-100',
'data-[indeterminate=true]:text-[#e1c08d] data-[indeterminate=true]:after:content-["\\273d"] data-[indeterminate=true]:after:text-[0.8em] data-[indeterminate=true]:after:opacity-100',
className,
].join(' ')}
/>
);
};