功能:DirectProject 聊天控制器暴露更早历史的加载态、失败态与重试入口
控制器新增 historyLoading / historyError 两个可渲染状态,与并发判据用的 ref 同步镜像。 loadEarlierHistory 失败时写入 historyError 并挂起自动加载,成功路径清掉失败记录。 新增 retryEarlierHistory:先解挂起再走同一条加载入口,供内联错误行的重试按钮调用。 加载失败不再写顶部状态行(状态行留给首屏读取失败等其它用途)。 Co-authored-by: Junie <junie@jetbrains.com>
This commit is contained in:
+42
-8
@@ -137,7 +137,8 @@ export type DirectProjectChatControllerProps = {
|
||||
*
|
||||
* 状态变量归属:reducer 的回合字段、待发消息投影、收口计数与 `history` / `live` 只由
|
||||
* `directThreadChat.ts` 写;本文件的 `commandInFlight`(唯一入口 `beginCommandInFlight` /
|
||||
* `endCommandInFlight`,只覆盖 IPC 在飞)、`localMessages`、埋点句柄与分页 ref 只服务发送与展示;
|
||||
* `endCommandInFlight`,只覆盖 IPC 在飞)、`localMessages`、分页 ref 与更早历史的
|
||||
* `historyLoading` / `historyError`(渲染层读的加载行与内联错误行判据)只服务发送与展示;
|
||||
* 界面上的「这一轮在跑吗」只有一个派生入口 `useDirectProjectTurnStatus()`,两态判据与真值表在
|
||||
* `../conversation/directTurnPresentation.ts` 的 `DirectChatTurnState`,渲染时否定式读
|
||||
* `state !== 'finished'`、肯定式读 `state === 'running'`(见 `DirectProjectTurn.tsx`)。
|
||||
@@ -182,8 +183,17 @@ export function useDirectProjectChatController({
|
||||
*/
|
||||
const pendingTurns = directThread.state.pendingTurns;
|
||||
const [historyHasMore, setHistoryHasMore] = useState(false);
|
||||
const historyOldestItemIdRef = useRef<string | null>(null);
|
||||
/**
|
||||
* 更早历史的加载态与失败态:渲染层要拿它决定加载行与内联错误行的显隐。
|
||||
*
|
||||
* `historyLoadingRef` 是同一件事的同步副本:并发判据必须在同一次事件处理里立刻生效,
|
||||
* 而 `setState` 要等下一次渲染,直接用 state 判会放过第二次触发。
|
||||
*/
|
||||
const [historyLoading, setHistoryLoading] = useState(false);
|
||||
const [historyError, setHistoryError] = useState<string | null>(null);
|
||||
const historyLoadingRef = useRef(false);
|
||||
const historyErrorRef = useRef<string | null>(null);
|
||||
const historyOldestItemIdRef = useRef<string | null>(null);
|
||||
const projectPathRef = useRef<string | null>(projectPath);
|
||||
projectPathRef.current = projectPath;
|
||||
const directTurnRunningRef = useRef(currentTurnRunning);
|
||||
@@ -196,6 +206,10 @@ export function useDirectProjectChatController({
|
||||
setStatusNotice('');
|
||||
setLocalMessages([]);
|
||||
setHistoryHasMore(false);
|
||||
setHistoryLoading(false);
|
||||
historyLoadingRef.current = false;
|
||||
historyErrorRef.current = null;
|
||||
setHistoryError(null);
|
||||
historyOldestItemIdRef.current = null;
|
||||
}, [projectPath]);
|
||||
|
||||
@@ -649,18 +663,27 @@ export function useDirectProjectChatController({
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动加载更早历史(滚动触顶与填充视口共用这一条入口)。
|
||||
*
|
||||
* 失败即挂起:`historyErrorRef` 非空期间这里直接返回,只有手动重试(先清掉错误)或切换
|
||||
* 项目才会重新开始。挂起态一定要能渲染出来——原来的常驻按钮删掉之后,内联错误行是用户
|
||||
* 唯一还能自己补救的入口。
|
||||
*/
|
||||
async function loadEarlierHistory() {
|
||||
const nextProjectPath = projectPath;
|
||||
if (
|
||||
!enabled ||
|
||||
!historyHasMore ||
|
||||
!nextProjectPath ||
|
||||
historyLoadingRef.current
|
||||
historyLoadingRef.current ||
|
||||
historyErrorRef.current
|
||||
)
|
||||
return;
|
||||
const invoke = resolveTauriInvoke();
|
||||
if (!invoke) return;
|
||||
historyLoadingRef.current = true;
|
||||
setHistoryLoading(true);
|
||||
try {
|
||||
const pages = await readDirectHistoryPages({
|
||||
existingEntries: directEntries,
|
||||
@@ -679,19 +702,27 @@ export function useDirectProjectChatController({
|
||||
historyOldestItemIdRef.current =
|
||||
pages.firstItemId ?? historyOldestItemIdRef.current;
|
||||
if (pages.error) throw pages.error;
|
||||
historyErrorRef.current = null;
|
||||
setHistoryError(null);
|
||||
} catch (error) {
|
||||
// 与加载成功路径同样按项目守卫:切项目后在飞的读取失败不能算到新项目头上。
|
||||
if (projectPathRef.current !== nextProjectPath) return;
|
||||
setStatusNotice(
|
||||
`读取更早的对话历史失败:${
|
||||
error instanceof Error ? error.message : String(error)
|
||||
}`,
|
||||
);
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
historyErrorRef.current = message;
|
||||
setHistoryError(message);
|
||||
} finally {
|
||||
historyLoadingRef.current = false;
|
||||
setHistoryLoading(false);
|
||||
}
|
||||
}
|
||||
|
||||
/** 手动重试更早历史:先解挂起,再走同一条加载入口。 */
|
||||
function retryEarlierHistory() {
|
||||
historyErrorRef.current = null;
|
||||
setHistoryError(null);
|
||||
void loadEarlierHistory();
|
||||
}
|
||||
|
||||
return {
|
||||
appendLocalMessage,
|
||||
attachmentNotice,
|
||||
@@ -702,8 +733,11 @@ export function useDirectProjectChatController({
|
||||
directEntries,
|
||||
directTurnRunning: currentTurnRunning,
|
||||
directTurnStartedAt: currentTurnStartedAt,
|
||||
historyError,
|
||||
historyHasMore,
|
||||
historyLoading,
|
||||
loadEarlierHistory,
|
||||
retryEarlierHistory,
|
||||
commandInFlight,
|
||||
localMessages,
|
||||
pendingTurns,
|
||||
|
||||
Reference in New Issue
Block a user