Compact dashboard room progress UI
Compact the Rooms progress panel into a Discord-like current progress strip, show only the latest output by default, and move history/compose controls behind details.
This commit is contained in:
@@ -1315,56 +1315,63 @@ function RoomActivityPanel({
|
||||
const task = activity.pairedTask;
|
||||
const turn = task?.currentTurn ?? null;
|
||||
const outputs = task?.outputs ?? [];
|
||||
const latestOutput = outputs.at(-1) ?? null;
|
||||
const progressText = turn
|
||||
? `${turn.role} · ${turn.intentKind} · ${t.rooms.attempt} ${turn.attemptNo}`
|
||||
: t.rooms.noTurn;
|
||||
|
||||
return (
|
||||
<div className="room-activity">
|
||||
<div className="room-activity-grid">
|
||||
<span>
|
||||
<small>{t.rooms.task}</small>
|
||||
<strong>{task?.title || task?.id || t.rooms.noTask}</strong>
|
||||
</span>
|
||||
<span>
|
||||
<small>{t.rooms.currentTurn}</small>
|
||||
<strong>
|
||||
{turn
|
||||
? `${turn.role} · ${t.rooms.attempt} ${turn.attemptNo}`
|
||||
: t.rooms.noTurn}
|
||||
</strong>
|
||||
</span>
|
||||
<span>
|
||||
<small>{t.rooms.round}</small>
|
||||
<strong>{task ? task.roundTripCount : '-'}</strong>
|
||||
</span>
|
||||
<span>
|
||||
<small>{t.rooms.updated}</small>
|
||||
<strong>
|
||||
{formatDate(turn?.updatedAt ?? task?.updatedAt, locale)}
|
||||
</strong>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="room-progress-strip">
|
||||
{turn ? (
|
||||
<div className="room-turn-line">
|
||||
<span className={`pill pill-${turn.state}`}>
|
||||
{statusLabel(turn.state, t)}
|
||||
</span>
|
||||
<span>{turn.intentKind}</span>
|
||||
{turn.executorServiceId ? (
|
||||
<span>{turn.executorServiceId}</span>
|
||||
) : (
|
||||
<span className="pill pill-inactive">{t.rooms.noTurn}</span>
|
||||
)}
|
||||
<strong>{progressText}</strong>
|
||||
<span>{task ? `${t.rooms.round} ${task.roundTripCount}` : '-'}</span>
|
||||
{turn?.executorServiceId ? <span>{turn.executorServiceId}</span> : null}
|
||||
<time>{formatDate(turn?.updatedAt ?? task?.updatedAt, locale)}</time>
|
||||
</div>
|
||||
|
||||
<section className="room-latest-output">
|
||||
<header>
|
||||
<strong>{t.rooms.latestOutput}</strong>
|
||||
{latestOutput ? (
|
||||
<span>
|
||||
#{latestOutput.turnNumber} · {latestOutput.role}
|
||||
{latestOutput.verdict ? ` · ${latestOutput.verdict}` : ''}
|
||||
</span>
|
||||
) : null}
|
||||
{turn.activeRunId ? (
|
||||
</header>
|
||||
{latestOutput ? (
|
||||
<p>{latestOutput.outputText}</p>
|
||||
) : (
|
||||
<p className="room-muted">{t.rooms.noOutput}</p>
|
||||
)}
|
||||
</section>
|
||||
|
||||
<details className="room-activity-details">
|
||||
<summary>{t.rooms.details}</summary>
|
||||
<div className="room-detail-grid">
|
||||
<section>
|
||||
<strong>{t.rooms.task}</strong>
|
||||
<p className="room-muted">
|
||||
{task?.title || task?.id || t.rooms.noTask}
|
||||
</p>
|
||||
<div className="room-turn-line">
|
||||
{turn?.activeRunId ? (
|
||||
<span className="mono-chip">{turn.activeRunId}</span>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{turn?.lastError ? (
|
||||
<p className="room-activity-error">{turn.lastError}</p>
|
||||
<span className="room-activity-error">{turn.lastError}</span>
|
||||
) : null}
|
||||
|
||||
<div className="room-activity-columns">
|
||||
</div>
|
||||
</section>
|
||||
<section>
|
||||
<strong>{t.rooms.output}</strong>
|
||||
<strong>{t.rooms.outputHistory}</strong>
|
||||
{outputs.length === 0 ? (
|
||||
<p className="room-muted">{t.rooms.noOutput}</p>
|
||||
) : (
|
||||
@@ -1385,7 +1392,7 @@ function RoomActivityPanel({
|
||||
)}
|
||||
</section>
|
||||
<section>
|
||||
<strong>{t.rooms.recentMessages}</strong>
|
||||
<strong>{t.rooms.messageHistory}</strong>
|
||||
{activity.messages.length === 0 ? (
|
||||
<p className="room-muted">{t.rooms.noMessages}</p>
|
||||
) : (
|
||||
@@ -1408,10 +1415,38 @@ function RoomActivityPanel({
|
||||
)}
|
||||
</section>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
function RoomComposeDetails({
|
||||
busy,
|
||||
onChange,
|
||||
onSubmit,
|
||||
t,
|
||||
value,
|
||||
}: {
|
||||
busy: boolean;
|
||||
onChange: (value: string) => void;
|
||||
onSubmit: () => void;
|
||||
t: Messages;
|
||||
value: string;
|
||||
}) {
|
||||
return (
|
||||
<details className="room-compose-details">
|
||||
<summary>{t.rooms.message}</summary>
|
||||
<RoomMessageForm
|
||||
busy={busy}
|
||||
onChange={onChange}
|
||||
onSubmit={onSubmit}
|
||||
t={t}
|
||||
value={value}
|
||||
/>
|
||||
</details>
|
||||
);
|
||||
}
|
||||
|
||||
function RoomPanel({
|
||||
onSendRoomMessage,
|
||||
roomActivity,
|
||||
@@ -1502,8 +1537,8 @@ function RoomPanel({
|
||||
t={t}
|
||||
/>
|
||||
</td>
|
||||
<td>
|
||||
<RoomMessageForm
|
||||
<td className="room-message-cell">
|
||||
<RoomComposeDetails
|
||||
busy={roomMessageKey === entry.jid}
|
||||
onChange={(value) => setDraft(entry.jid, value)}
|
||||
onSubmit={() => void submitRoomMessage(entry.jid)}
|
||||
@@ -1550,7 +1585,7 @@ function RoomPanel({
|
||||
locale={locale}
|
||||
t={t}
|
||||
/>
|
||||
<RoomMessageForm
|
||||
<RoomComposeDetails
|
||||
busy={roomMessageKey === entry.jid}
|
||||
onChange={(value) => setDraft(entry.jid, value)}
|
||||
onSubmit={() => void submitRoomMessage(entry.jid)}
|
||||
|
||||
@@ -158,8 +158,11 @@ export interface Messages {
|
||||
attempt: string;
|
||||
updated: string;
|
||||
output: string;
|
||||
latestOutput: string;
|
||||
outputHistory: string;
|
||||
noOutput: string;
|
||||
recentMessages: string;
|
||||
messageHistory: string;
|
||||
noMessages: string;
|
||||
details: string;
|
||||
message: string;
|
||||
@@ -446,8 +449,11 @@ export const messages = {
|
||||
attempt: '시도',
|
||||
updated: '갱신',
|
||||
output: '출력',
|
||||
latestOutput: '마지막 출력',
|
||||
outputHistory: '출력 기록',
|
||||
noOutput: '출력 없음',
|
||||
recentMessages: '최근 메시지',
|
||||
recentMessages: '메시지 기록',
|
||||
messageHistory: '메시지 기록',
|
||||
noMessages: '메시지 없음',
|
||||
details: '세부',
|
||||
message: 'Message',
|
||||
@@ -718,8 +724,11 @@ export const messages = {
|
||||
attempt: 'attempt',
|
||||
updated: 'updated',
|
||||
output: 'output',
|
||||
latestOutput: 'latest output',
|
||||
outputHistory: 'output log',
|
||||
noOutput: 'No output',
|
||||
recentMessages: 'Recent messages',
|
||||
recentMessages: 'Message log',
|
||||
messageHistory: 'Message log',
|
||||
noMessages: 'No messages',
|
||||
details: 'details',
|
||||
message: 'message',
|
||||
@@ -990,8 +999,11 @@ export const messages = {
|
||||
attempt: '尝试',
|
||||
updated: '更新',
|
||||
output: '输出',
|
||||
latestOutput: '最新输出',
|
||||
outputHistory: '输出记录',
|
||||
noOutput: '暂无输出',
|
||||
recentMessages: '最近消息',
|
||||
recentMessages: '消息记录',
|
||||
messageHistory: '消息记录',
|
||||
noMessages: '暂无消息',
|
||||
details: '详情',
|
||||
message: 'Message',
|
||||
@@ -1262,8 +1274,11 @@ export const messages = {
|
||||
attempt: '試行',
|
||||
updated: '更新',
|
||||
output: '出力',
|
||||
latestOutput: '最新出力',
|
||||
outputHistory: '出力履歴',
|
||||
noOutput: '出力なし',
|
||||
recentMessages: '最近のメッセージ',
|
||||
recentMessages: 'メッセージ履歴',
|
||||
messageHistory: 'メッセージ履歴',
|
||||
noMessages: 'メッセージなし',
|
||||
details: '詳細',
|
||||
message: 'Message',
|
||||
|
||||
@@ -1328,16 +1328,16 @@ progress::-moz-progress-bar {
|
||||
}
|
||||
|
||||
.room-activity-cell {
|
||||
min-width: 360px;
|
||||
min-width: 300px;
|
||||
}
|
||||
|
||||
.room-activity {
|
||||
display: grid;
|
||||
min-width: min(360px, 100%);
|
||||
gap: 9px;
|
||||
padding: 10px;
|
||||
min-width: min(300px, 100%);
|
||||
gap: 7px;
|
||||
padding: 8px;
|
||||
border: 1px solid rgba(43, 55, 38, 0.1);
|
||||
border-radius: 18px;
|
||||
border-radius: 15px;
|
||||
background: rgba(255, 250, 240, 0.58);
|
||||
}
|
||||
|
||||
@@ -1348,38 +1348,28 @@ progress::-moz-progress-bar {
|
||||
font-weight: 800;
|
||||
}
|
||||
|
||||
.room-activity-grid {
|
||||
.room-progress-strip {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(4, minmax(0, 1fr));
|
||||
gap: 7px;
|
||||
}
|
||||
|
||||
.room-activity-grid > span {
|
||||
grid-template-columns: auto minmax(96px, 1fr) auto auto auto;
|
||||
gap: 6px;
|
||||
align-items: center;
|
||||
min-width: 0;
|
||||
padding: 8px;
|
||||
border-radius: 13px;
|
||||
background: rgba(43, 55, 38, 0.045);
|
||||
color: var(--muted);
|
||||
font-size: 11px;
|
||||
font-weight: 850;
|
||||
}
|
||||
|
||||
.room-activity-grid small,
|
||||
.room-activity-grid strong {
|
||||
display: block;
|
||||
.room-progress-strip strong,
|
||||
.room-progress-strip span,
|
||||
.room-progress-strip time {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.room-activity-grid small {
|
||||
color: var(--muted);
|
||||
font-size: 10px;
|
||||
font-weight: 850;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.room-activity-grid strong {
|
||||
margin-top: 3px;
|
||||
.room-progress-strip strong {
|
||||
color: var(--ink);
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
@@ -1398,33 +1388,85 @@ progress::-moz-progress-bar {
|
||||
}
|
||||
|
||||
.room-activity-error {
|
||||
margin: 0;
|
||||
color: #7c2518;
|
||||
font-size: 12px;
|
||||
font-weight: 850;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.room-activity-columns {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
||||
gap: 9px;
|
||||
}
|
||||
|
||||
.room-activity-columns > section {
|
||||
.room-latest-output {
|
||||
display: grid;
|
||||
gap: 4px;
|
||||
min-width: 0;
|
||||
align-content: start;
|
||||
gap: 7px;
|
||||
padding: 8px;
|
||||
border-radius: 12px;
|
||||
background: rgba(43, 55, 38, 0.045);
|
||||
}
|
||||
|
||||
.room-activity-columns > section > strong {
|
||||
.room-latest-output header {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
align-items: baseline;
|
||||
justify-content: space-between;
|
||||
color: var(--muted);
|
||||
font-size: 11px;
|
||||
font-weight: 850;
|
||||
}
|
||||
|
||||
.room-latest-output strong,
|
||||
.room-detail-grid > section > strong {
|
||||
color: var(--bg-ink);
|
||||
font-size: 12px;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.room-latest-output header span,
|
||||
.room-latest-output p {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.room-latest-output p {
|
||||
display: -webkit-box;
|
||||
margin: 0;
|
||||
color: var(--ink);
|
||||
font-size: 12px;
|
||||
line-height: 1.32;
|
||||
overflow-wrap: anywhere;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 2;
|
||||
}
|
||||
|
||||
.room-activity-details,
|
||||
.room-compose-details {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.room-activity-details > summary,
|
||||
.room-compose-details > summary {
|
||||
min-height: 32px;
|
||||
color: var(--accent);
|
||||
font-size: 12px;
|
||||
font-weight: 900;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.room-detail-grid {
|
||||
display: grid;
|
||||
gap: 8px;
|
||||
min-width: 0;
|
||||
padding-top: 6px;
|
||||
}
|
||||
|
||||
.room-detail-grid > section {
|
||||
display: grid;
|
||||
min-width: 0;
|
||||
align-content: start;
|
||||
gap: 7px;
|
||||
}
|
||||
|
||||
.room-output-list,
|
||||
.room-message-list {
|
||||
display: grid;
|
||||
@@ -1486,6 +1528,14 @@ progress::-moz-progress-bar {
|
||||
-webkit-line-clamp: 4;
|
||||
}
|
||||
|
||||
.room-message-cell {
|
||||
width: 150px;
|
||||
}
|
||||
|
||||
.room-compose-details .room-compose {
|
||||
margin-top: 6px;
|
||||
}
|
||||
|
||||
.task-board {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
@@ -2165,9 +2215,13 @@ progress::-moz-progress-bar {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.room-activity-grid,
|
||||
.room-activity-columns {
|
||||
grid-template-columns: 1fr;
|
||||
.room-progress-strip {
|
||||
grid-template-columns: auto minmax(0, 1fr) auto;
|
||||
}
|
||||
|
||||
.room-progress-strip span:nth-of-type(n + 3),
|
||||
.room-progress-strip time {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.inbox-summary,
|
||||
|
||||
Reference in New Issue
Block a user