fix(frontend): ArrowUp rappelle l'historique chat même en multiligne — #304 (cause: le handler ArrowUp remontait dans le texte dès que le draft faisait plus d'une ligne, au lieu de rappeler le message précédent; fix type terminal: ArrowUp déclenche le rappel historique uniquement quand le curseur est à la fin de la dernière ligne du textarea, sinon navigation caret normale préservée; ArrowDown symétrique en fin de draft pour redescendre dans l'historique; QA verte reconfirmée par Git: npm test -- src/features/agents/CustomAgentChatView.test.tsx 71/71, npm run typecheck OK, git diff --check OK; QA fournie: npm run build OK; fichiers .ideai/* tickets/counter/index/attachments et scripts/ hors périmètre; aucun push)
This commit is contained in:
@ -1009,6 +1009,7 @@ export function CustomAgentChatView({
|
||||
const draftRef = useRef("");
|
||||
draftRef.current = draft;
|
||||
const draftBeforeHistoryNavigationRef = useRef("");
|
||||
const placeComposerAtEndAfterHistoryRef = useRef(false);
|
||||
const attachmentsRef = useRef<AttachmentDraft[]>([]);
|
||||
attachmentsRef.current = attachments;
|
||||
const imageTokenSeqRef = useRef(0);
|
||||
@ -1125,7 +1126,8 @@ export function CustomAgentChatView({
|
||||
const [composerHistory, setComposerHistory] = useState<string[]>(() =>
|
||||
readComposerHistory(composerHistoryKey),
|
||||
);
|
||||
const [, setComposerHistoryIndex] = useState<number | null>(null);
|
||||
const [composerHistoryIndex, setComposerHistoryIndex] =
|
||||
useState<number | null>(null);
|
||||
const displayTurns = turns;
|
||||
const sessionLabel = structuredSessionLabel(profile.structuredAdapter);
|
||||
const [requesterDelegation, setRequesterDelegation] =
|
||||
@ -1205,6 +1207,7 @@ export function CustomAgentChatView({
|
||||
const recallComposerHistory = useCallback(
|
||||
(direction: "previous" | "next") => {
|
||||
if (composerHistory.length === 0) return;
|
||||
placeComposerAtEndAfterHistoryRef.current = true;
|
||||
setComposerHistoryIndex((current) => {
|
||||
if (current === null && direction === "previous") {
|
||||
draftBeforeHistoryNavigationRef.current = draftRef.current;
|
||||
@ -1231,6 +1234,16 @@ export function CustomAgentChatView({
|
||||
[composerHistory],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!placeComposerAtEndAfterHistoryRef.current) return;
|
||||
placeComposerAtEndAfterHistoryRef.current = false;
|
||||
const composer = composerRef.current;
|
||||
if (!composer) return;
|
||||
const end = composer.value.length;
|
||||
composer.setSelectionRange(end, end);
|
||||
composer.scrollTop = composer.scrollHeight;
|
||||
}, [composerHistoryIndex, draft]);
|
||||
|
||||
const handleComposerHistoryKeyDown = useCallback(
|
||||
(event: KeyboardEvent<HTMLTextAreaElement>): boolean => {
|
||||
if (
|
||||
@ -1238,28 +1251,30 @@ export function CustomAgentChatView({
|
||||
event.ctrlKey ||
|
||||
event.metaKey ||
|
||||
event.shiftKey ||
|
||||
event.nativeEvent.isComposing ||
|
||||
event.keyCode === 229 ||
|
||||
(event.key !== "ArrowUp" && event.key !== "ArrowDown")
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
const target = event.currentTarget;
|
||||
if (
|
||||
event.key === "ArrowUp" &&
|
||||
target.value.slice(0, target.selectionStart).includes("\n")
|
||||
) {
|
||||
const caretIsAtTextEnd =
|
||||
target.selectionStart === target.selectionEnd &&
|
||||
target.selectionEnd === target.value.length;
|
||||
if (!caretIsAtTextEnd) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
event.key === "ArrowDown" &&
|
||||
target.value.slice(target.selectionEnd).includes("\n")
|
||||
) {
|
||||
if (event.key === "ArrowUp" && composerHistory.length === 0) {
|
||||
return false;
|
||||
}
|
||||
if (event.key === "ArrowDown" && composerHistoryIndex === null) {
|
||||
return false;
|
||||
}
|
||||
event.preventDefault();
|
||||
recallComposerHistory(event.key === "ArrowUp" ? "previous" : "next");
|
||||
return true;
|
||||
},
|
||||
[recallComposerHistory],
|
||||
[composerHistory.length, composerHistoryIndex, recallComposerHistory],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
Reference in New Issue
Block a user