Skip to content

Commit bf2cc3a

Browse files
authored
feat(app): show which messages are queued (#15587)
1 parent 4b9e19f commit bf2cc3a

20 files changed

Lines changed: 77 additions & 6 deletions

File tree

packages/ui/src/components/message-part.css

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,12 +46,18 @@
4646
overflow: hidden;
4747
background: var(--surface-weak);
4848
border: 1px solid var(--border-weak-base);
49-
transition: border-color 0.15s ease;
49+
transition:
50+
border-color 0.15s ease,
51+
opacity 0.3s ease;
5052

5153
&:hover {
5254
border-color: var(--border-strong-base);
5355
}
5456

57+
&[data-queued] {
58+
opacity: 0.6;
59+
}
60+
5561
&[data-type="image"] {
5662
width: 48px;
5763
height: 48px;
@@ -101,6 +107,11 @@
101107
border: 1px solid var(--border-weak-base);
102108
padding: 8px 12px;
103109
border-radius: 6px;
110+
transition: opacity 0.3s ease;
111+
112+
&[data-queued] {
113+
opacity: 0.6;
114+
}
104115

105116
[data-highlight="file"] {
106117
color: var(--syntax-property);
@@ -113,6 +124,14 @@
113124
max-width: 100%;
114125
}
115126

127+
[data-slot="user-message-queued-indicator"] {
128+
margin-top: 6px;
129+
margin-right: 2px;
130+
font-size: var(--font-size-small);
131+
color: var(--text-weak);
132+
user-select: none;
133+
}
134+
116135
[data-slot="user-message-copy-wrapper"] {
117136
min-height: 24px;
118137
margin-top: 4px;
@@ -149,6 +168,7 @@
149168
align-items: center;
150169
justify-content: flex-end;
151170
overflow: hidden;
171+
gap: 6px;
152172
}
153173

154174
[data-slot="user-message-meta-tail"] {

packages/ui/src/components/message-part.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ export interface MessageProps {
9292
parts: PartType[]
9393
showAssistantCopyPartID?: string | null
9494
interrupted?: boolean
95+
queued?: boolean
9596
showReasoningSummaries?: boolean
9697
}
9798

@@ -500,6 +501,7 @@ export function Message(props: MessageProps) {
500501
message={userMessage() as UserMessage}
501502
parts={props.parts}
502503
interrupted={props.interrupted}
504+
queued={props.queued}
503505
/>
504506
)}
505507
</Match>
@@ -679,7 +681,12 @@ function ContextToolGroup(props: { parts: ToolPart[]; busy?: boolean }) {
679681
)
680682
}
681683

682-
export function UserMessageDisplay(props: { message: UserMessage; parts: PartType[]; interrupted?: boolean }) {
684+
export function UserMessageDisplay(props: {
685+
message: UserMessage
686+
parts: PartType[]
687+
interrupted?: boolean
688+
queued?: boolean
689+
}) {
683690
const data = useData()
684691
const dialog = useDialog()
685692
const i18n = useI18n()
@@ -759,6 +766,7 @@ export function UserMessageDisplay(props: { message: UserMessage; parts: PartTyp
759766
<div
760767
data-slot="user-message-attachment"
761768
data-type={file.mime.startsWith("image/") ? "image" : "file"}
769+
data-queued={props.queued ? "" : undefined}
762770
onClick={() => {
763771
if (file.mime.startsWith("image/") && file.url) {
764772
openImagePreview(file.url, file.filename)
@@ -787,9 +795,14 @@ export function UserMessageDisplay(props: { message: UserMessage; parts: PartTyp
787795
<Show when={text()}>
788796
<>
789797
<div data-slot="user-message-body">
790-
<div data-slot="user-message-text">
798+
<div data-slot="user-message-text" data-queued={props.queued ? "" : undefined}>
791799
<HighlightedText text={text()} references={inlineFiles()} agents={agents()} />
792800
</div>
801+
<Show when={props.queued}>
802+
<div data-slot="user-message-queued-indicator">
803+
<TextShimmer text={i18n.t("ui.message.queued")} />
804+
</div>
805+
</Show>
793806
</div>
794807
<div data-slot="user-message-copy-wrapper" data-interrupted={props.interrupted ? "" : undefined}>
795808
<Show when={metaHead() || metaTail()}>

packages/ui/src/components/session-turn.tsx

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -192,11 +192,31 @@ export function SessionTurn(
192192
(item): item is AssistantMessage => item.role === "assistant" && typeof item.time.completed !== "number",
193193
)
194194
})
195+
196+
const pendingUser = createMemo(() => {
197+
const item = pending()
198+
if (!item?.parentID) return
199+
const messages = allMessages() ?? emptyMessages
200+
const result = Binary.search(messages, item.parentID, (m) => m.id)
201+
const msg = result.found ? messages[result.index] : messages.find((m) => m.id === item.parentID)
202+
if (!msg || msg.role !== "user") return
203+
return msg
204+
})
205+
195206
const active = createMemo(() => {
196207
const msg = message()
208+
const parent = pendingUser()
209+
if (!msg || !parent) return false
210+
return parent.id === msg.id
211+
})
212+
213+
const queued = createMemo(() => {
214+
const id = message()?.id
215+
if (!id) return false
216+
if (!pendingUser()) return false
197217
const item = pending()
198-
if (!msg || !item) return false
199-
return item.parentID === msg.id
218+
if (!item) return false
219+
return id > item.id
200220
})
201221

202222
const parts = createMemo(() => {
@@ -334,6 +354,7 @@ export function SessionTurn(
334354
)
335355
const showThinking = createMemo(() => {
336356
if (!working() || !!error()) return false
357+
if (queued()) return false
337358
if (status().type === "retry") return false
338359
if (showReasoningSummaries()) return assistantVisible() === 0
339360
if (assistantTailVisible() === "text") return false
@@ -364,7 +385,7 @@ export function SessionTurn(
364385
class={props.classes?.container}
365386
>
366387
<div data-slot="session-turn-message-content" aria-live="off">
367-
<Message message={msg()} parts={parts()} interrupted={interrupted()} />
388+
<Message message={msg()} parts={parts()} interrupted={interrupted()} queued={queued()} />
368389
</div>
369390
<Show when={compaction()}>
370391
{(part) => (

packages/ui/src/i18n/ar.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ export const dict = {
126126
"ui.message.copyResponse": "نسخ الرد",
127127
"ui.message.copied": "تم النسخ!",
128128
"ui.message.interrupted": "تمت المقاطعة",
129+
"ui.message.queued": "في الانتظار",
129130
"ui.message.attachment.alt": "مرفق",
130131

131132
"ui.patch.action.deleted": "محذوف",

packages/ui/src/i18n/br.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ export const dict = {
126126
"ui.message.copyResponse": "Copiar resposta",
127127
"ui.message.copied": "Copiado!",
128128
"ui.message.interrupted": "Interrompido",
129+
"ui.message.queued": "Na fila",
129130
"ui.message.attachment.alt": "anexo",
130131

131132
"ui.patch.action.deleted": "Excluído",

packages/ui/src/i18n/bs.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ export const dict = {
130130
"ui.message.copyResponse": "Kopiraj odgovor",
131131
"ui.message.copied": "Kopirano!",
132132
"ui.message.interrupted": "Prekinuto",
133+
"ui.message.queued": "U redu",
133134
"ui.message.attachment.alt": "prilog",
134135

135136
"ui.patch.action.deleted": "Obrisano",

packages/ui/src/i18n/da.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,7 @@ export const dict = {
125125
"ui.message.copyResponse": "Kopier svar",
126126
"ui.message.copied": "Kopieret!",
127127
"ui.message.interrupted": "Afbrudt",
128+
"ui.message.queued": "I kø",
128129
"ui.message.attachment.alt": "vedhæftning",
129130

130131
"ui.patch.action.deleted": "Slettet",

packages/ui/src/i18n/de.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ export const dict = {
131131
"ui.message.copyResponse": "Antwort kopieren",
132132
"ui.message.copied": "Kopiert!",
133133
"ui.message.interrupted": "Unterbrochen",
134+
"ui.message.queued": "In Warteschlange",
134135
"ui.message.attachment.alt": "Anhang",
135136

136137
"ui.patch.action.deleted": "Gelöscht",

packages/ui/src/i18n/en.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ export const dict: Record<string, string> = {
127127
"ui.message.copyResponse": "Copy response",
128128
"ui.message.copied": "Copied",
129129
"ui.message.interrupted": "Interrupted",
130+
"ui.message.queued": "Queued",
130131
"ui.message.attachment.alt": "attachment",
131132

132133
"ui.patch.action.deleted": "Deleted",

packages/ui/src/i18n/es.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ export const dict = {
126126
"ui.message.copyResponse": "Copiar respuesta",
127127
"ui.message.copied": "¡Copiado!",
128128
"ui.message.interrupted": "Interrumpido",
129+
"ui.message.queued": "En cola",
129130
"ui.message.attachment.alt": "adjunto",
130131

131132
"ui.patch.action.deleted": "Eliminado",

0 commit comments

Comments
 (0)