diff --git a/src/pages/agent-office/AgentOffice.css b/src/pages/agent-office/AgentOffice.css index e8dc4c0..4e790ba 100644 --- a/src/pages/agent-office/AgentOffice.css +++ b/src/pages/agent-office/AgentOffice.css @@ -70,6 +70,21 @@ flex-shrink: 0; } +.ao-col-chevron { + display: none; + color: #666; + font-size: 0.8rem; + margin-left: 4px; +} + +.ao-col-body { + display: flex; + flex-direction: column; + flex: 1; + min-height: 0; + overflow: hidden; +} + .ao-col-name { font-weight: bold; font-size: 0.9rem; @@ -303,3 +318,71 @@ font-size: 0.7rem; margin-left: 4px; } + +/* Mobile: vertical stack + accordion */ +@media (max-width: 768px) { + .ao-page { + height: auto; + min-height: 100vh; + } + + .ao-dashboard { + flex-direction: column; + gap: 1px; + overflow: visible; + flex: none; + } + + .ao-col { + flex: none; + overflow: visible; + } + + .ao-col-header { + cursor: pointer; + user-select: none; + padding: 12px 14px; + } + + .ao-col-chevron { + display: inline; + } + + .ao-col--collapsed .ao-col-body { + display: none; + } + + .ao-col--attention { + box-shadow: inset 3px 0 0 #fbbf24; + } + + .ao-col-tasks { + max-height: 260px; + } + + .ao-office-section { + height: 140px; + order: -1; + border-top: none; + border-bottom: 2px solid #2a2a4a; + } + + .ao-title { + font-size: 1rem; + letter-spacing: 1px; + } + + .ao-header { + padding: 8px 12px; + } + + .ao-col-commands { + gap: 6px; + } + + .ao-cmd-btn, + .ao-btn { + padding: 6px 12px; + font-size: 0.8rem; + } +} diff --git a/src/pages/agent-office/components/AgentColumn.jsx b/src/pages/agent-office/components/AgentColumn.jsx index 775a3e0..3893d10 100644 --- a/src/pages/agent-office/components/AgentColumn.jsx +++ b/src/pages/agent-office/components/AgentColumn.jsx @@ -35,9 +35,12 @@ const AgentColumn = ({ agentId, meta, agentState, notification, onCommand, onApp const [input, setInput] = useState(''); const [activeCommand, setActiveCommand] = useState(null); const [tokenUsage, setTokenUsage] = useState(null); + const [expanded, setExpanded] = useState(false); const state = agentState || { state: 'offline' }; const commands = AGENT_COMMANDS[agentId] || []; + const needsAttention = state.state === 'waiting' || notification > 0; + const isOpen = expanded || needsAttention; useEffect(() => { getAgentTasks(agentId, 10) @@ -89,11 +92,31 @@ const AgentColumn = ({ agentId, meta, agentState, notification, onCommand, onApp setActiveCommand(null); }; - const formatTime = (t) => t ? t.replace('T', ' ').slice(11, 19) : ''; + const formatTaskTime = (task) => { + const iso = task.completed_at || task.created_at; + if (!iso) return ''; + const d = new Date(iso); + if (isNaN(d.getTime())) return ''; + const now = new Date(); + const pad = (n) => String(n).padStart(2, '0'); + const hm = `${pad(d.getHours())}:${pad(d.getMinutes())}`; + const sameDay = d.toDateString() === now.toDateString(); + const yesterday = new Date(now); yesterday.setDate(now.getDate() - 1); + const isYesterday = d.toDateString() === yesterday.toDateString(); + if (sameDay) return `오늘 ${hm}`; + if (isYesterday) return `어제 ${hm}`; + return `${pad(d.getMonth() + 1)}-${pad(d.getDate())} ${hm}`; + }; + + const handleHeaderClick = (e) => { + e.stopPropagation(); + setExpanded(v => !v); + onClearNotification(); + }; return ( -
-
+
+
{meta.name} {tokenUsage && tokenUsage.total_tokens > 0 && ( {state.state} {notification > 0 && {notification}} +
+
+ + {state.detail && (
{state.detail}
)} @@ -153,7 +180,7 @@ const AgentColumn = ({ agentId, meta, agentState, notification, onCommand, onApp {badge.label}
- {formatTime(task.created_at)} + {formatTaskTime(task)} {task.result_data?.telegram_sent !== undefined && ( {task.result_data.telegram_sent ? ' TG OK' : ' TG Fail'} )} @@ -168,6 +195,7 @@ const AgentColumn = ({ agentId, meta, agentState, notification, onCommand, onApp ); })}
+
); };