Skip to content

Commit c82419c

Browse files
authored
Merge pull request #569 from chaitin/260503-chore-create-memory-file
260503 chore create memory file
2 parents 4f971b1 + 5e1e739 commit c82419c

11 files changed

Lines changed: 475 additions & 597 deletions

File tree

frontend/package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@
4848
"react": "^19.2.4",
4949
"react-ace": "^14.0.1",
5050
"react-day-picker": "^9.14.0",
51-
"react-diff-view": "^3.3.3",
5251
"react-dom": "^19.2.4",
5352
"react-markdown": "^10.1.0",
5453
"react-resizable-panels": "^4.9.0",

frontend/pnpm-lock.yaml

Lines changed: 0 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/src/components/common/markdown.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@ const CodeBlock = ({ code, language }: CodeBlockProps) => {
105105
language={language}
106106
PreTag="pre"
107107
wrapLines={true}
108-
codeTagProps={{ style: { wordBreak: "break-all", whiteSpace: "pre-wrap" } }}
108+
customStyle={{ textShadow: "none" }}
109+
codeTagProps={{ style: { wordBreak: "break-all", whiteSpace: "pre-wrap", textShadow: "none" } }}
109110
>
110111
{code}
111112
</SyntaxHighlighter>

frontend/src/components/console/task/chat-inputbox.tsx

Lines changed: 87 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,26 @@ export const TaskChatInputBox = ({ streamStatus, availableCommands, onSend, send
5656
const fileInputRef = useRef<HTMLInputElement>(null)
5757
const dragDepthRef = useRef(0)
5858
const isExecuting = (streamStatus === 'connected' || streamStatus === 'inited')
59+
const wasExecutingRef = useRef(isExecuting)
60+
const restoreSubmittedInputOnIdleRef = useRef(false)
61+
const lastSubmittedInputRef = useRef<{ content: string; uploadedFiles: TaskUploadedFile[] } | null>(null)
5962
const canInput = React.useMemo(() => {
6063
return !sending && !isExecuting && queueSize === 0
6164
}, [sending, isExecuting, queueSize])
6265

66+
React.useEffect(() => {
67+
if (wasExecutingRef.current && !isExecuting && restoreSubmittedInputOnIdleRef.current) {
68+
const lastSubmittedInput = lastSubmittedInputRef.current
69+
if (lastSubmittedInput) {
70+
setContent(lastSubmittedInput.content)
71+
setUploadedFiles(lastSubmittedInput.uploadedFiles)
72+
setPreviewFile(null)
73+
}
74+
restoreSubmittedInputOnIdleRef.current = false
75+
}
76+
wasExecutingRef.current = isExecuting
77+
}, [isExecuting])
78+
6379
const sendCurrentInput = async () => {
6480
if (content.trim() === '') {
6581
return
@@ -77,12 +93,22 @@ export const TaskChatInputBox = ({ streamStatus, availableCommands, onSend, send
7793
return
7894
}
7995

96+
lastSubmittedInputRef.current = {
97+
content,
98+
uploadedFiles,
99+
}
100+
restoreSubmittedInputOnIdleRef.current = false
80101
setContent('')
81102
setUploadedFiles([])
82103
setPreviewFile(null)
83104
setWhiteboardFileIndex(1)
84105
}
85106

107+
const handleCancel = () => {
108+
restoreSubmittedInputOnIdleRef.current = true
109+
onCancel?.()
110+
}
111+
86112
const handleSend = () => {
87113
if (content.trim() === '') {
88114
return
@@ -313,6 +339,19 @@ export const TaskChatInputBox = ({ streamStatus, availableCommands, onSend, send
313339
if (isComposing) {
314340
return
315341
}
342+
if (e.key === 'Enter' && e.ctrlKey) {
343+
e.preventDefault()
344+
const textarea = e.currentTarget
345+
const start = textarea.selectionStart
346+
const end = textarea.selectionEnd
347+
const nextContent = `${content.slice(0, start)}\n${content.slice(end)}`
348+
setContent(nextContent)
349+
requestAnimationFrame(() => {
350+
textarea.selectionStart = start + 1
351+
textarea.selectionEnd = start + 1
352+
})
353+
return
354+
}
316355
if (e.key === 'Enter' && !e.shiftKey) {
317356
e.preventDefault()
318357
handleSend()
@@ -360,7 +399,7 @@ export const TaskChatInputBox = ({ streamStatus, availableCommands, onSend, send
360399
{!isExecuting && (
361400
<InputGroupTextarea
362401
ref={textareaRef}
363-
className="min-h-8 max-h-48 text-sm break-all"
402+
className="min-h-8 max-h-36 resize-none overflow-y-auto text-sm break-all [field-sizing:content]"
364403
placeholder="描述你的需求,Shift+Enter 换行,Enter 发送。"
365404
value={content}
366405
onChange={(e) => setContent(e.target.value)}
@@ -421,57 +460,53 @@ export const TaskChatInputBox = ({ streamStatus, availableCommands, onSend, send
421460
)}
422461
</DropdownMenuContent>
423462
</DropdownMenu>
424-
{!isExecuting && (
425-
<>
426-
{canUploadMoreFiles && (
427-
<Tooltip>
428-
<TooltipTrigger asChild>
429-
<Button
430-
type="button"
431-
variant="outline"
432-
size="icon-sm"
433-
className="rounded-full"
434-
disabled={controlsDisabled}
435-
aria-label="上传附件"
436-
onClick={handleSelectFile}
437-
>
438-
<IconUpload />
439-
</Button>
440-
</TooltipTrigger>
441-
<TooltipContent>上传附件</TooltipContent>
442-
</Tooltip>
443-
)}
444-
<Tooltip>
445-
<TooltipTrigger asChild>
446-
<Button
447-
type="button"
448-
variant="outline"
449-
size="icon-sm"
450-
className="rounded-full"
451-
disabled={controlsDisabled}
452-
aria-label="画板"
453-
onClick={() => setWhiteboardDialogOpen(true)}
454-
>
455-
<IconPalette />
456-
</Button>
457-
</TooltipTrigger>
458-
<TooltipContent>画板</TooltipContent>
459-
</Tooltip>
460-
{uploadedFiles.map((uploadedFile) => (
461-
<TaskUploadedFileItem
462-
key={uploadedFile.accessUrl}
463-
file={uploadedFile}
464-
onPreview={() => setPreviewFile(uploadedFile)}
465-
onRemove={() => {
466-
if (previewFile?.accessUrl === uploadedFile.accessUrl) {
467-
setPreviewFile(null)
468-
}
469-
setUploadedFiles((prev) => prev.filter((file) => file.accessUrl !== uploadedFile.accessUrl))
470-
}}
471-
/>
472-
))}
473-
</>
463+
{canUploadMoreFiles && (
464+
<Tooltip>
465+
<TooltipTrigger asChild>
466+
<Button
467+
type="button"
468+
variant="outline"
469+
size="icon-sm"
470+
className="rounded-full"
471+
disabled={controlsDisabled}
472+
aria-label="上传附件"
473+
onClick={handleSelectFile}
474+
>
475+
<IconUpload />
476+
</Button>
477+
</TooltipTrigger>
478+
<TooltipContent>上传附件</TooltipContent>
479+
</Tooltip>
474480
)}
481+
<Tooltip>
482+
<TooltipTrigger asChild>
483+
<Button
484+
type="button"
485+
variant="outline"
486+
size="icon-sm"
487+
className="rounded-full"
488+
disabled={controlsDisabled}
489+
aria-label="画板"
490+
onClick={() => setWhiteboardDialogOpen(true)}
491+
>
492+
<IconPalette />
493+
</Button>
494+
</TooltipTrigger>
495+
<TooltipContent>画板</TooltipContent>
496+
</Tooltip>
497+
{uploadedFiles.map((uploadedFile) => (
498+
<TaskUploadedFileItem
499+
key={uploadedFile.accessUrl}
500+
file={uploadedFile}
501+
onPreview={() => setPreviewFile(uploadedFile)}
502+
onRemove={() => {
503+
if (previewFile?.accessUrl === uploadedFile.accessUrl) {
504+
setPreviewFile(null)
505+
}
506+
setUploadedFiles((prev) => prev.filter((file) => file.accessUrl !== uploadedFile.accessUrl))
507+
}}
508+
/>
509+
))}
475510
</div>
476511
<div className="flex flex-row gap-2 items-center min-w-0">
477512
{isExecuting && (
@@ -490,7 +525,7 @@ export const TaskChatInputBox = ({ streamStatus, availableCommands, onSend, send
490525
className={cn("flex flex-row gap-2 items-center", isExecuting && "rounded-full")}
491526
variant={isExecuting ? "destructive" : "default"}
492527
size={isExecuting ? "icon-sm" : "sm"}
493-
onClick={isExecuting ? onCancel : handleSend}
528+
onClick={isExecuting ? handleCancel : handleSend}
494529
disabled={isExecuting ? !onCancel : !canSend || inputDisabled}
495530
>
496531
{isExecuting ? <IconPlayerStopFilled /> : <IconSend />}

0 commit comments

Comments
 (0)