Merge pull request #1035 from JoeMakuta/fix/derive-has-changes-and-use-functional-setstate

fix : derive has changes and use functional setstate
This commit is contained in:
Rohan Verma 2026-03-30 15:22:01 -07:00 committed by GitHub
commit d836eea554
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 46 additions and 52 deletions

View file

@ -243,7 +243,7 @@ export const MCPConnectForm: FC<ConnectFormProps> = ({ onSubmit, isSubmitting })
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
setShowDetails(!showDetails);
setShowDetails(prev => !prev);
}}
>
{showDetails ? (

View file

@ -250,7 +250,7 @@ export const ComposioDriveConfig: FC<ConnectorConfigProps> = ({ connector, onCon
<div className="space-y-2">
<button
type="button"
onClick={() => setIsFolderTreeOpen(!isFolderTreeOpen)}
onClick={() => setIsFolderTreeOpen(prev => !prev)}
className="flex items-center gap-2 text-xs sm:text-sm text-muted-foreground hover:text-foreground transition-colors w-fit"
>
Change Selection

View file

@ -248,7 +248,7 @@ export const MCPConfig: FC<MCPConfigProps> = ({ connector, onConfigChange, onNam
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
setShowDetails(!showDetails);
setShowDetails(prev => !prev);
}}
>
{showDetails ? (

View file

@ -220,7 +220,7 @@ export const OneDriveConfig: FC<ConnectorConfigProps> = ({ connector, onConfigCh
<div className="space-y-2">
<button
type="button"
onClick={() => setIsFolderTreeOpen(!isFolderTreeOpen)}
onClick={() => setIsFolderTreeOpen(prev => !prev)}
className="flex items-center gap-2 text-xs sm:text-sm text-muted-foreground hover:text-foreground transition-colors w-fit"
>
Change Selection

View file

@ -86,7 +86,7 @@ export const WebcrawlerConfig: FC<ConnectorConfigProps> = ({ connector, onConfig
type="button"
variant="ghost"
size="sm"
onClick={() => setShowApiKey(!showApiKey)}
onClick={() => setShowApiKey(prev => !prev)}
className="absolute right-1 top-1/2 -translate-y-1/2 h-7 px-2 text-xs text-muted-foreground hover:text-foreground"
>
{showApiKey ? "Hide" : "Show"}

View file

@ -69,7 +69,7 @@ export const ThinkingStepsDisplay: FC<{ steps: ThinkingStep[]; isThreadRunning?:
<div className="rounded-lg">
<button
type="button"
onClick={() => setIsOpen(!isOpen)}
onClick={() => setIsOpen(prev => !prev)}
className={cn(
"flex w-full items-center gap-1.5 text-left text-sm transition-colors",
"text-muted-foreground hover:text-foreground"

View file

@ -45,7 +45,7 @@ export const ToolFallback: ToolCallMessagePartComponent = ({
>
<button
type="button"
onClick={() => setIsExpanded(!isExpanded)}
onClick={() => setIsExpanded(prev => !prev)}
className="flex w-full items-center gap-3 px-5 py-4 text-left transition-colors hover:bg-muted/50 focus:outline-none focus-visible:outline-none"
>
<div

View file

@ -93,7 +93,7 @@ export function CommentThread({
variant="ghost"
size="sm"
className="h-6 px-2 text-xs text-muted-foreground hover:text-foreground"
onClick={() => setIsRepliesExpanded(!isRepliesExpanded)}
onClick={() => setIsRepliesExpanded(prev => !prev)}
>
{isRepliesExpanded ? (
<ChevronDown className="mr-1 size-3" />

View file

@ -162,7 +162,7 @@ const MobileNav = ({ navItems, isScrolled, scrolledBgClassName }: any) => {
</Link>
<button
type="button"
onClick={() => setOpen(!open)}
onClick={() => setOpen(prev => !prev)}
className="relative z-50 flex items-center justify-center p-2 -mr-2 rounded-lg hover:bg-gray-100 dark:hover:bg-neutral-800 transition-colors touch-manipulation"
aria-label={open ? "Close menu" : "Open menu"}
>

View file

@ -37,8 +37,14 @@ export function useSidebarState(defaultCollapsed = false): UseSidebarStateReturn
}, []);
const toggleCollapsed = useCallback(() => {
setIsCollapsed(!isCollapsed);
}, [isCollapsed, setIsCollapsed]);
setIsCollapsedState(prev => {
const next = !prev;
try {
document.cookie = `${SIDEBAR_COOKIE_NAME}=${next}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
} catch {}
return next;
});
}, []);
// Keyboard shortcut: Cmd/Ctrl + \
useEffect(() => {

View file

@ -666,27 +666,33 @@ export function OnboardingTour() {
}, [targetEl, isActive]);
const handleNext = useCallback(() => {
if (stepIndex < TOUR_STEPS.length - 1) {
retryCountRef.current = 0;
setShouldAnimate(true);
setStepIndex(stepIndex + 1);
} else {
// Tour completed - save to localStorage
if (user?.id) {
const tourKey = `surfsense-tour-${user.id}`;
localStorage.setItem(tourKey, "true");
retryCountRef.current = 0;
setShouldAnimate(true);
setStepIndex(prev => {
if (prev < TOUR_STEPS.length - 1) {
return prev + 1;
} else {
// Tour completed - save to localStorage
if (user?.id) {
const tourKey = `surfsense-tour-${user.id}`;
localStorage.setItem(tourKey, "true");
}
setIsActive(false);
return prev;
}
setIsActive(false);
}
}, [stepIndex, user?.id]);
});
}, [user?.id]);
const handlePrev = useCallback(() => {
if (stepIndex > 0) {
retryCountRef.current = 0;
setShouldAnimate(true);
setStepIndex(stepIndex - 1);
}
}, [stepIndex]);
retryCountRef.current = 0;
setShouldAnimate(true);
setStepIndex(prev => {
if (prev > 0) {
return prev - 1;
}
return prev;
});
}, []);
const handleSkip = useCallback(() => {
// Tour skipped - save to localStorage

View file

@ -40,26 +40,17 @@ export function GeneralSettingsManager({ searchSpaceId }: GeneralSettingsManager
const [name, setName] = useState("");
const [description, setDescription] = useState("");
const [saving, setSaving] = useState(false);
const [hasChanges, setHasChanges] = useState(false);
// Initialize state from fetched search space
useEffect(() => {
if (searchSpace) {
setName(searchSpace.name || "");
setDescription(searchSpace.description || "");
setHasChanges(false);
}
}, [searchSpace]);
// Track changes
useEffect(() => {
if (searchSpace) {
const currentName = searchSpace.name || "";
const currentDescription = searchSpace.description || "";
const changed = currentName !== name || currentDescription !== description;
setHasChanges(changed);
}
}, [searchSpace, name, description]);
// Derive hasChanges during render
const hasChanges = !!searchSpace && ((searchSpace.name || "") !== name || (searchSpace.description || "") !== description);
const handleSave = async () => {
try {
@ -73,7 +64,6 @@ export function GeneralSettingsManager({ searchSpaceId }: GeneralSettingsManager
},
});
setHasChanges(false);
await fetchSearchSpace();
} catch (error: any) {
console.error("Error saving search space details:", error);

View file

@ -32,24 +32,16 @@ export function PromptConfigManager({ searchSpaceId }: PromptConfigManagerProps)
const [customInstructions, setCustomInstructions] = useState("");
const [saving, setSaving] = useState(false);
const [hasChanges, setHasChanges] = useState(false);
// Initialize state from fetched search space
useEffect(() => {
if (searchSpace) {
setCustomInstructions(searchSpace.qna_custom_instructions || "");
setHasChanges(false);
}
}, [searchSpace]);
// Track changes
useEffect(() => {
if (searchSpace) {
const currentCustom = searchSpace.qna_custom_instructions || "";
const changed = currentCustom !== customInstructions;
setHasChanges(changed);
}
}, [searchSpace, customInstructions]);
// Derive hasChanges during render
const hasChanges = !!searchSpace && (searchSpace.qna_custom_instructions || "") !== customInstructions;
const handleSave = async () => {
try {
@ -74,7 +66,7 @@ export function PromptConfigManager({ searchSpaceId }: PromptConfigManagerProps)
}
toast.success("System instructions saved successfully");
setHasChanges(false);
await fetchSearchSpace();
} catch (error: any) {
console.error("Error saving system instructions:", error);