diff --git a/dashboard/components/ChatMessages.js b/dashboard/components/ChatMessages.js
index 2147418..6a75935 100644
--- a/dashboard/components/ChatMessages.js
+++ b/dashboard/components/ChatMessages.js
@@ -1,8 +1,9 @@
import { html, useRef, useEffect } from '../lib/preact.js';
-import { getUserMessageBg } from '../utils/status.js';
+import { getUserMessageBg, getStatusMeta } from '../utils/status.js';
import { MessageBubble, filterDisplayMessages } from './MessageBubble.js';
export function ChatMessages({ messages, status }) {
+ const statusMeta = getStatusMeta(status);
const containerRef = useRef(null);
const userBgClass = getUserMessageBg(status);
const wasAtBottomRef = useRef(true);
@@ -56,15 +57,25 @@ export function ChatMessages({ messages, status }) {
const displayMessages = filterDisplayMessages(messages).slice(-20);
return html`
-
- ${displayMessages.map((msg, i) => html`
- <${MessageBubble}
- key=${i}
- msg=${msg}
- userBg=${userBgClass}
- compact=${true}
- />
- `)}
+
+
+ ${displayMessages.map((msg, i) => html`
+ <${MessageBubble}
+ key=${i}
+ msg=${msg}
+ userBg=${userBgClass}
+ compact=${true}
+ />
+ `)}
+
+ ${statusMeta.spinning && html`
+
+
+
+ ...
+
+
+ `}
`;
}
diff --git a/dashboard/components/Modal.js b/dashboard/components/Modal.js
index a8f8361..5547168 100644
--- a/dashboard/components/Modal.js
+++ b/dashboard/components/Modal.js
@@ -132,7 +132,7 @@ export function Modal({ session, conversations, conversationLoading, onClose, on
${session.project || session.name || session.session_id}
-
+
${status.label}
@@ -178,6 +178,15 @@ export function Modal({ session, conversations, conversationLoading, onClose, on
No conversation messages
`}
+ ${status.spinning && html`
+
+
+ Agent is working
+
+ ...
+
+
+ `}
diff --git a/dashboard/components/SessionCard.js b/dashboard/components/SessionCard.js
index 40a09d5..69061a2 100644
--- a/dashboard/components/SessionCard.js
+++ b/dashboard/components/SessionCard.js
@@ -35,7 +35,7 @@ export function SessionCard({ session, onClick, conversation, onFetchConversatio
-
+
${session.project || session.name || 'Session'}
diff --git a/dashboard/styles.css b/dashboard/styles.css
index 24644b6..5fbac34 100644
--- a/dashboard/styles.css
+++ b/dashboard/styles.css
@@ -67,6 +67,36 @@ body {
animation: pulse-attention 2s ease-in-out infinite;
}
+/* Active session spinner */
+@keyframes spin-ring {
+ to { transform: rotate(360deg); }
+}
+
+.spinner-dot {
+ position: relative;
+ display: inline-block;
+}
+
+.spinner-dot::after {
+ content: '';
+ position: absolute;
+ inset: -2px;
+ border-radius: 50%;
+ border: 1.5px solid transparent;
+ border-top-color: currentColor;
+ animation: spin-ring 0.8s linear infinite;
+}
+
+/* Working indicator at bottom of chat */
+@keyframes bounce-dot {
+ 0%, 80%, 100% { transform: translateY(0); }
+ 40% { transform: translateY(-4px); }
+}
+
+.working-dots span:nth-child(1) { animation: bounce-dot 1.2s ease-in-out infinite; }
+.working-dots span:nth-child(2) { animation: bounce-dot 1.2s ease-in-out 0.15s infinite; }
+.working-dots span:nth-child(3) { animation: bounce-dot 1.2s ease-in-out 0.3s infinite; }
+
/* Glass panel effect */
.glass-panel {
backdrop-filter: blur(10px);
diff --git a/dashboard/utils/status.js b/dashboard/utils/status.js
index a517bef..1e3d56b 100644
--- a/dashboard/utils/status.js
+++ b/dashboard/utils/status.js
@@ -22,6 +22,7 @@ export function getStatusMeta(status) {
dot: 'bg-active',
badge: 'bg-active/18 text-active border-active/40',
borderColor: '#5fd0a4',
+ spinning: true,
};
case 'starting':
return {
@@ -29,6 +30,7 @@ export function getStatusMeta(status) {
dot: 'bg-starting',
badge: 'bg-starting/18 text-starting border-starting/40',
borderColor: '#7cb2ff',
+ spinning: true,
};
case 'done':
return {