mirror of
https://github.com/arc53/DocsGPT.git
synced 2025-11-29 08:33:20 +00:00
chore(chat): remove image previews, keep drag-to-reorder
This commit is contained in:
@@ -95,15 +95,9 @@ export default function MessageInput({
|
|||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
const uniqueId = crypto.randomUUID();
|
const uniqueId = crypto.randomUUID();
|
||||||
|
|
||||||
// create preview for images
|
|
||||||
const isImage = file.type.startsWith('image/');
|
|
||||||
const previewUrl = isImage ? URL.createObjectURL(file) : undefined;
|
|
||||||
|
|
||||||
const newAttachment = {
|
const newAttachment = {
|
||||||
id: uniqueId,
|
id: uniqueId,
|
||||||
fileName: file.name,
|
fileName: file.name,
|
||||||
previewUrl,
|
|
||||||
mimeType: file.type,
|
|
||||||
progress: 0,
|
progress: 0,
|
||||||
status: 'uploading' as const,
|
status: 'uploading' as const,
|
||||||
taskId: '',
|
taskId: '',
|
||||||
@@ -145,7 +139,6 @@ export default function MessageInput({
|
|||||||
updates: { status: 'failed' },
|
updates: { status: 'failed' },
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
if (previewUrl) URL.revokeObjectURL(previewUrl);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -156,7 +149,6 @@ export default function MessageInput({
|
|||||||
updates: { status: 'failed' },
|
updates: { status: 'failed' },
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
if (previewUrl) URL.revokeObjectURL(previewUrl);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.open('POST', `${apiHost}${endpoints.USER.STORE_ATTACHMENT}`);
|
xhr.open('POST', `${apiHost}${endpoints.USER.STORE_ATTACHMENT}`);
|
||||||
@@ -277,15 +269,7 @@ export default function MessageInput({
|
|||||||
// Drag state for reordering
|
// Drag state for reordering
|
||||||
const [draggingId, setDraggingId] = useState<string | null>(null);
|
const [draggingId, setDraggingId] = useState<string | null>(null);
|
||||||
|
|
||||||
// Revoke object URLs on unmount to avoid memory leaks
|
// no preview object URLs to revoke (preview removed per reviewer request)
|
||||||
useEffect(() => {
|
|
||||||
return () => {
|
|
||||||
attachments.forEach((att) => {
|
|
||||||
if (att.previewUrl) URL.revokeObjectURL(att.previewUrl);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const findIndexById = (id: string) => attachments.findIndex((a) => a.id === id);
|
const findIndexById = (id: string) => attachments.findIndex((a) => a.id === id);
|
||||||
|
|
||||||
@@ -322,8 +306,6 @@ export default function MessageInput({
|
|||||||
<div className="border-dark-gray bg-lotion dark:border-grey relative flex w-full flex-col rounded-[23px] border dark:bg-transparent">
|
<div className="border-dark-gray bg-lotion dark:border-grey relative flex w-full flex-col rounded-[23px] border dark:bg-transparent">
|
||||||
<div className="flex flex-wrap gap-1.5 px-2 py-2 sm:gap-2 sm:px-3">
|
<div className="flex flex-wrap gap-1.5 px-2 py-2 sm:gap-2 sm:px-3">
|
||||||
{attachments.map((attachment) => {
|
{attachments.map((attachment) => {
|
||||||
const isImage = attachment.mimeType?.startsWith?.('image/');
|
|
||||||
const index = attachments.findIndex((a) => a.id === attachment.id);
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={attachment.id}
|
key={attachment.id}
|
||||||
@@ -336,61 +318,51 @@ export default function MessageInput({
|
|||||||
} ${draggingId === attachment.id ? 'opacity-60 ring-2 ring-dashed ring-purple-200' : ''}`}
|
} ${draggingId === attachment.id ? 'opacity-60 ring-2 ring-dashed ring-purple-200' : ''}`}
|
||||||
title={attachment.fileName}
|
title={attachment.fileName}
|
||||||
>
|
>
|
||||||
<div className="mr-2 flex items-center justify-center">
|
<div className="bg-purple-30 mr-2 flex h-8 w-8 items-center justify-center rounded-md p-1">
|
||||||
{isImage && attachment.previewUrl ? (
|
{attachment.status === 'completed' && (
|
||||||
<img
|
<img
|
||||||
src={attachment.previewUrl}
|
src={DocumentationDark}
|
||||||
alt={attachment.fileName}
|
alt="Attachment"
|
||||||
className="h-8 w-8 rounded-md object-cover"
|
className="h-[15px] w-[15px] object-fill"
|
||||||
/>
|
/>
|
||||||
) : (
|
)}
|
||||||
<div className="bg-purple-30 mr-2 flex h-8 w-8 items-center justify-center rounded-md p-1">
|
|
||||||
{attachment.status === 'completed' && (
|
|
||||||
<img
|
|
||||||
src={DocumentationDark}
|
|
||||||
alt="Attachment"
|
|
||||||
className="h-[15px] w-[15px] object-fill"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{attachment.status === 'failed' && (
|
{attachment.status === 'failed' && (
|
||||||
<img
|
<img
|
||||||
src={AlertIcon}
|
src={AlertIcon}
|
||||||
alt="Failed"
|
alt="Failed"
|
||||||
className="h-[15px] w-[15px] object-fill"
|
className="h-[15px] w-[15px] object-fill"
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{(attachment.status === 'uploading' ||
|
{(attachment.status === 'uploading' ||
|
||||||
attachment.status === 'processing') && (
|
attachment.status === 'processing') && (
|
||||||
<div className="flex h-[15px] w-[15px] items-center justify-center">
|
<div className="flex h-[15px] w-[15px] items-center justify-center">
|
||||||
<svg className="h-[15px] w-[15px]" viewBox="0 0 24 24">
|
<svg className="h-[15px] w-[15px]" viewBox="0 0 24 24">
|
||||||
<circle
|
<circle
|
||||||
className="opacity-0"
|
className="opacity-0"
|
||||||
cx="12"
|
cx="12"
|
||||||
cy="12"
|
cy="12"
|
||||||
r="10"
|
r="10"
|
||||||
stroke="transparent"
|
stroke="transparent"
|
||||||
strokeWidth="4"
|
strokeWidth="4"
|
||||||
fill="none"
|
fill="none"
|
||||||
/>
|
/>
|
||||||
<circle
|
<circle
|
||||||
className="text-[#ECECF1]"
|
className="text-[#ECECF1]"
|
||||||
cx="12"
|
cx="12"
|
||||||
cy="12"
|
cy="12"
|
||||||
r="10"
|
r="10"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
strokeWidth="4"
|
strokeWidth="4"
|
||||||
fill="none"
|
fill="none"
|
||||||
strokeDasharray="62.83"
|
strokeDasharray="62.83"
|
||||||
strokeDashoffset={
|
strokeDashoffset={
|
||||||
62.83 * (1 - attachment.progress / 100)
|
62.83 * (1 - attachment.progress / 100)
|
||||||
}
|
}
|
||||||
transform="rotate(-90 12 12)"
|
transform="rotate(-90 12 12)"
|
||||||
/>
|
/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -402,7 +374,6 @@ export default function MessageInput({
|
|||||||
<button
|
<button
|
||||||
className="ml-1.5 flex items-center justify-center rounded-full p-1"
|
className="ml-1.5 flex items-center justify-center rounded-full p-1"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (attachment.previewUrl) URL.revokeObjectURL(attachment.previewUrl);
|
|
||||||
dispatch(removeAttachment(attachment.id));
|
dispatch(removeAttachment(attachment.id));
|
||||||
}}
|
}}
|
||||||
aria-label={t('conversation.attachments.remove')}
|
aria-label={t('conversation.attachments.remove')}
|
||||||
|
|||||||
@@ -4,10 +4,6 @@ import { RootState } from '../store';
|
|||||||
export interface Attachment {
|
export interface Attachment {
|
||||||
id: string; // Unique identifier for the attachment (required for state management)
|
id: string; // Unique identifier for the attachment (required for state management)
|
||||||
fileName: string;
|
fileName: string;
|
||||||
// Optional preview URL for image thumbnails (object URL)
|
|
||||||
previewUrl?: string;
|
|
||||||
// MIME type of the original file
|
|
||||||
mimeType?: string;
|
|
||||||
progress: number;
|
progress: number;
|
||||||
status: 'uploading' | 'processing' | 'completed' | 'failed';
|
status: 'uploading' | 'processing' | 'completed' | 'failed';
|
||||||
taskId: string; // Server-assigned task ID (used for API calls)
|
taskId: string; // Server-assigned task ID (used for API calls)
|
||||||
|
|||||||
Reference in New Issue
Block a user