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:
parent
53d4bf8804
commit
09bb36f9b6
@ -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)
|
// Determine how many tags to show (2 rows worth, approximately 6-8 tags depending on length)
|
||||||
const MAX_TAGS_COLLAPSED = 6;
|
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(() => {
|
useEffect(() => {
|
||||||
|
if (!isEditing) {
|
||||||
setEditingTags(tags);
|
setEditingTags(tags);
|
||||||
}, [tags]);
|
}
|
||||||
|
}, [tags, isEditing]);
|
||||||
|
|
||||||
// Focus input when starting to add a new tag
|
// Focus input when starting to add a new tag
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { Briefcase, Terminal } from "lucide-react";
|
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 { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "../../ui/primitives";
|
||||||
import { cn } from "../../ui/primitives/styles";
|
import { cn } from "../../ui/primitives/styles";
|
||||||
import { SimpleTooltip } from "../../ui/primitives/tooltip";
|
import { SimpleTooltip } from "../../ui/primitives/tooltip";
|
||||||
@ -20,31 +20,8 @@ export const KnowledgeCardType: React.FC<KnowledgeCardTypeProps> = ({
|
|||||||
knowledgeType,
|
knowledgeType,
|
||||||
}) => {
|
}) => {
|
||||||
const [isEditing, setIsEditing] = useState(false);
|
const [isEditing, setIsEditing] = useState(false);
|
||||||
const selectRef = useRef<HTMLDivElement>(null);
|
|
||||||
const updateMutation = useUpdateKnowledgeItem();
|
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 isTechnical = knowledgeType === "technical";
|
||||||
|
|
||||||
const handleTypeChange = async (newType: "technical" | "business") => {
|
const handleTypeChange = async (newType: "technical" | "business") => {
|
||||||
@ -85,11 +62,12 @@ export const KnowledgeCardType: React.FC<KnowledgeCardTypeProps> = ({
|
|||||||
if (isEditing) {
|
if (isEditing) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={selectRef}
|
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
onKeyDown={(e) => e.stopPropagation()}
|
onKeyDown={(e) => e.stopPropagation()}
|
||||||
>
|
>
|
||||||
<Select
|
<Select
|
||||||
|
open={isEditing}
|
||||||
|
onOpenChange={(open) => setIsEditing(open)}
|
||||||
value={knowledgeType}
|
value={knowledgeType}
|
||||||
onValueChange={(value) => handleTypeChange(value as "technical" | "business")}
|
onValueChange={(value) => handleTypeChange(value as "technical" | "business")}
|
||||||
disabled={updateMutation.isPending}
|
disabled={updateMutation.isPending}
|
||||||
|
|||||||
@ -566,6 +566,13 @@ export function useUpdateKnowledgeItem() {
|
|||||||
updatedItem.metadata = { ...updatedItem.metadata, 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 };
|
||||||
|
}
|
||||||
|
|
||||||
queryClient.setQueryData<KnowledgeItem>(knowledgeKeys.detail(sourceId), updatedItem);
|
queryClient.setQueryData<KnowledgeItem>(knowledgeKeys.detail(sourceId), updatedItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -584,6 +591,12 @@ export function useUpdateKnowledgeItem() {
|
|||||||
updatedItem.tags = newTags;
|
updatedItem.tags = newTags;
|
||||||
updatedItem.metadata = { ...updatedItem.metadata, 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 updatedItem;
|
||||||
}
|
}
|
||||||
return item;
|
return item;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user