Repository navigation
fix(web): attach a picture pasted into the message box - #152
Conversation
The message box took no files from the clipboard, so a pasted screenshot did nothing. Pasted files attach like chosen ones; a clipboard picture, which always arrives as image.png, gets a stamped name so two pastes are not refused as duplicates.
|
Triage: Pass No changes needed from you. A maintainer will review this pull request. Approve held: code review has 2 findings at P2 or above open on this head. |
| onPaste={(event) => { | ||
| const files = pastedFiles(event.clipboardData); | ||
| if (files.length === 0) return; | ||
| event.preventDefault(); | ||
| addFiles(files); | ||
| }} |
There was a problem hiding this comment.
P2 · Paste attaches files while attaching is turned off
When the provider is missing or no MIME types are allowed, the drop zone is disabled and the paperclip is hidden. The new paste handler checks neither condition, so pasting still attaches files.
Paste a screenshot when providerMissing is true or limits.mimeTypes is empty.
Resolve this comment. Triage will not finish while it is open.
| if (files.length === 0) return; | ||
| event.preventDefault(); | ||
| addFiles(files); |
There was a problem hiding this comment.
P2 · Paste is silently swallowed while limits are still loading
The handler calls preventDefault() before addFiles. addFiles returns early when limits is undefined, so the paste is cancelled and nothing appears: no attachment and no message. This is the same silent failure the PR is meant to fix.
Paste an image before the attachment limits have loaded.
Resolve this comment. Triage will not finish while it is open.
| if (files.length === 0) return; | ||
| event.preventDefault(); |
There was a problem hiding this comment.
P2 · Mixed text-and-image clipboard drops the text
Whenever the clipboard carries any file, preventDefault() runs, even if it also carries text. Office apps and some browsers put a picture next to the text when you copy, so a paste that should insert text attaches an image and loses the text.
Copy cells from Excel or text from Word, which also puts an image/png on the clipboard, then paste into the message box.
Resolve this comment. Triage will not finish while it is open.
| const stamp = at | ||
| .toISOString() | ||
| .slice(0, 19) | ||
| .replace("T", "-") | ||
| .replaceAll(":", "-"); |
There was a problem hiding this comment.
P2 · Pasted names are only unique to the second, so close pastes collide as duplicates
The name is built from the timestamp cut down to whole seconds. Two pastes of a clipboard picture within the same second get the same pasted-…png name. Within one paste, a later file is pushed forward by index * 1000 ms, so its name can also match the first file of a paste made a second later. The attachment list then rejects the second file as already attached, which is the bug this PR set out to fix.
Press Ctrl+V twice quickly with a screenshot on the clipboard, or paste two images and paste again a second later.
Resolve this comment. Triage will not finish while it is open.
…astes, and never collides names The paste handler attached files while attaching was off or its limits were still loading, cancelled the paste either way, and took a picture an office app copies beside text in place of the text. Pasted pictures were named to the second, so two quick pastes collided. Paste follows the drop zone's condition, a paste with text is the browser's, and each pasted picture gets a counted name.
| const files = pastedFiles(event.clipboardData); | ||
| if (files.length === 0) return; |
There was a problem hiding this comment.
P2 · A copied file that also puts text on the clipboard is not attached
The handler leaves the paste alone whenever pastedFiles returns nothing. pastedFiles (in pasted-files.ts, not part of this diff) returns nothing whenever the clipboard carries any non-blank text/plain. When you copy a file in a file manager, the browser usually also puts the file name on the clipboard as text/plain. So pasting a real file inserts its name instead of attaching it, which goes against the PR's goal of attaching any readable file.
Copy a PDF or image file in macOS Finder and paste it into the message box in Chrome.
Resolve this comment. Triage will not finish while it is open.
| ): File[] { | ||
| if (clipboard === null) return []; | ||
| if (clipboard.getData("text/plain").trim() !== "") return []; | ||
| return Array.from(clipboard.files, (file) => { |
There was a problem hiding this comment.
P2 · Any text on the clipboard throws away the pasted files
If the clipboard has any non-blank text/plain, the code skips every file. Copying a file in a file manager (Finder, Explorer) or using "Copy Image" in some browsers puts the file name or image URL on the clipboard as text/plain next to the file. The file is then silently dropped: the paste inserts a name or URL instead of attaching anything, which is the silent failure #151 is meant to fix.
Copy report.pdf in macOS Finder and paste it into the message box: the clipboard holds the file plus text/plain "report.pdf".
Resolve this comment. Triage will not finish while it is open.
| .toISOString() | ||
| .slice(0, 19) | ||
| .replace("T", "-") | ||
| .replaceAll(":", "-"); | ||
| const extension = EXTENSIONS[type]; |
There was a problem hiding this comment.
P3 · Name stamp uses UTC instead of the person's local time
toISOString() always gives UTC. A stamp meant to show "the time for the person" is wrong by their UTC offset; outside UTC it can even show a different date from the one they pasted on.
Paste a screenshot from a browser set to any time zone other than UTC.
Resolve this comment. Triage will not finish while it is open.
Closes #151
What
A picture (or any readable file) pasted into the message box attaches, the same as one chosen with the paperclip or dropped.
Why
The box took no files from the clipboard, so a pasted screenshot did nothing and said nothing. Details in #151.
Changes
apps/web/src/pages/workspace/pasted-files.ts:pastedFilesreads the clipboard's files; a clipboard picture, which browsers nameimage.pngevery time, gets a stamped name such aspasted-2026-11-04-10-52-07.png, so a second paste is not refused as a duplicate. A named file keeps its name.apps/web/src/pages/workspace/index.tsx: the textarea's paste handler hands those files to the sameaddFilesthe picker and the drop zone use, with its limits and refusals; a text paste is left to the browser.pasted-files.test.tscovers the naming and the empty cases.