Attach images pasted into the composer, comments and chat #171

Merged
retoor merged 1 commits from blindxfish/devplacepy:PasteImage into master 2026-08-17 22:44:46 +02:00
Contributor

Pressing Ctrl+V with a screenshot on the clipboard now attaches it immediately, instead of requiring a trip through the file picker.

How

The clipboard reader lives in dp-upload behind a new opt-in paste boolean attribute. With it set, the component binds one paste listener on its closest("form") and routes the clipboard's image files through the same handleFiles path as the picker and the drop target - so validation, size/count limits, the terms gate and the hidden attachment_uids field are all shared, and no page controller grows a clipboard reader of its own. A paste carrying plain text is never swallowed.

It is opt-in rather than a form-wide default because a form may hold several upload buttons - projects.html has cover + logo beside the attachment one - and a default would attach one pasted screenshot to all three at once. Marking exactly the button that owns the form's content attachments keeps that unambiguous.

Where it lands

Set on _attachment_form.html, so every form that includes it inherits the behaviour:

  • create post (feed composer and the project page's Post an update), edit post
  • create gist, edit gist
  • create project, project screenshots
  • create issue, issue attach form, issue comment form

Plus _comment_form.html (comments on posts, projects, gists and news, and the inline boxes on feed cards and /gists) and messages.html + the mode="embed" skeleton AppChat builds (direct messages).

Deliberately not enabled on the project cover/logo pickers (the several-buttons-per-form case above) or the project file browser (mode="direct", not inside a form).

Server contract

Unchanged. A pasted image goes to /uploads/upload exactly as a picked file does and binds through attachment_uids, so no route, schema, agent tool or docs endpoint changed.

Tests

paste_image() helper in tests/conftest.py (dispatches a real ClipboardEvent carrying a PNG File), plus one e2e test per surface: post composer, comment form, chat.

Full suite run in the project's own Docker image: 3353 passed, 10 failed in 26m32s. All ten failures reproduce on a pristine HEAD checkout in the same container and are environmental - nine in tests/api/projects/workspace.py fail with FileNotFoundError: 'docker' (the image only installs the docker CLI when built with INSTALL_DOCKER_CLI=true), and tests/e2e/game/farm.py::test_steal_takes_build_and_pays_thief asserts against suite-wide accumulated farm coins. The e2e game tier passes clean on its own (36 passed).

🤖 Generated with Claude Code

Pressing Ctrl+V with a screenshot on the clipboard now attaches it immediately, instead of requiring a trip through the file picker. ## How The clipboard reader lives in `dp-upload` behind a new opt-in `paste` boolean attribute. With it set, the component binds **one** paste listener on its `closest("form")` and routes the clipboard's image files through the same `handleFiles` path as the picker and the drop target - so validation, size/count limits, the terms gate and the hidden `attachment_uids` field are all shared, and no page controller grows a clipboard reader of its own. A paste carrying plain text is never swallowed. It is opt-in rather than a form-wide default because a form may hold several upload buttons - `projects.html` has cover + logo beside the attachment one - and a default would attach one pasted screenshot to all three at once. Marking exactly the button that owns the form's content attachments keeps that unambiguous. ## Where it lands Set on `_attachment_form.html`, so every form that includes it inherits the behaviour: - create post (feed composer and the project page's Post an update), edit post - create gist, edit gist - create project, project screenshots - create issue, issue attach form, issue comment form Plus `_comment_form.html` (comments on posts, projects, gists and news, and the inline boxes on feed cards and `/gists`) and `messages.html` + the `mode="embed"` skeleton `AppChat` builds (direct messages). Deliberately not enabled on the project cover/logo pickers (the several-buttons-per-form case above) or the project file browser (`mode="direct"`, not inside a form). ## Server contract Unchanged. A pasted image goes to `/uploads/upload` exactly as a picked file does and binds through `attachment_uids`, so no route, schema, agent tool or docs endpoint changed. ## Tests `paste_image()` helper in `tests/conftest.py` (dispatches a real `ClipboardEvent` carrying a PNG `File`), plus one e2e test per surface: post composer, comment form, chat. Full suite run in the project's own Docker image: **3353 passed, 10 failed in 26m32s**. All ten failures reproduce on a pristine `HEAD` checkout in the same container and are environmental - nine in `tests/api/projects/workspace.py` fail with `FileNotFoundError: 'docker'` (the image only installs the docker CLI when built with `INSTALL_DOCKER_CLI=true`), and `tests/e2e/game/farm.py::test_steal_takes_build_and_pays_thief` asserts against suite-wide accumulated farm coins. The e2e game tier passes clean on its own (36 passed). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
blindxfish added 1 commit 2026-08-17 22:24:09 +02:00
Attach images pasted into the composer, comments and chat
Some checks failed
DevPlace CI / test (pull_request) Has been cancelled
076f55f380
Pressing Ctrl+V with a screenshot on the clipboard now attaches it
immediately instead of requiring a trip through the file picker.

The clipboard reader lives in dp-upload behind a new opt-in `paste`
boolean attribute: with it set, the component binds one paste listener
on its closest form and routes the clipboard image files through the
same handleFiles path as the picker and the drop target, so validation,
limits, the terms gate and the hidden attachment_uids field are shared.
A paste carrying plain text is never swallowed.

It is opt-in rather than a form-wide default because a form may hold
several upload buttons - projects.html has cover and logo beside the
attachment one - and a default would attach one pasted screenshot to
all of them.

Set on _attachment_form.html, so every form including it inherits the
behaviour (post composer, post edit, gists, projects, issues,
screenshots), plus _comment_form.html, messages.html and the embed-mode
skeleton AppChat builds.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
retoor merged commit 08d370b020 into master 2026-08-17 22:44:46 +02:00
Sign in to join this conversation.
No reviewers
No Label
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: retoor/devplacepy#171
No description provided.