resolve /chat/<id> by scanning project groups and make session rows real links
deep-linking or refreshing /chat/<id> only has the id, so add loadClaudeSessionById to scan every project group for the transcript and return its real cwd. the session list page resolves on load from that, setting the cwd picker and resuming. session rows are now <Link to=/chat/<id>> so clicking updates the url and flows through the same resolve path. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
import { useRef, useState, useCallback } from 'react';
|
||||
import { useNavigate } from 'react-router';
|
||||
import { Plus, MessageSquare, RefreshCw, Loader2, Trash2, Pencil, Check, X } from 'lucide-react';
|
||||
import { Link, useNavigate } from 'react-router';
|
||||
import { Plus, MessageSquare, RefreshCw, Trash2, Pencil, Check, X } from 'lucide-react';
|
||||
import { usePanelChannel } from 'hooks/usePanelChannel';
|
||||
import { useClaudeSessions } from 'state/useClaudeSessions';
|
||||
import type { SelectedSession } from './ChatDetailPanel';
|
||||
import type { ChatMessage } from '../Chat/types';
|
||||
import { PwdSelector } from './PwdSelector';
|
||||
|
||||
// Reads the /chat conversation list from Claude's own transcript store (source of truth).
|
||||
@@ -13,9 +12,8 @@ export const SessionList = () => {
|
||||
const navigate = useNavigate();
|
||||
// The working directory the list operates on (null = the default general_chat_sessions dir).
|
||||
const [activeCwd, setActiveCwd] = usePanelChannel<string | null>('chat:active-cwd', null);
|
||||
const { sessions, isLoading, refetch, loadSession, deleteSession, renameSession } = useClaudeSessions(activeCwd);
|
||||
const { sessions, isLoading, refetch, deleteSession, renameSession } = useClaudeSessions(activeCwd);
|
||||
const [selected, setSelected] = usePanelChannel<SelectedSession>('chat:selected-session', null);
|
||||
const [openingId, setOpeningId] = useState<string | null>(null);
|
||||
const [editingId, setEditingId] = useState<string | null>(null);
|
||||
const [editValue, setEditValue] = useState('');
|
||||
const [confirmingId, setConfirmingId] = useState<string | null>(null);
|
||||
@@ -28,17 +26,6 @@ export const SessionList = () => {
|
||||
}
|
||||
}, []);
|
||||
|
||||
const handleSelect = async (id: string) => {
|
||||
if (openingId || editingId) return;
|
||||
setOpeningId(id);
|
||||
try {
|
||||
const detail = await loadSession(id);
|
||||
setSelected({ id, model: detail.model, resumeSessionId: id, initialMessages: detail.messages as ChatMessage[] });
|
||||
} finally {
|
||||
setOpeningId(null);
|
||||
}
|
||||
};
|
||||
|
||||
const startRename = (id: string, current: string) => {
|
||||
setConfirmingId(null);
|
||||
setEditingId(id);
|
||||
@@ -144,16 +131,11 @@ export const SessionList = () => {
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<button
|
||||
onClick={() => handleSelect(session.id)}
|
||||
disabled={!!openingId}
|
||||
<Link
|
||||
to={`/chat/${session.id}`}
|
||||
className="flex flex-1 items-center gap-3 px-4 py-3 min-w-0 text-left cursor-pointer"
|
||||
>
|
||||
{openingId === session.id ? (
|
||||
<Loader2 className="h-4 w-4 shrink-0 text-duck-teal/60 animate-spin" />
|
||||
) : (
|
||||
<MessageSquare className="h-4 w-4 shrink-0 text-duck-teal/60" />
|
||||
)}
|
||||
<MessageSquare className="h-4 w-4 shrink-0 text-duck-teal/60" />
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-sm font-medium text-duck-dark/80 dark:text-foreground/80 truncate">
|
||||
{session.title}
|
||||
@@ -179,7 +161,7 @@ export const SessionList = () => {
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</Link>
|
||||
|
||||
{isConfirming ? (
|
||||
<div className="flex shrink-0 items-center gap-1 mr-2">
|
||||
|
||||
Reference in New Issue
Block a user