fix: show claw image upload progress
This commit is contained in:
parent
36d575b825
commit
d37cb6cffc
@ -1116,6 +1116,14 @@ type CanvasTypewriterTextProps = {
|
||||
onComplete?: (typingKey: string) => void;
|
||||
};
|
||||
|
||||
type CanvasComposerUploadProgress = {
|
||||
title: string;
|
||||
message: string;
|
||||
current: number;
|
||||
total: number;
|
||||
fileName?: string;
|
||||
};
|
||||
|
||||
type MarkdownTableBlockRange = {
|
||||
start: number;
|
||||
end: number;
|
||||
@ -1353,6 +1361,60 @@ function CanvasAssistantTypingPlaceholder({ hint }: { hint?: string | null }) {
|
||||
);
|
||||
}
|
||||
|
||||
function CanvasComposerUploadProgressDialog({
|
||||
progress,
|
||||
}: {
|
||||
progress: CanvasComposerUploadProgress | null;
|
||||
}) {
|
||||
if (!progress) return null;
|
||||
|
||||
const percent =
|
||||
progress.total > 1
|
||||
? Math.max(
|
||||
8,
|
||||
Math.min(100, Math.round((progress.current / progress.total) * 100))
|
||||
)
|
||||
: 100;
|
||||
const isSingleFile = progress.total <= 1;
|
||||
|
||||
return createPortal(
|
||||
<div className="fixed inset-0 z-[1000] flex items-center justify-center bg-black/35 px-4 backdrop-blur-[2px]">
|
||||
<div className="w-full max-w-[360px] rounded-[22px] border border-white/12 bg-[#111215]/95 p-5 text-white shadow-2xl">
|
||||
<div className="flex items-start gap-3">
|
||||
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-white/10 text-[#e0ff3a]">
|
||||
<Loader2 className="h-5 w-5 animate-spin" />
|
||||
</div>
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="text-[15px] font-semibold leading-5">
|
||||
{progress.title}
|
||||
</div>
|
||||
{progress.fileName ? (
|
||||
<div className="mt-1 truncate text-[12px] leading-5 text-zinc-400">
|
||||
{progress.fileName}
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-4 h-1.5 overflow-hidden rounded-full bg-white/10">
|
||||
<div
|
||||
className={cn(
|
||||
"h-full rounded-full bg-[#e0ff3a] transition-all duration-300",
|
||||
isSingleFile && "animate-pulse"
|
||||
)}
|
||||
style={{ width: `${percent}%` }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-3 text-[12px] leading-5 text-zinc-400">
|
||||
{progress.message}
|
||||
</div>
|
||||
</div>
|
||||
</div>,
|
||||
document.body
|
||||
);
|
||||
}
|
||||
|
||||
function normalizeCanvasAgentText(value: string): string {
|
||||
return String(value || "")
|
||||
.replace(/\r\n/g, "\n")
|
||||
@ -1941,6 +2003,8 @@ export function CanvasChatPanel({
|
||||
} | null>(null);
|
||||
const [downloadProgress, setDownloadProgress] =
|
||||
useState<CanvasImageDownloadProgress | null>(null);
|
||||
const [composerUploadProgress, setComposerUploadProgress] =
|
||||
useState<CanvasComposerUploadProgress | null>(null);
|
||||
const [downloadingOriginalUrl, setDownloadingOriginalUrl] = useState("");
|
||||
const [addingClawdImageUrl, setAddingClawdImageUrl] = useState("");
|
||||
const downloadAbortControllerRef = useRef<AbortController | null>(null);
|
||||
@ -10641,30 +10705,45 @@ export function CanvasChatPanel({
|
||||
|
||||
if (isClawdMode) {
|
||||
let handledCount = 0;
|
||||
for (const file of files) {
|
||||
const uploaded = await uploadImageFileForComposerAttachment(file);
|
||||
if (!uploaded) continue;
|
||||
try {
|
||||
for (const [index, file] of files.entries()) {
|
||||
setComposerUploadProgress({
|
||||
title:
|
||||
files.length === 1
|
||||
? "正在上传图片"
|
||||
: `正在上传 ${files.length} 张图片`,
|
||||
message: `正在上传第 ${index + 1}/${files.length} 张,图片较大时可能需要一点时间。`,
|
||||
current: index + 1,
|
||||
total: files.length,
|
||||
fileName: file.name,
|
||||
});
|
||||
|
||||
handledCount += 1;
|
||||
setAttachments((prev) => {
|
||||
const newIndex = prev.length;
|
||||
setTimeout(() => {
|
||||
insertImageTagInEditor(uploaded.imageUrl, uploaded.name, newIndex);
|
||||
(textareaRef.current as HTMLDivElement | null)?.focus();
|
||||
}, 0);
|
||||
const uploaded = await uploadImageFileForComposerAttachment(file);
|
||||
if (!uploaded) continue;
|
||||
|
||||
return [
|
||||
...prev,
|
||||
{
|
||||
url: uploaded.imageUrl,
|
||||
name: uploaded.name,
|
||||
contentType: uploaded.contentType,
|
||||
assetId: uploaded.assetId,
|
||||
width: uploaded.width,
|
||||
height: uploaded.height,
|
||||
},
|
||||
];
|
||||
});
|
||||
handledCount += 1;
|
||||
setAttachments((prev) => {
|
||||
const newIndex = prev.length;
|
||||
setTimeout(() => {
|
||||
insertImageTagInEditor(uploaded.imageUrl, uploaded.name, newIndex);
|
||||
(textareaRef.current as HTMLDivElement | null)?.focus();
|
||||
}, 0);
|
||||
|
||||
return [
|
||||
...prev,
|
||||
{
|
||||
url: uploaded.imageUrl,
|
||||
name: uploaded.name,
|
||||
contentType: uploaded.contentType,
|
||||
assetId: uploaded.assetId,
|
||||
width: uploaded.width,
|
||||
height: uploaded.height,
|
||||
},
|
||||
];
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
setComposerUploadProgress(null);
|
||||
}
|
||||
|
||||
if (handledCount > 0) {
|
||||
@ -10887,30 +10966,47 @@ export function CanvasChatPanel({
|
||||
}
|
||||
|
||||
let handledImageCount = 0;
|
||||
for (const file of imageFiles) {
|
||||
const uploaded = await uploadImageFileForComposerAttachment(file);
|
||||
if (!uploaded) continue;
|
||||
if (imageFiles.length > 0) {
|
||||
try {
|
||||
for (const [index, file] of imageFiles.entries()) {
|
||||
setComposerUploadProgress({
|
||||
title:
|
||||
imageFiles.length === 1
|
||||
? "正在上传图片"
|
||||
: `正在上传 ${imageFiles.length} 张图片`,
|
||||
message: `正在上传第 ${index + 1}/${imageFiles.length} 张,图片较大时可能需要一点时间。`,
|
||||
current: index + 1,
|
||||
total: imageFiles.length,
|
||||
fileName: file.name,
|
||||
});
|
||||
|
||||
handledImageCount += 1;
|
||||
setAttachments((prev) => {
|
||||
const newIndex = prev.length;
|
||||
setTimeout(() => {
|
||||
insertImageTagInEditor(uploaded.imageUrl, uploaded.name, newIndex);
|
||||
(textareaRef.current as HTMLDivElement | null)?.focus();
|
||||
}, 0);
|
||||
const uploaded = await uploadImageFileForComposerAttachment(file);
|
||||
if (!uploaded) continue;
|
||||
|
||||
return [
|
||||
...prev,
|
||||
{
|
||||
url: uploaded.imageUrl,
|
||||
name: uploaded.name,
|
||||
contentType: uploaded.contentType,
|
||||
assetId: uploaded.assetId,
|
||||
width: uploaded.width,
|
||||
height: uploaded.height,
|
||||
},
|
||||
];
|
||||
});
|
||||
handledImageCount += 1;
|
||||
setAttachments((prev) => {
|
||||
const newIndex = prev.length;
|
||||
setTimeout(() => {
|
||||
insertImageTagInEditor(uploaded.imageUrl, uploaded.name, newIndex);
|
||||
(textareaRef.current as HTMLDivElement | null)?.focus();
|
||||
}, 0);
|
||||
|
||||
return [
|
||||
...prev,
|
||||
{
|
||||
url: uploaded.imageUrl,
|
||||
name: uploaded.name,
|
||||
contentType: uploaded.contentType,
|
||||
assetId: uploaded.assetId,
|
||||
width: uploaded.width,
|
||||
height: uploaded.height,
|
||||
},
|
||||
];
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
setComposerUploadProgress(null);
|
||||
}
|
||||
}
|
||||
|
||||
if (handledImageCount > 0) {
|
||||
@ -11200,7 +11296,9 @@ export function CanvasChatPanel({
|
||||
);
|
||||
|
||||
const isLoading = status === 'streaming' || status === 'submitted';
|
||||
const isSubmitting = isLoading || isDetailGenerating || isClawdSubmitting;
|
||||
const isComposerUploading = Boolean(composerUploadProgress);
|
||||
const isSubmitting =
|
||||
isLoading || isDetailGenerating || isClawdSubmitting || isComposerUploading;
|
||||
const hasInputOrAttachments = Boolean(
|
||||
input.trim() || attachments.length > 0 || (!isDetailGenerationMode && selectedSkillTag)
|
||||
);
|
||||
@ -12851,6 +12949,7 @@ export function CanvasChatPanel({
|
||||
onCancel={handleCancelOriginalImageDownload}
|
||||
progress={downloadProgress}
|
||||
/>
|
||||
<CanvasComposerUploadProgressDialog progress={composerUploadProgress} />
|
||||
|
||||
{!isWorkspacePresentation && shouldShowCanvasBanner ? (
|
||||
<div className="px-[10px] pb-0">
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user