feat: conditionally render "Compare" button based on active checkpoint and lora selection, improve fallback title generation, and update default settings

This commit is contained in:
Shine1i 2026-02-15 18:38:25 +01:00
commit e59ef60a5c
5 changed files with 41 additions and 19 deletions

View file

@ -174,7 +174,8 @@ function InlineSidebar({
function TopBarActions({
onNewThread,
onNewCompare,
}: { onNewThread: () => void; onNewCompare: () => void }) {
showCompare,
}: { onNewThread: () => void; onNewCompare: () => void; showCompare: boolean }) {
const { state } = useSidebar();
if (state !== "collapsed") {
return null;
@ -189,14 +190,16 @@ function TopBarActions({
</TooltipTrigger>
<TooltipContent side="bottom">New Chat</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild={true}>
<Button variant="ghost" size="icon-sm" onClick={onNewCompare}>
<HugeiconsIcon icon={ColumnInsertIcon} strokeWidth={2} />
</Button>
</TooltipTrigger>
<TooltipContent side="bottom">Compare</TooltipContent>
</Tooltip>
{showCompare ? (
<Tooltip>
<TooltipTrigger asChild={true}>
<Button variant="ghost" size="icon-sm" onClick={onNewCompare}>
<HugeiconsIcon icon={ColumnInsertIcon} strokeWidth={2} />
</Button>
</TooltipTrigger>
<TooltipContent side="bottom">Compare</TooltipContent>
</Tooltip>
) : null}
</>
);
}
@ -215,6 +218,11 @@ export function ChatPage(): ReactElement {
const lorasFromStore = useChatRuntimeStore((state) => state.loras);
const modelsError = useChatRuntimeStore((state) => state.modelsError);
const { refresh, selectModel, ejectModel } = useChatModelRuntime();
const canCompare = useMemo(() => {
const selected = inferenceParams.checkpoint;
if (!selected) return false;
return lorasFromStore.some((lora) => lora.id === selected);
}, [inferenceParams.checkpoint, lorasFromStore]);
const handleCheckpointChange = useCallback(
(value: string, meta?: { isLora: boolean }) => {
@ -277,6 +285,7 @@ export function ChatPage(): ReactElement {
onSelect={setView}
onNewThread={handleNewThread}
onNewCompare={handleNewCompare}
showCompare={canCompare}
/>
</InlineSidebar>
@ -287,6 +296,7 @@ export function ChatPage(): ReactElement {
<TopBarActions
onNewThread={handleNewThread}
onNewCompare={handleNewCompare}
showCompare={canCompare}
/>
<ModelSelector
models={models}

View file

@ -273,7 +273,7 @@ export function ChatSettingsPanel({
<CollapsibleSection
icon={SlidersHorizontalIcon}
label="Sampling"
defaultOpen={true}
defaultOpen={false}
>
<div className="flex flex-col gap-5">
<ParamSlider

View file

@ -225,6 +225,14 @@ async function generateTitleWithModel(payload: {
const inflightTitleByKey = new Set<string>();
function fallbackTitleFromUserText(userText: string): string {
const firstLine = (userText || "").split(/\r?\n/, 1)[0] ?? "";
const cleaned = firstLine.replace(/\s+/g, " ").trim();
const max = 48;
if (!cleaned) return "New Chat";
return cleaned.slice(0, max) + (cleaned.length > max ? "..." : "");
}
function toThreadMessage(m: MessageRecord): ThreadMessage {
const base = {
id: m.id,
@ -342,7 +350,7 @@ function createDexieAdapter(
const userText = extractTextParts(firstUser) || "New Chat";
if (!autoTitle) {
const title = userText.slice(0, 60) + (userText.length > 60 ? "..." : "");
const title = fallbackTitleFromUserText(userText);
await db.threads.update(remoteId, { title });
if (pairId) {
const paired = await db.threads
@ -394,7 +402,7 @@ function createDexieAdapter(
(await generateTitleWithModel({
userText,
})) ||
(userText.slice(0, 60) + (userText.length > 60 ? "..." : ""));
fallbackTitleFromUserText(userText);
await db.threads.update(remoteId, { title });
if (pairId) {

View file

@ -57,7 +57,7 @@ export const useChatRuntimeStore = create<ChatRuntimeStore>((set) => ({
loras: [],
warmingByThreadId: {},
runningByThreadId: {},
autoTitle: loadBool(AUTO_TITLE_KEY, true),
autoTitle: loadBool(AUTO_TITLE_KEY, false),
modelsError: null,
setParams: (params) => set({ params }),
setModels: (models) => set({ models }),

View file

@ -62,11 +62,13 @@ export function ThreadSidebar({
onSelect,
onNewThread,
onNewCompare,
showCompare,
}: {
view: ChatView;
onSelect: (view: ChatView) => void;
onNewThread: () => void;
onNewCompare: () => void;
showCompare: boolean;
}) {
const allThreads = useLiveQuery(
() => db.threads.orderBy("createdAt").reverse().toArray(),
@ -112,12 +114,14 @@ export function ThreadSidebar({
<span>New Chat</span>
</SidebarMenuButton>
</SidebarMenuItem>
<SidebarMenuItem>
<SidebarMenuButton onClick={onNewCompare}>
<HugeiconsIcon icon={ColumnInsertIcon} />
<span>Compare</span>
</SidebarMenuButton>
</SidebarMenuItem>
{showCompare ? (
<SidebarMenuItem>
<SidebarMenuButton onClick={onNewCompare}>
<HugeiconsIcon icon={ColumnInsertIcon} />
<span>Compare</span>
</SidebarMenuButton>
</SidebarMenuItem>
) : null}
</SidebarMenu>
</SidebarGroupContent>
</SidebarGroup>