-
-
-
-
props.onChange(event.target.value)}
- placeholder={t('sessions.search.placeholder')}
- className="w-full appearance-none rounded-lg border border-[var(--app-border)] bg-[var(--app-bg)] py-1.5 pl-8 pr-16 text-sm text-[var(--app-fg)] outline-none transition-colors placeholder:text-[var(--app-hint)] focus:border-[var(--app-link)] [&::-webkit-search-cancel-button]:hidden [&::-webkit-search-decoration]:hidden"
- />
- {props.value ? (
-
+
{
+ if (!event.currentTarget.contains(event.relatedTarget as Node | null)) {
+ props.onExpandedChange(false)
+ }
+ }}
+ >
+
+
+
+
props.onChange(event.target.value)}
+ placeholder={t('sessions.search.placeholder')}
+ className="w-full appearance-none rounded-lg border border-[var(--app-border)] bg-[var(--app-bg)] py-1.5 pl-8 pr-16 text-sm text-[var(--app-fg)] outline-none transition-colors placeholder:text-[var(--app-hint)] focus:border-[var(--app-link)] [&::-webkit-search-cancel-button]:hidden [&::-webkit-search-decoration]:hidden"
+ />
+ {props.value ? (
+
+ ) : null}
+
+
+ {datePickerOpen ? (
+ <>
+
)
@@ -896,6 +948,7 @@ export function SessionList(props: {
onRefresh: () => void
isLoading: boolean
renderHeader?: boolean
+ headerActions?: React.ReactNode
api: ApiClient | null
machineLabelsById?: Record
machinesById?: Record
@@ -909,6 +962,7 @@ export function SessionList(props: {
const { machineFilter, setMachineFilter } = useSessionListMachineFilter()
const showDetailedStatus = sessionListStatusMode === 'detailed'
const [searchQuery, setSearchQuery] = useState('')
+ const [searchExpanded, setSearchExpanded] = useState(false)
const [customStart, setCustomStart] = useState('')
const [customEnd, setCustomEnd] = useState('')
const [, setCodexImportedSessionsVersion] = useState(0)
@@ -1121,36 +1175,55 @@ export function SessionList(props: {
})
}, [allGroups])
+ // The search control unmounts when the list empties; reset the expansion so
+ // it cannot suppress header actions (or re-expand on its own when sessions
+ // return) while no search control is rendered.
+ const showSearch = props.sessions.length > 0
+ useEffect(() => {
+ if (!showSearch) setSearchExpanded(false)
+ }, [showSearch])
+
+ const showHeaderRow = showSearch || renderHeader || Boolean(props.headerActions)
+
return (
- {renderHeader ? (
-
-
-
-
+ {showHeaderRow ? (
+
+ {showSearch ? (
+
{
+ setCustomStart(start)
+ setCustomEnd(end)
+ }}
+ expanded={searchExpanded}
+ onExpandedChange={setSearchExpanded}
+ />
+ ) : null}
+ {!(showSearch && searchExpanded) ? (
+ <>
+
+ {renderHeader ? (
+
+
+
+ ) : null}
+ {props.headerActions}
+ >
+ ) : null}
) : null}
- {props.sessions.length > 0 ? (
-
{
- setCustomStart(start)
- setCustomEnd(end)
- }}
- />
- ) : null}
-
{props.sessions.length === 0 && (
-
-
-
-
-
-
-
navigate({ to: '/browse' })}
- className="p-1.5 rounded-full text-[var(--app-hint)] hover:text-[var(--app-fg)] hover:bg-[var(--app-subtle-bg)] transition-colors"
- title={t('browse.nav')}
- >
-
-
-
navigate({ to: '/settings' })}
- className="p-1.5 rounded-full text-[var(--app-hint)] hover:text-[var(--app-fg)] hover:bg-[var(--app-subtle-bg)] transition-colors"
- title={t('settings.title')}
- >
-
-
-
navigate({ to: '/sessions/new' })}
- className="session-list-new-button flex h-9 w-9 items-center justify-center rounded-full text-[var(--app-link)] transition-colors"
- title={t('sessions.new')}
- >
-
-
-
-
-
-
-
+
{error ? (
{error}
@@ -292,6 +250,45 @@ function SessionsPage() {
onRefresh={handleRefresh}
isLoading={isLoading}
renderHeader={false}
+ headerActions={(
+
+
+
+
+
navigate({ to: '/browse' })}
+ className="p-1.5 rounded-full text-[var(--app-hint)] hover:text-[var(--app-fg)] hover:bg-[var(--app-subtle-bg)] transition-colors"
+ title={t('browse.nav')}
+ >
+
+
+
navigate({ to: '/settings' })}
+ className="p-1.5 rounded-full text-[var(--app-hint)] hover:text-[var(--app-fg)] hover:bg-[var(--app-subtle-bg)] transition-colors"
+ title={t('settings.title')}
+ >
+
+
+
navigate({ to: '/sessions/new' })}
+ className="session-list-new-button flex h-9 w-9 items-center justify-center rounded-full text-[var(--app-link)] transition-colors"
+ title={t('sessions.new')}
+ >
+
+
+
+ )}
api={api}
machineLabelsById={machineLabelsById}
machinesById={machinesById}