mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-06-26 21:39:43 +02:00
refactor: simplify state management in ChatShareButton and ModelSelector
This commit is contained in:
parent
80f83e32c6
commit
01307f36dd
2 changed files with 1 additions and 31 deletions
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
import { useQueryClient } from "@tanstack/react-query";
|
import { useQueryClient } from "@tanstack/react-query";
|
||||||
import { useAtomValue, useSetAtom } from "jotai";
|
import { useAtomValue, useSetAtom } from "jotai";
|
||||||
import { Loader2, User, Users } from "lucide-react";
|
import { User, Users } from "lucide-react";
|
||||||
import { useCallback, useState } from "react";
|
import { useCallback, useState } from "react";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { currentThreadAtom, setThreadVisibilityAtom } from "@/atoms/chat/current-thread.atom";
|
import { currentThreadAtom, setThreadVisibilityAtom } from "@/atoms/chat/current-thread.atom";
|
||||||
|
|
@ -45,7 +45,6 @@ const visibilityOptions: {
|
||||||
export function ChatShareButton({ thread, onVisibilityChange, className }: ChatShareButtonProps) {
|
export function ChatShareButton({ thread, onVisibilityChange, className }: ChatShareButtonProps) {
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [isUpdating, setIsUpdating] = useState(false);
|
|
||||||
|
|
||||||
// Use Jotai atom for visibility (single source of truth)
|
// Use Jotai atom for visibility (single source of truth)
|
||||||
const currentThreadState = useAtomValue(currentThreadAtom);
|
const currentThreadState = useAtomValue(currentThreadAtom);
|
||||||
|
|
@ -62,7 +61,6 @@ export function ChatShareButton({ thread, onVisibilityChange, className }: ChatS
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsUpdating(true);
|
|
||||||
// Update Jotai atom immediately for instant UI feedback
|
// Update Jotai atom immediately for instant UI feedback
|
||||||
setThreadVisibility(newVisibility);
|
setThreadVisibility(newVisibility);
|
||||||
|
|
||||||
|
|
@ -84,8 +82,6 @@ export function ChatShareButton({ thread, onVisibilityChange, className }: ChatS
|
||||||
// Revert Jotai state on error
|
// Revert Jotai state on error
|
||||||
setThreadVisibility(thread.visibility ?? "PRIVATE");
|
setThreadVisibility(thread.visibility ?? "PRIVATE");
|
||||||
toast.error("Failed to update sharing settings");
|
toast.error("Failed to update sharing settings");
|
||||||
} finally {
|
|
||||||
setIsUpdating(false);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[thread, currentVisibility, onVisibilityChange, queryClient, setThreadVisibility]
|
[thread, currentVisibility, onVisibilityChange, queryClient, setThreadVisibility]
|
||||||
|
|
@ -128,16 +124,6 @@ export function ChatShareButton({ thread, onVisibilityChange, className }: ChatS
|
||||||
onCloseAutoFocus={(e) => e.preventDefault()}
|
onCloseAutoFocus={(e) => e.preventDefault()}
|
||||||
>
|
>
|
||||||
<div className="p-1.5 space-y-1">
|
<div className="p-1.5 space-y-1">
|
||||||
{/* Updating overlay */}
|
|
||||||
{isUpdating && (
|
|
||||||
<div className="absolute inset-0 z-10 flex items-center justify-center bg-background/80 backdrop-blur-sm rounded-lg">
|
|
||||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
||||||
<Loader2 className="size-4 animate-spin" />
|
|
||||||
<span>Updating</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{visibilityOptions.map((option) => {
|
{visibilityOptions.map((option) => {
|
||||||
const isSelected = currentVisibility === option.value;
|
const isSelected = currentVisibility === option.value;
|
||||||
const Icon = option.icon;
|
const Icon = option.icon;
|
||||||
|
|
@ -147,7 +133,6 @@ export function ChatShareButton({ thread, onVisibilityChange, className }: ChatS
|
||||||
type="button"
|
type="button"
|
||||||
key={option.value}
|
key={option.value}
|
||||||
onClick={() => handleVisibilityChange(option.value)}
|
onClick={() => handleVisibilityChange(option.value)}
|
||||||
disabled={isUpdating}
|
|
||||||
className={cn(
|
className={cn(
|
||||||
"w-full flex items-center gap-2.5 px-2.5 py-2 rounded-md transition-all",
|
"w-full flex items-center gap-2.5 px-2.5 py-2 rounded-md transition-all",
|
||||||
"hover:bg-accent/50 cursor-pointer",
|
"hover:bg-accent/50 cursor-pointer",
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,6 @@ interface ModelSelectorProps {
|
||||||
export function ModelSelector({ onEdit, onAddNew, className }: ModelSelectorProps) {
|
export function ModelSelector({ onEdit, onAddNew, className }: ModelSelectorProps) {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const [searchQuery, setSearchQuery] = useState("");
|
const [searchQuery, setSearchQuery] = useState("");
|
||||||
const [isSwitching, setIsSwitching] = useState(false);
|
|
||||||
|
|
||||||
// Fetch configs
|
// Fetch configs
|
||||||
const { data: userConfigs, isLoading: userConfigsLoading } = useAtomValue(newLLMConfigsAtom);
|
const { data: userConfigs, isLoading: userConfigsLoading } = useAtomValue(newLLMConfigsAtom);
|
||||||
|
|
@ -137,7 +136,6 @@ export function ModelSelector({ onEdit, onAddNew, className }: ModelSelectorProp
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsSwitching(true);
|
|
||||||
try {
|
try {
|
||||||
await updatePreferences({
|
await updatePreferences({
|
||||||
search_space_id: Number(searchSpaceId),
|
search_space_id: Number(searchSpaceId),
|
||||||
|
|
@ -150,8 +148,6 @@ export function ModelSelector({ onEdit, onAddNew, className }: ModelSelectorProp
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Failed to switch model:", error);
|
console.error("Failed to switch model:", error);
|
||||||
toast.error("Failed to switch model");
|
toast.error("Failed to switch model");
|
||||||
} finally {
|
|
||||||
setIsSwitching(false);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[currentConfig, searchSpaceId, updatePreferences]
|
[currentConfig, searchSpaceId, updatePreferences]
|
||||||
|
|
@ -216,23 +212,12 @@ export function ModelSelector({ onEdit, onAddNew, className }: ModelSelectorProp
|
||||||
shouldFilter={false}
|
shouldFilter={false}
|
||||||
className="rounded-lg relative [&_[data-slot=command-input-wrapper]]:border-0 [&_[data-slot=command-input-wrapper]]:px-0 [&_[data-slot=command-input-wrapper]]:gap-2"
|
className="rounded-lg relative [&_[data-slot=command-input-wrapper]]:border-0 [&_[data-slot=command-input-wrapper]]:px-0 [&_[data-slot=command-input-wrapper]]:gap-2"
|
||||||
>
|
>
|
||||||
{/* Switching overlay */}
|
|
||||||
{isSwitching && (
|
|
||||||
<div className="absolute inset-0 z-10 flex items-center justify-center bg-background/80 backdrop-blur-sm rounded-lg">
|
|
||||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
||||||
<Loader2 className="size-4 animate-spin" />
|
|
||||||
<span>Switching model...</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="flex items-center gap-1 md:gap-2 px-2 md:px-3 py-1.5 md:py-2">
|
<div className="flex items-center gap-1 md:gap-2 px-2 md:px-3 py-1.5 md:py-2">
|
||||||
<CommandInput
|
<CommandInput
|
||||||
placeholder="Search models"
|
placeholder="Search models"
|
||||||
value={searchQuery}
|
value={searchQuery}
|
||||||
onValueChange={setSearchQuery}
|
onValueChange={setSearchQuery}
|
||||||
className="h-7 md:h-8 text-xs md:text-sm border-0 bg-transparent focus:ring-0 placeholder:text-muted-foreground/60"
|
className="h-7 md:h-8 text-xs md:text-sm border-0 bg-transparent focus:ring-0 placeholder:text-muted-foreground/60"
|
||||||
disabled={isSwitching}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue