mirror of
https://github.com/temetro/temetro.git
synced 2026-09-04 06:45:26 +00:00
frontend: fix file attach dropping the picked file (live FileList race)
The file pickers read event.target.files but reset event.target.value = "" before the file was actually used: in the AI composer the value reset ran before React's deferred setState updater read the (now-empty) live FileList, so no chip appeared; in Messages the reset ran before the length check, so it returned early. Snapshot the files into a plain array synchronously, before the reset. This is why attaching seemed to fail (no badge) — especially while typing. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -85,12 +85,17 @@ export function ChatInput({
|
|||||||
|
|
||||||
const handleFilesSelected = useCallback(
|
const handleFilesSelected = useCallback(
|
||||||
(event: ChangeEvent<HTMLInputElement>) => {
|
(event: ChangeEvent<HTMLInputElement>) => {
|
||||||
const selected = event.target.files;
|
// Copy the files out NOW: `event.target.files` is a live FileList, and the
|
||||||
if (selected && selected.length > 0) {
|
// `event.target.value = ""` reset below empties it. React runs the
|
||||||
setFiles((prev) => [...prev, ...Array.from(selected)]);
|
// functional setState updater during a later render, so reading the
|
||||||
}
|
// FileList inside the updater would see it already cleared (no file added,
|
||||||
|
// no chip). Snapshot to a plain array first.
|
||||||
|
const picked = Array.from(event.target.files ?? []);
|
||||||
// Reset so picking the same file again still fires onChange.
|
// Reset so picking the same file again still fires onChange.
|
||||||
event.target.value = "";
|
event.target.value = "";
|
||||||
|
if (picked.length > 0) {
|
||||||
|
setFiles((prev) => [...prev, ...picked]);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[]
|
[]
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -283,12 +283,15 @@ export function MessagesView() {
|
|||||||
|
|
||||||
// Open the file picker; on select, upload each and stage it.
|
// Open the file picker; on select, upload each and stage it.
|
||||||
const onPickFiles = async (event: ChangeEvent<HTMLInputElement>) => {
|
const onPickFiles = async (event: ChangeEvent<HTMLInputElement>) => {
|
||||||
const files = event.target.files;
|
// Snapshot before resetting: `event.target.files` is a live FileList that
|
||||||
|
// `event.target.value = ""` empties, so reading it afterwards (or in a later
|
||||||
|
// tick) yields nothing.
|
||||||
|
const picked = Array.from(event.target.files ?? []);
|
||||||
event.target.value = "";
|
event.target.value = "";
|
||||||
if (!files?.length) return;
|
if (picked.length === 0) return;
|
||||||
setUploading(true);
|
setUploading(true);
|
||||||
try {
|
try {
|
||||||
for (const file of Array.from(files)) {
|
for (const file of picked) {
|
||||||
if (file.size > MAX_ATTACHMENT_BYTES) {
|
if (file.size > MAX_ATTACHMENT_BYTES) {
|
||||||
notify.error(
|
notify.error(
|
||||||
t("messages.attach.tooLargeTitle"),
|
t("messages.attach.tooLargeTitle"),
|
||||||
|
|||||||
Reference in New Issue
Block a user