mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-09-07 05:04:58 +08:00
feat(toggle-unread): threads can now toggle their unread status. fixes T3483.
Summary: still WIP, but functionality is there. TODO: [x] write tests [x] swap out the current markasread icon for the correct markasread icon that @sdw is making [x] figure out how to address this point by @bengotow: https://phab.nylas.com/D2024?id=19139#inline-12168 Test Plan: tested manually. still need to write tests though. Reviewers: evan, bengotow Reviewed By: bengotow Subscribers: sdw Maniphest Tasks: T3483 Differential Revision: https://phab.nylas.com/D2024
This commit is contained in:
parent
0289de243a
commit
4e6b4f4c9c
11 changed files with 125 additions and 4 deletions
|
@ -7,6 +7,7 @@ SidebarThreadParticipants = require "./sidebar-thread-participants"
|
||||||
|
|
||||||
ThreadStarButton = require './thread-star-button'
|
ThreadStarButton = require './thread-star-button'
|
||||||
ThreadArchiveButton = require './thread-archive-button'
|
ThreadArchiveButton = require './thread-archive-button'
|
||||||
|
ThreadToggleUnreadButton = require './thread-toggle-unread-button'
|
||||||
|
|
||||||
AutolinkerExtension = require './plugins/autolinker-extension'
|
AutolinkerExtension = require './plugins/autolinker-extension'
|
||||||
TrackingPixelsExtension = require './plugins/tracking-pixels-extension'
|
TrackingPixelsExtension = require './plugins/tracking-pixels-extension'
|
||||||
|
@ -31,6 +32,9 @@ module.exports =
|
||||||
ComponentRegistry.register ThreadArchiveButton,
|
ComponentRegistry.register ThreadArchiveButton,
|
||||||
role: 'message:Toolbar'
|
role: 'message:Toolbar'
|
||||||
|
|
||||||
|
ComponentRegistry.register ThreadToggleUnreadButton,
|
||||||
|
role: 'message:Toolbar'
|
||||||
|
|
||||||
MessageStore.registerExtension(AutolinkerExtension)
|
MessageStore.registerExtension(AutolinkerExtension)
|
||||||
MessageStore.registerExtension(TrackingPixelsExtension)
|
MessageStore.registerExtension(TrackingPixelsExtension)
|
||||||
|
|
||||||
|
@ -38,6 +42,7 @@ module.exports =
|
||||||
ComponentRegistry.unregister MessageList
|
ComponentRegistry.unregister MessageList
|
||||||
ComponentRegistry.unregister ThreadStarButton
|
ComponentRegistry.unregister ThreadStarButton
|
||||||
ComponentRegistry.unregister ThreadArchiveButton
|
ComponentRegistry.unregister ThreadArchiveButton
|
||||||
|
ComponentRegistry.unregister ThreadToggleUnreadButton
|
||||||
ComponentRegistry.unregister MessageToolbarItems
|
ComponentRegistry.unregister MessageToolbarItems
|
||||||
ComponentRegistry.unregister SidebarThreadParticipants
|
ComponentRegistry.unregister SidebarThreadParticipants
|
||||||
MessageStore.unregisterExtension(AutolinkerExtension)
|
MessageStore.unregisterExtension(AutolinkerExtension)
|
||||||
|
|
|
@ -11,7 +11,7 @@ class StarButton extends React.Component
|
||||||
|
|
||||||
render: =>
|
render: =>
|
||||||
selected = @props.thread? and @props.thread.starred
|
selected = @props.thread? and @props.thread.starred
|
||||||
<button className="btn btn-toolbar btn-star"
|
<button className="btn btn-toolbar"
|
||||||
style={order: -104}
|
style={order: -104}
|
||||||
data-tooltip="Star"
|
data-tooltip="Star"
|
||||||
onClick={@_onStarToggle}>
|
onClick={@_onStarToggle}>
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
React = require 'react'
|
||||||
|
{Actions, FocusedContentStore, ChangeUnreadTask} = require 'nylas-exports'
|
||||||
|
{RetinaImg} = require 'nylas-component-kit'
|
||||||
|
|
||||||
|
class ThreadToggleUnreadButton extends React.Component
|
||||||
|
@displayName: "ThreadToggleUnreadButton"
|
||||||
|
@containerRequired: false
|
||||||
|
|
||||||
|
render: =>
|
||||||
|
fragment = if @props.thread?.unread then "read" else "unread"
|
||||||
|
|
||||||
|
<button className="btn btn-toolbar"
|
||||||
|
style={order: -106}
|
||||||
|
data-tooltip="Mark as #{fragment}"
|
||||||
|
onClick={@_onClick}>
|
||||||
|
<RetinaImg name="icon-toolbar-markas#{fragment}@2x.png"
|
||||||
|
mode={RetinaImg.Mode.ContentIsMask} />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
_onClick: (e) =>
|
||||||
|
e.stopPropagation()
|
||||||
|
|
||||||
|
task = new ChangeUnreadTask
|
||||||
|
thread: @props.thread
|
||||||
|
unread: !@props.thread.unread
|
||||||
|
Actions.queueTask task
|
||||||
|
Actions.popSheet()
|
||||||
|
|
||||||
|
module.exports = ThreadToggleUnreadButton
|
|
@ -1,9 +1,10 @@
|
||||||
React = require "react/addons"
|
React = require "react/addons"
|
||||||
ReactTestUtils = React.addons.TestUtils
|
ReactTestUtils = React.addons.TestUtils
|
||||||
TestUtils = React.addons.TestUtils
|
TestUtils = React.addons.TestUtils
|
||||||
{Thread, FocusedContentStore, Actions} = require "nylas-exports"
|
{Thread, FocusedContentStore, Actions, ChangeUnreadTask} = require "nylas-exports"
|
||||||
|
|
||||||
StarButton = require '../lib/thread-star-button'
|
StarButton = require '../lib/thread-star-button'
|
||||||
|
ThreadToggleUnreadButton = require '../lib/thread-toggle-unread-button'
|
||||||
|
|
||||||
test_thread = (new Thread).fromJSON({
|
test_thread = (new Thread).fromJSON({
|
||||||
"id" : "thread_12345"
|
"id" : "thread_12345"
|
||||||
|
@ -35,3 +36,28 @@ describe "MessageToolbarItem starring", ->
|
||||||
|
|
||||||
expect(Actions.queueTask.mostRecentCall.args[0].threads).toEqual([test_thread_starred])
|
expect(Actions.queueTask.mostRecentCall.args[0].threads).toEqual([test_thread_starred])
|
||||||
expect(Actions.queueTask.mostRecentCall.args[0].starred).toEqual(false)
|
expect(Actions.queueTask.mostRecentCall.args[0].starred).toEqual(false)
|
||||||
|
|
||||||
|
describe "MessageToolbarItem marking as unread", ->
|
||||||
|
thread = null
|
||||||
|
markUnreadBtn = null
|
||||||
|
|
||||||
|
beforeEach ->
|
||||||
|
thread = new Thread(id: "thread-id-lol-123")
|
||||||
|
markUnreadBtn = ReactTestUtils.renderIntoDocument(
|
||||||
|
<ThreadToggleUnreadButton thread={thread} />
|
||||||
|
)
|
||||||
|
|
||||||
|
it "queues a task to change unread status to true", ->
|
||||||
|
spyOn Actions, "queueTask"
|
||||||
|
ReactTestUtils.Simulate.click React.findDOMNode(markUnreadBtn)
|
||||||
|
|
||||||
|
changeUnreadTask = Actions.queueTask.calls[0].args[0]
|
||||||
|
expect(changeUnreadTask instanceof ChangeUnreadTask).toBe true
|
||||||
|
expect(changeUnreadTask.unread).toBe true
|
||||||
|
expect(changeUnreadTask.threads[0].id).toBe thread.id
|
||||||
|
|
||||||
|
it "returns to the thread list", ->
|
||||||
|
spyOn Actions, "popSheet"
|
||||||
|
ReactTestUtils.Simulate.click React.findDOMNode(markUnreadBtn)
|
||||||
|
|
||||||
|
expect(Actions.popSheet).toHaveBeenCalled()
|
||||||
|
|
|
@ -2,7 +2,7 @@ _ = require 'underscore'
|
||||||
React = require "react"
|
React = require "react"
|
||||||
{ComponentRegistry, WorkspaceStore} = require "nylas-exports"
|
{ComponentRegistry, WorkspaceStore} = require "nylas-exports"
|
||||||
|
|
||||||
{DownButton, UpButton, ThreadBulkArchiveButton, ThreadBulkStarButton} = require "./thread-buttons"
|
{DownButton, UpButton, ThreadBulkArchiveButton, ThreadBulkStarButton, ThreadBulkToggleUnreadButton} = require "./thread-buttons"
|
||||||
{DraftDeleteButton} = require "./draft-buttons"
|
{DraftDeleteButton} = require "./draft-buttons"
|
||||||
ThreadSelectionBar = require './thread-selection-bar'
|
ThreadSelectionBar = require './thread-selection-bar'
|
||||||
ThreadList = require './thread-list'
|
ThreadList = require './thread-list'
|
||||||
|
@ -42,6 +42,9 @@ module.exports =
|
||||||
ComponentRegistry.register ThreadBulkStarButton,
|
ComponentRegistry.register ThreadBulkStarButton,
|
||||||
role: 'thread:BulkAction'
|
role: 'thread:BulkAction'
|
||||||
|
|
||||||
|
ComponentRegistry.register ThreadBulkToggleUnreadButton,
|
||||||
|
role: 'thread:BulkAction'
|
||||||
|
|
||||||
ComponentRegistry.register DraftDeleteButton,
|
ComponentRegistry.register DraftDeleteButton,
|
||||||
role: 'draft:BulkAction'
|
role: 'draft:BulkAction'
|
||||||
|
|
||||||
|
@ -51,6 +54,7 @@ module.exports =
|
||||||
ComponentRegistry.unregister ThreadList
|
ComponentRegistry.unregister ThreadList
|
||||||
ComponentRegistry.unregister ThreadSelectionBar
|
ComponentRegistry.unregister ThreadSelectionBar
|
||||||
ComponentRegistry.unregister ThreadBulkArchiveButton
|
ComponentRegistry.unregister ThreadBulkArchiveButton
|
||||||
|
ComponentRegistry.unregister ThreadBulkToggleUnreadButton
|
||||||
ComponentRegistry.unregister DownButton
|
ComponentRegistry.unregister DownButton
|
||||||
ComponentRegistry.unregister UpButton
|
ComponentRegistry.unregister UpButton
|
||||||
ComponentRegistry.unregister DraftDeleteButton
|
ComponentRegistry.unregister DraftDeleteButton
|
||||||
|
|
|
@ -42,6 +42,47 @@ class ThreadBulkStarButton extends React.Component
|
||||||
Actions.toggleStarSelection()
|
Actions.toggleStarSelection()
|
||||||
|
|
||||||
|
|
||||||
|
class ThreadBulkToggleUnreadButton extends React.Component
|
||||||
|
@displayName: 'ThreadBulkToggleUnreadButton'
|
||||||
|
@containerRequired: false
|
||||||
|
|
||||||
|
@propTypes:
|
||||||
|
selection: React.PropTypes.object.isRequired
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
|
@state = @_getStateFromStores()
|
||||||
|
super
|
||||||
|
|
||||||
|
componentDidMount: =>
|
||||||
|
@unsubscribers = []
|
||||||
|
@unsubscribers.push ThreadListStore.listen @_onStoreChange
|
||||||
|
|
||||||
|
componentWillUnmount: =>
|
||||||
|
unsubscribe() for unsubscribe in @unsubscribers
|
||||||
|
|
||||||
|
render: =>
|
||||||
|
fragment = if @state.canMarkUnread then "unread" else "read"
|
||||||
|
|
||||||
|
<button style={order:-106}
|
||||||
|
className="btn btn-toolbar"
|
||||||
|
data-tooltip="Mark as #{fragment}"
|
||||||
|
onClick={@_onClick}>
|
||||||
|
<RetinaImg name="icon-toolbar-markas#{fragment}@2x.png"
|
||||||
|
mode={RetinaImg.Mode.ContentIsMask} />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
_onClick: =>
|
||||||
|
Actions.toggleUnreadSelection()
|
||||||
|
|
||||||
|
_onStoreChange: =>
|
||||||
|
@setState @_getStateFromStores()
|
||||||
|
|
||||||
|
_getStateFromStores: =>
|
||||||
|
selections = ThreadListStore.view().selection.items()
|
||||||
|
canMarkUnread: not selections.every (s) -> s.unread is true
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ThreadNavButtonMixin =
|
ThreadNavButtonMixin =
|
||||||
getInitialState: ->
|
getInitialState: ->
|
||||||
@_getStateFromStores()
|
@_getStateFromStores()
|
||||||
|
@ -117,4 +158,4 @@ UpButton = React.createClass
|
||||||
UpButton.containerRequired = false
|
UpButton.containerRequired = false
|
||||||
DownButton.containerRequired = false
|
DownButton.containerRequired = false
|
||||||
|
|
||||||
module.exports = {DownButton, UpButton, ThreadBulkArchiveButton, ThreadBulkStarButton}
|
module.exports = {DownButton, UpButton, ThreadBulkArchiveButton, ThreadBulkStarButton, ThreadBulkToggleUnreadButton}
|
||||||
|
|
|
@ -9,6 +9,7 @@ NylasStore = require 'nylas-store'
|
||||||
DatabaseStore,
|
DatabaseStore,
|
||||||
AccountStore,
|
AccountStore,
|
||||||
WorkspaceStore,
|
WorkspaceStore,
|
||||||
|
ChangeUnreadTask,
|
||||||
ChangeStarredTask,
|
ChangeStarredTask,
|
||||||
FocusedContentStore,
|
FocusedContentStore,
|
||||||
ArchiveThreadHelper,
|
ArchiveThreadHelper,
|
||||||
|
@ -33,6 +34,8 @@ class ThreadListStore extends NylasStore
|
||||||
@listenTo Actions.toggleStarSelection, @_onToggleStarSelection
|
@listenTo Actions.toggleStarSelection, @_onToggleStarSelection
|
||||||
@listenTo Actions.toggleStarFocused, @_onToggleStarFocused
|
@listenTo Actions.toggleStarFocused, @_onToggleStarFocused
|
||||||
|
|
||||||
|
@listenTo Actions.toggleUnreadSelection, @_onToggleUnreadSelection
|
||||||
|
|
||||||
@listenTo DatabaseStore, @_onDataChanged
|
@listenTo DatabaseStore, @_onDataChanged
|
||||||
@listenTo AccountStore, @_onAccountChanged
|
@listenTo AccountStore, @_onAccountChanged
|
||||||
@listenTo FocusedMailViewStore, @_onMailViewChanged
|
@listenTo FocusedMailViewStore, @_onMailViewChanged
|
||||||
|
@ -146,6 +149,15 @@ class ThreadListStore extends NylasStore
|
||||||
if task
|
if task
|
||||||
Actions.queueTask(task)
|
Actions.queueTask(task)
|
||||||
|
|
||||||
|
_onToggleUnreadSelection: ->
|
||||||
|
threads = @_view.selection.items()
|
||||||
|
allUnread = threads.every (t) ->
|
||||||
|
t.unread is true
|
||||||
|
unread = not allUnread
|
||||||
|
|
||||||
|
task = new ChangeUnreadTask {threads, unread}
|
||||||
|
Actions.queueTask task
|
||||||
|
|
||||||
_onArchive: ->
|
_onArchive: ->
|
||||||
@_archiveAndShiftBy('auto')
|
@_archiveAndShiftBy('auto')
|
||||||
|
|
||||||
|
|
|
@ -328,6 +328,7 @@ class Actions
|
||||||
@archiveAndPrevious: ActionScopeWindow
|
@archiveAndPrevious: ActionScopeWindow
|
||||||
@toggleStarSelection: ActionScopeWindow
|
@toggleStarSelection: ActionScopeWindow
|
||||||
@toggleStarFocused: ActionScopeWindow
|
@toggleStarFocused: ActionScopeWindow
|
||||||
|
@toggleUnreadSelection: ActionScopeWindow
|
||||||
@deleteSelection: ActionScopeWindow
|
@deleteSelection: ActionScopeWindow
|
||||||
|
|
||||||
@moveThread: ActionScopeWindow
|
@moveThread: ActionScopeWindow
|
||||||
|
|
|
@ -36,6 +36,9 @@ class ChangeUnreadTask extends ChangeMailTask
|
||||||
@threads = _.compact(threads)
|
@threads = _.compact(threads)
|
||||||
return super
|
return super
|
||||||
|
|
||||||
|
_processesNestedMessages: ->
|
||||||
|
true
|
||||||
|
|
||||||
_changesToModel: (model) ->
|
_changesToModel: (model) ->
|
||||||
{unread: @unread}
|
{unread: @unread}
|
||||||
|
|
||||||
|
|
BIN
static/images/toolbar/icon-toolbar-markasread@2x.png
Normal file
BIN
static/images/toolbar/icon-toolbar-markasread@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 244 KiB |
BIN
static/images/toolbar/icon-toolbar-markasunread@2x.png
Normal file
BIN
static/images/toolbar/icon-toolbar-markasunread@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 244 KiB |
Loading…
Add table
Reference in a new issue