Conversation
The header already started a resize anywhere that wasn't a button, but the tab switcher and window controls cover both top corners, so grabbing one did nothing. The empty pill also read "Add a comment" while clicking it opens the email reply.
…mposer # Conflicts: # desk/src/components/CommunicationArea.vue # desk/src/components/EmailEditor.vue
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #3674 +/- ##
===========================================
+ Coverage 73.76% 75.10% +1.33%
===========================================
Files 148 154 +6
Lines 10841 11439 +598
===========================================
+ Hits 7997 8591 +594
- Misses 2844 2848 +4 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
The framework composer only took a label, so the send state was the word "Sending...". frappe/frappe#42696 adds a `submitting` prop that lights the button's own spinner; pass it and shorten the labels to "Sending" and "Commenting".
The panes padded both sides on top of the composer's own padding, so Send and the CC/BCC toggles ended 10px short of the Close button above them. Keep only the start inset, which puts the text under the tab labels, and let the composer's padding meet the chrome on the end side.
The composer fades its own bottom edge since frappe/frappe#42696.
The panel sat under the Send button because the composer had nowhere to put it. frappe/frappe#42696 adds a `#footer` slot between the body and the utilities row; render it there, where develop's editor had it.
aerodeval
marked this pull request as ready for review
September 10, 2026 07:11
|
Tick the box to add this pull request to the merge queue (same as
|
Contributor
|
The docked resize cursor came from a positional selector into the library's title bar. The header slot div fills that bar, so a conditional class on it does the same without naming library internals.
…mposer # Conflicts: # desk/src/components/CommentTextEditor.vue # desk/src/components/EmailEditor.vue # desk/src/components/SavedReplyActions/SavedReplyActions.vue # desk/src/components/index.ts # desk/src/components/ticket-agent/TicketActivityPanel.vue
frappe-ui has no ./frappe subpath and no rounded-lg alias any more.
A media node sent mid-upload has no src and the file is unrecoverable. Also forwards the editor's signal and progress callback to the uploader.
A failed request was cached as "no contact" for the session, and the page size counted addresses when one address can own several contacts.
The staged list can be cleared while the request is out, so the retry was re-sending nothing.
The height is stored for the whole browser, so it outlives the window it was dragged in.
Hold the timeline reserve during a drag, drop the duplicate tabpanel scroller, keep the composer open when replying from the thread, and outline the channel switcher.
The drag sized the whole column, so every header row opened at the editor's expense. Size the message area instead and let the window follow it.
The drag stopped at the body's resting floor and then snapped the window shut with nothing moving on screen, ended the gesture at the collapse so reopening needed a second click, and held the timeline's reserved height back until release, where it landed in one jump. The body now shrinks to nothing before collapsing, the gesture stays live through the collapse so pulling back up reopens it, and the timeline follows the composer through the drag. Resizing is handle-only and the resize cursor holds until the pointer comes up.
Hold the thread's reserved space until the drag ends so it stops moving under the pointer, capture the pointer on the composer root so collapsing mid-drag cannot drop the gesture, and carry the resize cursor there too, since a captured pointer takes its cursor from whatever holds the capture. Frost the window only when it is docked.
Badge rounds itself fully, so the action chips read as pills next to the recipient chips above them, which use rounded-4. Pin both the chips and the overflow badge to that radius, and drop the block's right margin.
The composer draws its own attachment chips, so AttachmentList stopped being used and took the preview dialog with it. Fill the composer's attachments slot with it in both channels.
Trim the composer column to 9px and inset the panel by half a pixel so its border sits on the column edge, then match the chip row and pull the header's controls back to where the composer's own icons sit.
Cap the chip and carry the name in a title, and hold the icons at their size: Button renders slot content bare, so a prefix or suffix icon is a plain flex child and collapses once the chip has a width to fit into.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
New Communication Composer experience in frappe helpdesk
Why
the earlier composer provided very less space to work with and would often ruin the experience while typing as most of the content which agents wanted to refer to was hidden by the composer. This PR aims to solve this problem by adding a floating composer which provides flexibility to the user as they can drag around and move the composer once it is floating.
Depends on
Built using the component in frappe/ui folder frappe/frappe#40280
EmailComposer/CommentComposerin@framework/uishow-*flags, splitv-model:to/cc/bcc, flat submit payload,extensionssubmitting(spinner on Send),#footerslot (the staged saved reply actions render there), toolbar start, body bottom fade, attach button spinnerWhat changes
Drafts, mentions, saved replies, attachments, signatures and the existing
localStoragedraft keys all behave as before.Beyond the composer itself:
components/CommentTextEditor.vue,EmailEditor.vue,CommunicationArea.vuecomponents/communication-area/communication-area/recipients.tsName <email>addresses and fills chip labels from Contacts, bounded to the addresses being labelledcommunication-area/useDockedResize.tsticket-agent/TicketActivityPanel.vueticket-agent/timeline/TicketTimeline.vueeditor/config.tshelpdeskExtensionsso every editor and the composer share one liststores/agent.ts,composables/useSavedReplyActionOptions.tsloadOnce()so readers share one agent fetch instead of racingSavedReplyActions/SavedReplyActions.vuetypes.tsReplyPayload, what the timeline hands the composermodals/ShortcutsModal.vueElistedpages/ticket/MobileTicketAgent.vueBefore / after
Email/Commenttabs in its headerScreenshots
Demo:
Screen.Recording.2026-09-18.at.2.23.09.AM.mov