Mailspring/internal_packages/thread-list/lib/thread-buttons.cjsx
Juan Tejada 0d15c6cea6 fix(remove-from-view): Fix logic for delete/remove-from-view behavior:
Summary:
- Separate gmail's remove-from-view and delete behaviors and write logic
  for each of those
  - Remove MailboxPerspective::{canArchiveThreads, canTrashThreads,
    removeThreads} and some unecessary code in TaskFactory
  - Instead, add MailboxPerspective::tasksForRemovingFromPerspective (I
    know its a bit of a mouthful)
  - I initially tried to put all of the logic for each execution path
    inside the TaskFactory by checking perspective types, but it made
    more sense to use the polymorphism already in place for the different
    perspective types.
  - There is a default delete/remove-from-view behavior which is
    configurable via simple ruleset objects. The gmail behavior is
    configured in this way.
- Update swipe css classes based on destination of threads
- Fixes #1460:
  - Update logic to display archive/trash buttons and context menu options correctly
    when selected threads can be archived/trashed (not based on
    perspective)
  - Same for swiping
- Add a bunch of specs
- Convert some code to ES6
- TODO write some docs for new functions

Test Plan: Unit tests

Reviewers: drew, evan, bengotow

Reviewed By: bengotow

Differential Revision: https://phab.nylas.com/D2682
2016-03-07 18:16:37 -08:00

203 lines
5.5 KiB
CoffeeScript

_ = require 'underscore'
React = require "react/addons"
classNames = require 'classnames'
ThreadListStore = require './thread-list-store'
{RetinaImg} = require 'nylas-component-kit'
{Actions,
TaskFactory,
AccountStore,
CategoryStore,
FocusedContentStore,
FocusedPerspectiveStore} = require "nylas-exports"
class ThreadBulkArchiveButton extends React.Component
@displayName: 'ThreadBulkArchiveButton'
@containerRequired: false
@propTypes:
selection: React.PropTypes.object.isRequired
render: ->
canArchiveThreads = FocusedPerspectiveStore.current().canArchiveThreads(@props.selection.items())
return <span /> unless canArchiveThreads
<button style={order:-107}
className="btn btn-toolbar"
title="Archive"
onClick={@_onArchive}>
<RetinaImg name="toolbar-archive.png" mode={RetinaImg.Mode.ContentIsMask} />
</button>
_onArchive: =>
tasks = TaskFactory.tasksForArchiving
threads: @props.selection.items(),
fromPerspective: FocusedPerspectiveStore.current()
Actions.queueTasks(tasks)
return
class ThreadBulkTrashButton extends React.Component
@displayName: 'ThreadBulkTrashButton'
@containerRequired: false
@propTypes:
selection: React.PropTypes.object.isRequired
render: ->
canTrashThreads = FocusedPerspectiveStore.current().canTrashThreads(@props.selection.items())
return <span /> unless canTrashThreads
<button style={order:-106}
className="btn btn-toolbar"
title="Move to Trash"
onClick={@_onRemove}>
<RetinaImg name="toolbar-trash.png" mode={RetinaImg.Mode.ContentIsMask} />
</button>
_onRemove: =>
tasks = TaskFactory.tasksForMovingToTrash
threads: @props.selection.items(),
fromPerspective: FocusedPerspectiveStore.current()
Actions.queueTasks(tasks)
return
class ThreadBulkStarButton extends React.Component
@displayName: 'ThreadBulkStarButton'
@containerRequired: false
@propTypes:
selection: React.PropTypes.object.isRequired
render: ->
postClickStarredState = _.every @props.selection.items(), (t) -> t.starred is false
title = "Remove stars from all"
imageName = "toolbar-star-selected.png"
if postClickStarredState
title = "Star all"
imageName = "toolbar-star.png"
<button style={order:-104}
className="btn btn-toolbar"
title={title}
onClick={@_onStar}>
<RetinaImg name={imageName} mode={RetinaImg.Mode.ContentIsMask} />
</button>
_onStar: =>
task = TaskFactory.taskForInvertingStarred(threads: @props.selection.items())
Actions.queueTask(task)
return
class ThreadBulkToggleUnreadButton extends React.Component
@displayName: 'ThreadBulkToggleUnreadButton'
@containerRequired: false
@propTypes:
selection: React.PropTypes.object.isRequired
render: =>
postClickUnreadState = _.every @props.selection.items(), (t) -> _.isMatch(t, {unread: false})
fragment = if postClickUnreadState then "unread" else "read"
<button style={order:-105}
className="btn btn-toolbar"
title="Mark as #{fragment}"
onClick={@_onClick}>
<RetinaImg name="toolbar-markas#{fragment}.png"
mode={RetinaImg.Mode.ContentIsMask} />
</button>
_onClick: =>
task = TaskFactory.taskForInvertingUnread(threads: @props.selection.items())
Actions.queueTask(task)
return
ThreadNavButtonMixin =
getInitialState: ->
@_getStateFromStores()
componentDidMount: ->
@_unsubscribe = ThreadListStore.listen @_onStoreChange
@_unsubscribe_focus = FocusedContentStore.listen @_onStoreChange
isFirstThread: ->
selectedId = FocusedContentStore.focusedId('thread')
ThreadListStore.dataSource().get(0)?.id is selectedId
isLastThread: ->
selectedId = FocusedContentStore.focusedId('thread')
lastIndex = ThreadListStore.dataSource().count() - 1
ThreadListStore.dataSource().get(lastIndex)?.id is selectedId
componentWillUnmount: ->
@_unsubscribe()
@_unsubscribe_focus()
_onStoreChange: ->
@setState @_getStateFromStores()
DownButton = React.createClass
displayName: 'DownButton'
mixins: [ThreadNavButtonMixin]
render: ->
<div className={@_classSet()} onClick={@_onClick} title="Next thread">
<RetinaImg name="toolbar-down-arrow.png" mode={RetinaImg.Mode.ContentIsMask} />
</div>
_classSet: ->
classNames
"btn-icon": true
"message-toolbar-arrow": true
"down": true
"disabled": @state.disabled
_onClick: ->
return if @state.disabled
NylasEnv.commands.dispatch(document.body, 'core:next-item')
return
_getStateFromStores: ->
disabled: @isLastThread()
UpButton = React.createClass
displayName: 'UpButton'
mixins: [ThreadNavButtonMixin]
render: ->
<div className={@_classSet()} onClick={@_onClick} title="Previous thread">
<RetinaImg name="toolbar-up-arrow.png" mode={RetinaImg.Mode.ContentIsMask} />
</div>
_classSet: ->
classNames
"btn-icon": true
"message-toolbar-arrow": true
"up": true
"disabled": @state.disabled
_onClick: ->
return if @state.disabled
NylasEnv.commands.dispatch(document.body, 'core:previous-item')
return
_getStateFromStores: ->
disabled: @isFirstThread()
UpButton.containerRequired = false
DownButton.containerRequired = false
module.exports = {
DownButton,
UpButton,
ThreadBulkArchiveButton,
ThreadBulkTrashButton,
ThreadBulkStarButton,
ThreadBulkToggleUnreadButton
}