|
|
@@ -262,6 +262,10 @@ type SessionTreeProps = Pick<
|
|
|
onSessionArchive: (sessionId: SessionNode['id']) => void
|
|
|
/** Session order behavior: fixed after edits, or additionally promoted by user activity. */
|
|
|
orderBy: SessionOrderBy
|
|
|
+ /** One Session chosen from search that must be exposed and scrolled into view. */
|
|
|
+ revealSessionId?: SessionId | undefined
|
|
|
+ /** Acknowledge that the chosen Session row has been revealed. */
|
|
|
+ onSessionRevealed: (sessionId: SessionId) => void
|
|
|
}
|
|
|
|
|
|
/** The scrolling session tree; unmounting drops the sessions subscription and expand-all state. */
|
|
|
@@ -271,11 +275,18 @@ function SessionTree({
|
|
|
insertWorkspaceBefore, insertSessionBefore, orderBy,
|
|
|
groupExpansion, setGroupExpanded,
|
|
|
sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, home, t,
|
|
|
+ revealSessionId, onSessionRevealed,
|
|
|
}: SessionTreeProps) {
|
|
|
const list = useSessions(s => s)
|
|
|
const pendingInteractions = useSessionPendingInteraction(s => s)
|
|
|
const current = list.current
|
|
|
- const [expandedSessionGroups, setExpandedSessionGroups] = useState<string[]>([])
|
|
|
+ const revealGroup = revealSessionId === undefined
|
|
|
+ ? undefined
|
|
|
+ : (workspaces.find(w => w.sessionIds.includes(revealSessionId))?.workspaceId as string | undefined)
|
|
|
+ ?? UNGROUPED_KEY
|
|
|
+ const [expandedSessionGroups, setExpandedSessionGroups] = useState<string[]>(
|
|
|
+ () => revealGroup === undefined ? [] : [revealGroup],
|
|
|
+ )
|
|
|
// Transient drag marker state; the selected mode owns the resulting order.
|
|
|
const [drag, setDrag] = useState<DragState | null>(null)
|
|
|
const sessionDropCommitted = useRef(false)
|
|
|
@@ -564,6 +575,9 @@ function SessionTree({
|
|
|
onRename={onSessionRename}
|
|
|
onFork={forkSession}
|
|
|
onArchive={onSessionArchive}
|
|
|
+ onReveal={node.id === revealSessionId
|
|
|
+ ? () => { onSessionRevealed(node.id) }
|
|
|
+ : undefined}
|
|
|
drag={dragProps}
|
|
|
t={t}
|
|
|
/>
|
|
|
@@ -594,7 +608,8 @@ function SessionTree({
|
|
|
function FlatList({
|
|
|
useSessions, useSessionPendingInteraction, open, forkSession, onSessionRename, onSessionArchive,
|
|
|
archivedSessionIds,
|
|
|
- orderBy, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, t,
|
|
|
+ orderBy, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder,
|
|
|
+ revealSessionId, onSessionRevealed, t,
|
|
|
}: Pick<
|
|
|
SessionTreeProps,
|
|
|
| 'useSessions'
|
|
|
@@ -609,6 +624,8 @@ function FlatList({
|
|
|
| 'sessionUpdatedAtByAccount'
|
|
|
| 'syncSessionOrderAccount'
|
|
|
| 'setSessionOrder'
|
|
|
+ | 'revealSessionId'
|
|
|
+ | 'onSessionRevealed'
|
|
|
| 't'
|
|
|
>) {
|
|
|
const list = useSessions(s => s)
|
|
|
@@ -683,6 +700,9 @@ function FlatList({
|
|
|
onRename={onSessionRename}
|
|
|
onFork={forkSession}
|
|
|
onArchive={onSessionArchive}
|
|
|
+ onReveal={node.id === revealSessionId
|
|
|
+ ? () => { onSessionRevealed(node.id) }
|
|
|
+ : undefined}
|
|
|
flat
|
|
|
drag={{
|
|
|
start: () => {
|
|
|
@@ -874,6 +894,7 @@ export function WorkspaceBrowser({
|
|
|
// does not silently drop an in-progress filter.
|
|
|
const [query, setQuery] = useState('')
|
|
|
const [searchExpanded, setSearchExpanded] = useState(false)
|
|
|
+ const [revealSessionId, setRevealSessionId] = useState<SessionId | undefined>(undefined)
|
|
|
const normalizedQuery = sanitizeSearchQuery(query).trim()
|
|
|
const [remoteSearch, setRemoteSearch] = useState<RemoteSearchState>({
|
|
|
query: '',
|
|
|
@@ -889,6 +910,19 @@ export function WorkspaceBrowser({
|
|
|
const wsPlusRef = useRef<HTMLButtonElement>(null)
|
|
|
const composingRef = useRef(false)
|
|
|
|
|
|
+ const openSearchResult = (sessionId: SessionId): void => {
|
|
|
+ const groupKey = (workspaces.find(workspace => workspace.sessionIds.includes(sessionId))
|
|
|
+ ?.workspaceId as string | undefined) ?? UNGROUPED_KEY
|
|
|
+ actions.setGroupExpanded(groupKey, true)
|
|
|
+ setRevealSessionId(sessionId)
|
|
|
+ setQuery('')
|
|
|
+ setSearchExpanded(false)
|
|
|
+ open(sessionId)
|
|
|
+ }
|
|
|
+ const acknowledgeSessionReveal = (sessionId: SessionId): void => {
|
|
|
+ setRevealSessionId(current => current === sessionId ? undefined : current)
|
|
|
+ }
|
|
|
+
|
|
|
// Rail search = expand + land in the search box: the flag arms before the
|
|
|
// expand request; once the shell flips wide the input mounts and takes focus.
|
|
|
const [searchOnExpand, setSearchOnExpand] = useState(false)
|
|
|
@@ -1206,7 +1240,7 @@ export function WorkspaceBrowser({
|
|
|
<SearchResults
|
|
|
useSessions={useSessions}
|
|
|
useSessionPendingInteraction={useSessionPendingInteraction}
|
|
|
- open={open}
|
|
|
+ open={openSearchResult}
|
|
|
workspaces={workspaces}
|
|
|
archivedSessionIds={archivedSessionIds}
|
|
|
query={normalizedQuery}
|
|
|
@@ -1227,6 +1261,8 @@ export function WorkspaceBrowser({
|
|
|
sessionUpdatedAtByAccount={sessionUpdatedAtByAccount}
|
|
|
syncSessionOrderAccount={actions.syncSessionOrderAccount}
|
|
|
setSessionOrder={actions.setSessionOrder}
|
|
|
+ revealSessionId={revealSessionId}
|
|
|
+ onSessionRevealed={acknowledgeSessionReveal}
|
|
|
t={t}
|
|
|
/>
|
|
|
)
|
|
|
@@ -1250,6 +1286,8 @@ export function WorkspaceBrowser({
|
|
|
insertWorkspaceBefore={insertWorkspaceBefore}
|
|
|
insertSessionBefore={insertSessionBefore}
|
|
|
orderBy={orderBy}
|
|
|
+ revealSessionId={revealSessionId}
|
|
|
+ onSessionRevealed={acknowledgeSessionReveal}
|
|
|
home={home}
|
|
|
t={t}
|
|
|
onRenameRequest={(workspaceId, currentTitle) => {
|