feat(KB-257): add localStorage persistence for QuickEntryBox draft input

- Persist draft task input in localStorage to prevent data loss on refresh
- Restore saved draft when component mounts
- Clear localStorage entry when task is successfully created
- Add comprehensive tests for persistence behavior
- Remove fixed positioning styles from ListView component
This commit is contained in:
gsxdsm
2026-03-30 23:20:04 -07:00
parent b139876e98
commit 42375d2f4c
2 changed files with 118 additions and 2 deletions

View File

@@ -6,6 +6,8 @@ import { fetchModels } from "../api";
import { Link, Brain, Lightbulb, ListTree } from "lucide-react";
import { CustomModelDropdown } from "./CustomModelDropdown";
const STORAGE_KEY = "kb-quick-entry-text";
interface QuickEntryBoxProps {
onCreate?: (input: TaskCreateInput) => Promise<void>;
addToast: (message: string, type?: ToastType) => void;
@@ -42,7 +44,12 @@ function parseModelSelection(value: string): { provider?: string; modelId?: stri
}
export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels, onPlanningMode, onSubtaskBreakdown }: QuickEntryBoxProps) {
const [description, setDescription] = useState("");
const [description, setDescription] = useState(() => {
if (typeof window !== "undefined") {
return localStorage.getItem(STORAGE_KEY) || "";
}
return "";
});
const [isSubmitting, setIsSubmitting] = useState(false);
const [isExpanded, setIsExpanded] = useState(false);
const textareaRef = useRef<HTMLTextAreaElement>(null);
@@ -115,6 +122,13 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
[loadedModels],
);
// Persist description to localStorage whenever it changes
useEffect(() => {
if (typeof window !== "undefined") {
localStorage.setItem(STORAGE_KEY, description);
}
}, [description]);
// Cleanup timeout on unmount
useEffect(() => {
return () => {
@@ -173,6 +187,10 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
if (textareaRef.current) {
textareaRef.current.style.height = "auto";
}
// Clear localStorage when form is reset (after successful creation)
if (typeof window !== "undefined") {
localStorage.removeItem(STORAGE_KEY);
}
}, []);
const handleSubmit = useCallback(async () => {
@@ -233,13 +251,17 @@ export function QuickEntryBox({ onCreate, addToast, tasks = [], availableModels,
setShowModels(false);
return;
}
// Clear non-empty input on Escape
// Clear non-empty input on Escape and clear localStorage
if (description.trim()) {
setDescription("");
// Reset height
if (textareaRef.current) {
textareaRef.current.style.height = "auto";
}
// Clear localStorage when user explicitly clears input
if (typeof window !== "undefined") {
localStorage.removeItem(STORAGE_KEY);
}
}
// Collapse on escape
resetForm();