fix: terminal shift-left bug and session sidebar naming/filtering
- Guard ResizeObserver in terminal against internal xterm DOM changes by tracking last width/height and only calling fit() on real resize - Remove padding from .terminal-container and conflicting .xterm height override that caused measurement mismatches with xterm-addon-fit - Filter live session sidebar to active statuses only (running, building, pending) instead of showing all sessions including stopped ones - Add display name fallback across sidebar, sessions page, and instance list to prevent blank names when display_name is empty Quality gates: tsc (pass), eslint (pass)
This commit is contained in:
@@ -48,3 +48,8 @@ apps/web/dist/
|
||||
# OS
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Local runtime state
|
||||
.atl/
|
||||
.pi/
|
||||
swap-pane
|
||||
|
||||
@@ -16,8 +16,11 @@ const NAV_ITEMS: { to: string; label: string; icon: IconName }[] = [
|
||||
{ to: "/settings", label: "Settings", icon: "settings" }
|
||||
];
|
||||
|
||||
const ACTIVE_STATUSES = ["running", "building", "pending"];
|
||||
|
||||
const SessionItem = ({ session }: { session: Session }) => {
|
||||
const isRunning = session.status === "running";
|
||||
const displayName = session.display_name || session.tool_type_name || "Unnamed Session";
|
||||
|
||||
return (
|
||||
<a
|
||||
@@ -25,11 +28,11 @@ const SessionItem = ({ session }: { session: Session }) => {
|
||||
target={session.url ? "_blank" : undefined}
|
||||
rel={session.url ? "noopener noreferrer" : undefined}
|
||||
className="nav-item session-item"
|
||||
title={`${session.display_name} (${session.status})`}
|
||||
title={`${displayName} (${session.status})`}
|
||||
>
|
||||
<span className={`session-status ${isRunning ? "running" : ""}`} />
|
||||
<Icon name={session.tool_icon as IconName} size="sm" />
|
||||
<span className="session-name">{session.display_name}</span>
|
||||
<span className="session-name">{displayName}</span>
|
||||
</a>
|
||||
);
|
||||
};
|
||||
@@ -101,13 +104,15 @@ export const AppShell = () => {
|
||||
);
|
||||
})}
|
||||
|
||||
{sessions.length > 0 && (
|
||||
{sessions.filter((s) => ACTIVE_STATUSES.includes(s.status)).length > 0 && (
|
||||
<>
|
||||
<div className="nav-divider" />
|
||||
<div className="nav-section-title">Live sessions</div>
|
||||
{sessions.map((session) => (
|
||||
<SessionItem key={session.id} session={session} />
|
||||
))}
|
||||
{sessions
|
||||
.filter((s) => ACTIVE_STATUSES.includes(s.status))
|
||||
.map((session) => (
|
||||
<SessionItem key={session.id} session={session} />
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</aside>
|
||||
|
||||
@@ -194,7 +194,7 @@ export const InstanceList = ({ projectId, repoId, toolTypes }: InstanceListProps
|
||||
{instances.map((instance) => (
|
||||
<div key={instance.id} className="instance-card">
|
||||
<div className="instance-info">
|
||||
<div className="instance-name">{instance.display_name}</div>
|
||||
<div className="instance-name">{instance.display_name || instance.tool_type_name || "Unnamed Instance"}</div>
|
||||
<div className="instance-meta">
|
||||
<span
|
||||
className="status-dot"
|
||||
|
||||
@@ -178,12 +178,26 @@ export const TerminalComponent: React.FC<TerminalProps> = ({
|
||||
|
||||
// Resize observer for container-level resize detection
|
||||
let resizeTimeout: ReturnType<typeof setTimeout> | null = null;
|
||||
const resizeObserver = new ResizeObserver(() => {
|
||||
let lastWidth = 0;
|
||||
let lastHeight = 0;
|
||||
const resizeObserver = new ResizeObserver((entries) => {
|
||||
if (resizeTimeout) {
|
||||
clearTimeout(resizeTimeout);
|
||||
}
|
||||
const entry = entries[0];
|
||||
if (!entry) return;
|
||||
const { width, height } = entry.contentRect;
|
||||
resizeTimeout = setTimeout(() => {
|
||||
resizeTimeout = null;
|
||||
// Guard against internal xterm DOM changes that don't affect container size
|
||||
if (
|
||||
Math.abs(width - lastWidth) < 1 &&
|
||||
Math.abs(height - lastHeight) < 1
|
||||
) {
|
||||
return;
|
||||
}
|
||||
lastWidth = width;
|
||||
lastHeight = height;
|
||||
const prevCols = term.cols;
|
||||
const prevRows = term.rows;
|
||||
fitAddon.fit();
|
||||
|
||||
@@ -266,7 +266,7 @@ export const SessionsPage = () => {
|
||||
<h2>Last Session</h2>
|
||||
<div className="card last-session-card">
|
||||
<div className="last-session-info">
|
||||
<h3>{lastSession.display_name}</h3>
|
||||
<h3>{lastSession.display_name || lastSession.tool_type_name || "Unnamed Session"}</h3>
|
||||
<p className="muted">
|
||||
{lastSession.tool_type_name} · {lastSession.project_name} · {lastSession.repository_name}
|
||||
</p>
|
||||
@@ -316,7 +316,7 @@ export const SessionsPage = () => {
|
||||
{activeSessions.map((session) => (
|
||||
<div className="card session-card" key={session.id}>
|
||||
<div className="session-info">
|
||||
<h4>{session.display_name}</h4>
|
||||
<h4>{session.display_name || session.tool_type_name || "Unnamed Session"}</h4>
|
||||
<p className="muted">
|
||||
{session.tool_type_name} · {session.project_name}
|
||||
</p>
|
||||
@@ -445,7 +445,7 @@ export const SessionsPage = () => {
|
||||
{recentSessions.map((session) => (
|
||||
<div className="recent-session-item" key={session.id}>
|
||||
<div className="recent-session-info">
|
||||
<span className="recent-session-name">{session.display_name}</span>
|
||||
<span className="recent-session-name">{session.display_name || session.tool_type_name || "Unnamed Session"}</span>
|
||||
<span className="muted">
|
||||
{session.tool_type_name} · {session.project_name}
|
||||
</span>
|
||||
|
||||
@@ -2748,11 +2748,6 @@ a.nav-item,
|
||||
.terminal-container {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
padding: 0.25rem;
|
||||
}
|
||||
|
||||
.terminal-container .xterm {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.terminal-container .xterm-viewport {
|
||||
|
||||
Reference in New Issue
Block a user