Merge develop into main
All checks were successful
All checks were successful
Consolidate all feature and fix branches into main: - feat: orchestrator observability + mosaic rails integration (#422) - fix: post-422 CI and compose env follow-up (#423) - fix: orchestrator startup provider-key requirements (#425) - fix: BetterAuth OAuth2 flow and compose wiring (#426) - fix: BetterAuth UUID ID generation (#427) - test: web vitest localStorage/file warnings (#428) - fix: auth frontend remediation + review hardening (#421) - Plus numerous Docker, deploy, and auth fixes from develop Lockfile conflict resolved by regenerating from merged package.json. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -56,6 +56,15 @@ export function LinkAutocomplete({
|
||||
const mirrorRef = useRef<HTMLDivElement | null>(null);
|
||||
const cursorSpanRef = useRef<HTMLSpanElement | null>(null);
|
||||
|
||||
// Refs for event handler to avoid stale closures when effects re-attach listeners
|
||||
const stateRef = useRef(state);
|
||||
const resultsRef = useRef(results);
|
||||
const selectedIndexRef = useRef(selectedIndex);
|
||||
const insertLinkRef = useRef<((result: SearchResult) => void) | null>(null);
|
||||
stateRef.current = state;
|
||||
resultsRef.current = results;
|
||||
selectedIndexRef.current = selectedIndex;
|
||||
|
||||
/**
|
||||
* Search for knowledge entries matching the query.
|
||||
* Accepts an AbortSignal to allow cancellation of in-flight requests,
|
||||
@@ -254,47 +263,48 @@ export function LinkAutocomplete({
|
||||
}, [textareaRef, state.isOpen, calculateDropdownPosition, debouncedSearch]);
|
||||
|
||||
/**
|
||||
* Handle keyboard navigation in the dropdown
|
||||
* Handle keyboard navigation in the dropdown.
|
||||
* Reads from refs to avoid stale closures when the effect
|
||||
* that attaches this listener hasn't re-run yet.
|
||||
*/
|
||||
const handleKeyDown = useCallback(
|
||||
(e: KeyboardEvent): void => {
|
||||
if (!state.isOpen) return;
|
||||
const handleKeyDown = useCallback((e: KeyboardEvent): void => {
|
||||
if (!stateRef.current.isOpen) return;
|
||||
|
||||
switch (e.key) {
|
||||
case "ArrowDown":
|
||||
e.preventDefault();
|
||||
setSelectedIndex((prev) => (prev + 1) % results.length);
|
||||
break;
|
||||
const currentResults = resultsRef.current;
|
||||
|
||||
case "ArrowUp":
|
||||
e.preventDefault();
|
||||
setSelectedIndex((prev) => (prev - 1 + results.length) % results.length);
|
||||
break;
|
||||
switch (e.key) {
|
||||
case "ArrowDown":
|
||||
e.preventDefault();
|
||||
setSelectedIndex((prev) => (prev + 1) % currentResults.length);
|
||||
break;
|
||||
|
||||
case "Enter":
|
||||
e.preventDefault();
|
||||
if (results.length > 0 && selectedIndex >= 0) {
|
||||
const selected = results[selectedIndex];
|
||||
if (selected) {
|
||||
insertLink(selected);
|
||||
}
|
||||
case "ArrowUp":
|
||||
e.preventDefault();
|
||||
setSelectedIndex((prev) => (prev - 1 + currentResults.length) % currentResults.length);
|
||||
break;
|
||||
|
||||
case "Enter":
|
||||
e.preventDefault();
|
||||
if (currentResults.length > 0 && selectedIndexRef.current >= 0) {
|
||||
const selected = currentResults[selectedIndexRef.current];
|
||||
if (selected) {
|
||||
insertLinkRef.current?.(selected);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case "Escape":
|
||||
e.preventDefault();
|
||||
setState({
|
||||
isOpen: false,
|
||||
query: "",
|
||||
position: { top: 0, left: 0 },
|
||||
triggerIndex: -1,
|
||||
});
|
||||
setResults([]);
|
||||
break;
|
||||
}
|
||||
},
|
||||
[state.isOpen, results, selectedIndex]
|
||||
);
|
||||
case "Escape":
|
||||
e.preventDefault();
|
||||
setState({
|
||||
isOpen: false,
|
||||
query: "",
|
||||
position: { top: 0, left: 0 },
|
||||
triggerIndex: -1,
|
||||
});
|
||||
setResults([]);
|
||||
break;
|
||||
}
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Insert the selected link into the textarea
|
||||
@@ -330,6 +340,7 @@ export function LinkAutocomplete({
|
||||
},
|
||||
[textareaRef, state.triggerIndex, onInsert]
|
||||
);
|
||||
insertLinkRef.current = insertLink;
|
||||
|
||||
/**
|
||||
* Handle click on a result
|
||||
|
||||
Reference in New Issue
Block a user