feat(mobile): add child session indicators to current session in MobileSessionStatusBar (#525)

- Add childIndicators prop to SessionStatusHeader component
- Display up to 3 running child sessions with their agent colors
- Show extra count (+n) when there are more than 3 child sessions
- Align visual style with non-selected session items (using brackets [])
- Pass childIndicators through CollapsedView and ExpandedView components
- Extract child indicators from current session's processed status

Co-authored-by: Jovines <jovines@qq.com>
This commit is contained in:
Jovines
2026-02-26 20:08:42 +02:00
committed by GitHub
co-authored by Jovines
parent 26b95e2bd9
commit 32619e9f90
@@ -393,6 +393,7 @@ interface SessionStatusHeaderProps {
currentProjectColor?: string | null; currentProjectColor?: string | null;
onToggle: () => void; onToggle: () => void;
isExpanded?: boolean; isExpanded?: boolean;
childIndicators?: Array<{ session: Session; isRunning: boolean }>;
} }
function SessionStatusHeader({ function SessionStatusHeader({
@@ -401,10 +402,12 @@ function SessionStatusHeader({
currentProjectIcon, currentProjectIcon,
currentProjectColor, currentProjectColor,
onToggle, onToggle,
isExpanded = false isExpanded = false,
childIndicators = []
}: SessionStatusHeaderProps) { }: SessionStatusHeaderProps) {
const ProjectIcon = currentProjectIcon ? PROJECT_ICON_MAP[currentProjectIcon] : null; const ProjectIcon = currentProjectIcon ? PROJECT_ICON_MAP[currentProjectIcon] : null;
const projectColorVar = currentProjectColor ? (PROJECT_COLOR_MAP[currentProjectColor] ?? null) : null; const projectColorVar = currentProjectColor ? (PROJECT_COLOR_MAP[currentProjectColor] ?? null) : null;
const extraCount = childIndicators.length > 3 ? childIndicators.length - 3 : 0;
return ( return (
<button <button
@@ -431,9 +434,40 @@ function SessionStatusHeader({
<div className="w-full h-px bg-[var(--interactive-border)] my-1" /> <div className="w-full h-px bg-[var(--interactive-border)] my-1" />
</div> </div>
)} )}
<span className="text-[13px] text-[var(--surface-foreground)] truncate leading-none"> <div className="flex items-center gap-1.5">
{currentSessionTitle} <span className="text-[13px] text-[var(--surface-foreground)] truncate leading-none">
</span> {currentSessionTitle}
</span>
{childIndicators.length > 0 && (
<div className="flex items-center gap-0.5 text-[var(--surface-mutedForeground)]">
<span className="text-[10px]">[</span>
<div className="flex items-center gap-0.5">
{childIndicators.slice(0, 3).map((child) => {
const childAgent = (child.session as { agent?: string }).agent || 'agent';
const childColor = getAgentColor(childAgent);
return (
<div
key={child.session.id}
className="flex-shrink-0"
title={`Sub-session: ${child.session.title || 'Untitled'}`}
>
<RiLoader4Line
className="h-2.5 w-2.5 animate-spin"
style={{ color: `var(${childColor.var})` }}
/>
</div>
);
})}
{extraCount > 0 && (
<span className="text-[10px] text-[var(--surface-mutedForeground)]">
+{extraCount}
</span>
)}
</div>
<span className="text-[10px]">]</span>
</div>
)}
</div>
</button> </button>
); );
} }
@@ -723,6 +757,7 @@ function CollapsedView({
onNewSession, onNewSession,
cornerRadius, cornerRadius,
contextUsage, contextUsage,
childIndicators = [],
}: { }: {
runningCount: number; runningCount: number;
unreadCount: number; unreadCount: number;
@@ -734,6 +769,7 @@ function CollapsedView({
onNewSession: () => void; onNewSession: () => void;
cornerRadius?: number; cornerRadius?: number;
contextUsage: SessionContextUsage | null; contextUsage: SessionContextUsage | null;
childIndicators?: Array<{ session: Session; isRunning: boolean }>;
}) { }) {
const { handleTouchStart, handleTouchMove, handleTouchEnd } = useDrawerSwipe(); const { handleTouchStart, handleTouchMove, handleTouchEnd } = useDrawerSwipe();
@@ -755,6 +791,7 @@ function CollapsedView({
currentProjectIcon={currentProjectIcon} currentProjectIcon={currentProjectIcon}
currentProjectColor={currentProjectColor} currentProjectColor={currentProjectColor}
onToggle={onToggle} onToggle={onToggle}
childIndicators={childIndicators}
/> />
</div> </div>
<div className="flex items-center gap-2 flex-shrink-0"> <div className="flex items-center gap-2 flex-shrink-0">
@@ -808,6 +845,7 @@ function ExpandedView({
activeProjectId, activeProjectId,
getProjectStatus, getProjectStatus,
homeDirectory, homeDirectory,
childIndicators = [],
}: { }: {
sessions: SessionWithStatus[]; sessions: SessionWithStatus[];
currentSessionId: string; currentSessionId: string;
@@ -834,6 +872,7 @@ function ExpandedView({
activeProjectId: string | null; activeProjectId: string | null;
getProjectStatus: (path: string) => { hasRunning: boolean; hasUnread: boolean }; getProjectStatus: (path: string) => { hasRunning: boolean; hasUnread: boolean };
homeDirectory: string | null; homeDirectory: string | null;
childIndicators?: Array<{ session: Session; isRunning: boolean }>;
}) { }) {
const containerRef = React.useRef<HTMLDivElement>(null); const containerRef = React.useRef<HTMLDivElement>(null);
const [collapsedHeight, setCollapsedHeight] = React.useState<number | null>(null); const [collapsedHeight, setCollapsedHeight] = React.useState<number | null>(null);
@@ -900,6 +939,7 @@ function ExpandedView({
currentProjectColor={currentProjectColor} currentProjectColor={currentProjectColor}
onToggle={onToggleCollapse} onToggle={onToggleCollapse}
isExpanded={true} isExpanded={true}
childIndicators={childIndicators}
/> />
</div> </div>
<div <div
@@ -1006,6 +1046,10 @@ export const MobileSessionStatusBar: React.FC<MobileSessionStatusBarProps> = ({
? getSessionTitle(currentSession) ? getSessionTitle(currentSession)
: '← Swipe here to open sidebars →'; : '← Swipe here to open sidebars →';
// Calculate current session's child indicators
const currentSessionWithStatus = sortedSessions.find((s) => s.id === currentSessionId);
const currentSessionChildIndicators = currentSessionWithStatus?._childIndicators ?? [];
const activeProject = getActiveProject(); const activeProject = getActiveProject();
const currentProjectLabel = activeProject?.label || formatDirectoryName(activeProject?.path || '', homeDirectory); const currentProjectLabel = activeProject?.label || formatDirectoryName(activeProject?.path || '', homeDirectory);
const currentProjectIcon = activeProject?.icon; const currentProjectIcon = activeProject?.icon;
@@ -1088,6 +1132,7 @@ export const MobileSessionStatusBar: React.FC<MobileSessionStatusBarProps> = ({
onNewSession={handleCreateSession} onNewSession={handleCreateSession}
cornerRadius={cornerRadius} cornerRadius={cornerRadius}
contextUsage={contextUsage} contextUsage={contextUsage}
childIndicators={currentSessionChildIndicators}
/> />
); );
} }
@@ -1122,6 +1167,7 @@ export const MobileSessionStatusBar: React.FC<MobileSessionStatusBarProps> = ({
activeProjectId={activeProjectId} activeProjectId={activeProjectId}
getProjectStatus={getProjectStatus} getProjectStatus={getProjectStatus}
homeDirectory={homeDirectory} homeDirectory={homeDirectory}
childIndicators={currentSessionChildIndicators}
/> />
); );
}; };