feat: Add optimistic updates and improve component reliability

- Add optimistic updates for knowledge_type changes in useUpdateKnowledgeItem
- Update both detail and summary caches to prevent visual reversion
- Refactor KnowledgeCardType to use controlled Radix Select component
- Remove manual click-outside detection in favor of Radix onOpenChange
- Protect tag editing state from being overwritten by external updates
- Ensure user input is preserved during active editing sessions

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
leex279 2025-09-14 15:55:39 +02:00 committed by Wirasm
parent 53d4bf8804
commit 09bb36f9b6
3 changed files with 21 additions and 28 deletions

View File

@ -28,10 +28,12 @@ export const KnowledgeCardTags: React.FC<KnowledgeCardTagsProps> = ({ sourceId,
// Determine how many tags to show (2 rows worth, approximately 6-8 tags depending on length)
const MAX_TAGS_COLLAPSED = 6;
// Update local state when props change
// Update local state when props change, but only when not editing to avoid overwriting user input
useEffect(() => {
setEditingTags(tags);
}, [tags]);
if (!isEditing) {
setEditingTags(tags);
}
}, [tags, isEditing]);
// Focus input when starting to add a new tag
useEffect(() => {

View File

@ -4,7 +4,7 @@
*/
import { Briefcase, Terminal } from "lucide-react";
import { useEffect, useRef, useState } from "react";
import { useState } from "react";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../ui/primitives";
import { cn } from "../../ui/primitives/styles";
import { SimpleTooltip } from "../../ui/primitives/tooltip";
@ -20,31 +20,8 @@ export const KnowledgeCardType: React.FC<KnowledgeCardTypeProps> = ({
knowledgeType,
}) => {
const [isEditing, setIsEditing] = useState(false);
const selectRef = useRef<HTMLDivElement>(null);
const updateMutation = useUpdateKnowledgeItem();
// Handle click outside to cancel editing
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (isEditing && selectRef.current && event.target) {
const target = event.target as Element;
// Don't close if clicking on the select component or its dropdown content
if (!selectRef.current.contains(target) &&
!target.closest('[data-radix-select-content]') &&
!target.closest('[data-radix-select-item]') &&
!target.closest('[data-radix-popper-content-wrapper]')) {
setIsEditing(false);
}
}
};
if (isEditing) {
document.addEventListener("mousedown", handleClickOutside);
return () => document.removeEventListener("mousedown", handleClickOutside);
}
}, [isEditing]);
const isTechnical = knowledgeType === "technical";
const handleTypeChange = async (newType: "technical" | "business") => {
@ -85,11 +62,12 @@ export const KnowledgeCardType: React.FC<KnowledgeCardTypeProps> = ({
if (isEditing) {
return (
<div
ref={selectRef}
onClick={(e) => e.stopPropagation()}
onKeyDown={(e) => e.stopPropagation()}
>
<Select
open={isEditing}
onOpenChange={(open) => setIsEditing(open)}
value={knowledgeType}
onValueChange={(value) => handleTypeChange(value as "technical" | "business")}
disabled={updateMutation.isPending}

View File

@ -566,6 +566,13 @@ export function useUpdateKnowledgeItem() {
updatedItem.metadata = { ...updatedItem.metadata, tags: newTags };
}
if ('knowledge_type' in updates) {
const newType = updates.knowledge_type as string;
// Update both top-level knowledge_type and metadata.knowledge_type for consistency
updatedItem.knowledge_type = newType as "technical" | "business";
updatedItem.metadata = { ...updatedItem.metadata, knowledge_type: newType };
}
queryClient.setQueryData<KnowledgeItem>(knowledgeKeys.detail(sourceId), updatedItem);
}
@ -584,6 +591,12 @@ export function useUpdateKnowledgeItem() {
updatedItem.tags = newTags;
updatedItem.metadata = { ...updatedItem.metadata, tags: newTags };
}
if ('knowledge_type' in updates) {
const newType = updates.knowledge_type as string;
// Update both top-level knowledge_type and metadata.knowledge_type for consistency
updatedItem.knowledge_type = newType as "technical" | "business";
updatedItem.metadata = { ...updatedItem.metadata, knowledge_type: newType };
}
return updatedItem;
}
return item;