mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-06-12 08:51:53 +00:00
fix(desktop): show a staging spinner in the edit composer while OS drops upload
The message-edit composer staged dropped OS files asynchronously with no visible state, so confirming the edit before the upload resolved could send the message without the gateway-side ref (helix4u review note on #43109). Add a staging flag: while uploadOsDropRefs is in flight, show a small spinner pill in the bubble and block submit (disabled send button + submitEdit guard) so the edit can't outrace the ref insertion. New `attachingFile` i18n string across en/zh/zh-hant/ja.
This commit is contained in:
parent
891c9a6823
commit
b021497bc8
6 changed files with 32 additions and 11 deletions
|
|
@ -971,6 +971,10 @@ const UserEditComposer: FC<UserEditComposerProps> = ({ cwd, gateway, sessionId }
|
|||
const [triggerPlacement, setTriggerPlacement] = useState<'bottom' | 'top'>('top')
|
||||
const [focusRequestId, setFocusRequestId] = useState(0)
|
||||
const [submitting, setSubmitting] = useState(false)
|
||||
// True while OS-drop files are being staged/uploaded into the session. Blocks
|
||||
// submit and shows a spinner so confirming the edit can't race the async
|
||||
// upload and drop the gateway-side ref before it lands in the draft.
|
||||
const [staging, setStaging] = useState(false)
|
||||
const expanded = draft.includes('\n')
|
||||
const canSubmit = draft.trim().length > 0
|
||||
const at = useAtCompletions({ cwd, gateway, sessionId })
|
||||
|
|
@ -1324,11 +1328,14 @@ const UserEditComposer: FC<UserEditComposerProps> = ({ cwd, gateway, sessionId }
|
|||
}
|
||||
|
||||
if (osDrops.length) {
|
||||
void uploadOsDropRefs(osDrops).then(refs => {
|
||||
if (insertRefStrings(refs)) {
|
||||
triggerHaptic('selection')
|
||||
}
|
||||
})
|
||||
setStaging(true)
|
||||
void uploadOsDropRefs(osDrops)
|
||||
.then(refs => {
|
||||
if (insertRefStrings(refs)) {
|
||||
triggerHaptic('selection')
|
||||
}
|
||||
})
|
||||
.finally(() => setStaging(false))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1360,7 +1367,7 @@ const UserEditComposer: FC<UserEditComposerProps> = ({ cwd, gateway, sessionId }
|
|||
const submitEdit = (editor: HTMLDivElement) => {
|
||||
const nextDraft = syncDraftFromEditor(editor)
|
||||
|
||||
if (submitting || !nextDraft.trim()) {
|
||||
if (submitting || staging || !nextDraft.trim()) {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -1517,10 +1524,19 @@ const UserEditComposer: FC<UserEditComposerProps> = ({ cwd, gateway, sessionId }
|
|||
suppressContentEditableWarning
|
||||
/>
|
||||
<ComposerPrimitive.Input className="sr-only" tabIndex={-1} unstable_focusOnScrollToBottom={false} />
|
||||
{staging && (
|
||||
<span
|
||||
className="pointer-events-none absolute bottom-2 left-2 inline-flex items-center gap-1 rounded-full bg-background/80 px-1.5 py-0.5 text-[0.62rem] text-muted-foreground backdrop-blur-[1px]"
|
||||
data-slot="aui_edit-staging"
|
||||
>
|
||||
<Loader2Icon className="size-3 animate-spin" />
|
||||
{copy.attachingFile}
|
||||
</span>
|
||||
)}
|
||||
<button
|
||||
aria-label={copy.sendEdited}
|
||||
className={cn('absolute right-2 bottom-2 size-5', USER_ACTION_ICON_BUTTON_CLASS)}
|
||||
disabled={!canSubmit || submitting}
|
||||
disabled={!canSubmit || submitting || staging}
|
||||
onClick={() => {
|
||||
const editor = editorRef.current
|
||||
|
||||
|
|
|
|||
|
|
@ -1622,7 +1622,8 @@ export const en: Translations = {
|
|||
restoreCheckpoint: 'Restore checkpoint',
|
||||
restoreNext: 'Restore next checkpoint',
|
||||
goForward: 'Go forward',
|
||||
sendEdited: 'Send edited message'
|
||||
sendEdited: 'Send edited message',
|
||||
attachingFile: 'Attaching…'
|
||||
},
|
||||
approval: {
|
||||
gatewayDisconnected: 'Hermes gateway is not connected',
|
||||
|
|
|
|||
|
|
@ -1766,7 +1766,8 @@ export const ja = defineLocale({
|
|||
restoreCheckpoint: 'チェックポイントを復元',
|
||||
restoreNext: '次のチェックポイントに戻す',
|
||||
goForward: '進む',
|
||||
sendEdited: '編集済みメッセージを送信'
|
||||
sendEdited: '編集済みメッセージを送信',
|
||||
attachingFile: '添付中…'
|
||||
},
|
||||
approval: {
|
||||
gatewayDisconnected: 'Hermes ゲートウェイが接続されていません',
|
||||
|
|
|
|||
|
|
@ -1293,6 +1293,7 @@ export interface Translations {
|
|||
restoreNext: string
|
||||
goForward: string
|
||||
sendEdited: string
|
||||
attachingFile: string
|
||||
}
|
||||
approval: {
|
||||
gatewayDisconnected: string
|
||||
|
|
|
|||
|
|
@ -1727,7 +1727,8 @@ export const zhHant = defineLocale({
|
|||
restoreCheckpoint: '還原檢查點',
|
||||
restoreNext: '還原至下一個檢查點',
|
||||
goForward: '前進',
|
||||
sendEdited: '傳送編輯後的訊息'
|
||||
sendEdited: '傳送編輯後的訊息',
|
||||
attachingFile: '正在附加…'
|
||||
},
|
||||
approval: {
|
||||
gatewayDisconnected: 'Hermes 閘道未連線',
|
||||
|
|
|
|||
|
|
@ -1802,7 +1802,8 @@ export const zh: Translations = {
|
|||
restoreCheckpoint: '恢复检查点',
|
||||
restoreNext: '恢复下一个检查点',
|
||||
goForward: '前进',
|
||||
sendEdited: '发送编辑后的消息'
|
||||
sendEdited: '发送编辑后的消息',
|
||||
attachingFile: '正在附加…'
|
||||
},
|
||||
approval: {
|
||||
gatewayDisconnected: 'Hermes 网关未连接',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue