diff --git a/examples/N1-Filters/lib/filters-store.coffee b/examples/N1-Filters/lib/filters-store.coffee index 0a8d857a9..52a07638d 100644 --- a/examples/N1-Filters/lib/filters-store.coffee +++ b/examples/N1-Filters/lib/filters-store.coffee @@ -2,7 +2,7 @@ NylasStore = require 'nylas-store' _ = require 'underscore' _s = require 'underscore.string' {Actions, CategoryStore, AccountStore, ChangeLabelsTask, - ChangeFolderTask, ArchiveThreadHelper, ChangeStarredTask, + ChangeFolderTask, TaskFactory, ChangeStarredTask, ChangeUnreadTask, Utils} = require 'nylas-exports' # The FiltersStore performs all business logic for filters: the single source @@ -90,25 +90,14 @@ class FiltersStore extends NylasStore unread: false threads: [thread] else if action is "archive" and val is true - ArchiveThreadHelper.getArchiveTask [thread] + TaskFactory.taskForArchiving({threads: [thread]}) else if action is "star" and val is true new ChangeStarredTask starred: true threads: [thread] else if action is "delete" and val is true - trash = CategoryStore.getStandardCategory "trash" + TaskFactory.taskForMovingToTrash({threads: [thread]}) - # Some email providers use labels, like Gmail, and others use folders, - # like Microsoft Exchange. Labels and folders behave very differently, - # so there are different Task classes to modify records for them. - if AccountStore.current().usesFolders() - new ChangeFolderTask - folder: trash - threads: [thread] - else - new ChangeLabelsTask - labelsToAdd: [trash] - threads: [thread] .value() _getPassedFilters: ({message, thread}) => diff --git a/internal_packages/category-picker/lib/category-picker.cjsx b/internal_packages/category-picker/lib/category-picker.cjsx index b031c819f..1e7bbf031 100644 --- a/internal_packages/category-picker/lib/category-picker.cjsx +++ b/internal_packages/category-picker/lib/category-picker.cjsx @@ -7,12 +7,11 @@ React = require 'react' Thread, Actions, TaskQueue, + TaskFactory, AccountStore, CategoryStore, DatabaseStore, WorkspaceStore, - ChangeLabelsTask, - ChangeFolderTask, SyncbackCategoryTask, TaskQueueStatusStore, FocusedMailViewStore} = require 'nylas-exports' @@ -194,72 +193,36 @@ class CategoryPicker extends React.Component return {parts} _onSelectCategory: (item) => - return unless @_threads().length > 0 + threads = @_threads() + + return unless threads.length > 0 return unless @_account @refs.menu.setSelectedItem(null) - if @_account.usesLabels() - if item.newCategoryItem - cat = new Label - displayName: @state.searchValue, - accountId: AccountStore.current().id - task = new SyncbackCategoryTask - category: cat - organizationUnit: "label" + if item.newCategoryItem + category = new AccountStore.current().categoryClass() + displayName: @state.searchValue, + accountId: AccountStore.current().id + syncbackTask = new SyncbackCategoryTask({category}) + TaskQueueStatusStore.waitForPerformRemote(syncbackTask).then => + DatabaseStore.findBy(category.constructor, clientId: category.clientId).then (category) => + applyTask = TaskFactory.taskForApplyingCategory + threads: threads + category: category + Actions.queueTask(applyTask) + Actions.queueTask(syncbackTask) - TaskQueueStatusStore.waitForPerformRemote(task).then => - DatabaseStore.findBy Label, clientId: cat.clientId - .then (cat) => - changeLabelsTask = new ChangeLabelsTask - labelsToAdd: [cat] - threads: @_threads() - Actions.queueTask(changeLabelsTask) - - Actions.queueTask(task) - else if item.usage > 0 - task = new ChangeLabelsTask - labelsToRemove: [item.category] - threads: @_threads() - Actions.queueTask(task) - else - task = new ChangeLabelsTask - labelsToAdd: [item.category] - threads: @_threads() - Actions.queueTask(task) - - else if @_account.usesFolders() - if item.newCategoryItem? - cat = new Folder - displayName: @state?.searchValue, - accountId: AccountStore.current().id - task = new SyncbackCategoryTask - category: cat - organizationUnit: "folder" - - TaskQueueStatusStore.waitForPerformRemote(task).then => - DatabaseStore.findBy Folder, clientId: cat.clientId - .then (cat) => - return if not cat?.serverId - - changeFolderTask = new ChangeFolderTask - folder: cat - threads: @_threads() - if @props.thread - Actions.moveThread(@props.thread, changeFolderTask) - else if @props.items - Actions.moveThreads(@_threads(), changeFolderTask) - Actions.queueTask(task) - else - task = new ChangeFolderTask - folder: item.category - threads: @_threads() - if @props.thread - Actions.moveThread(@props.thread, task) - else if @props.items - Actions.moveThreads(@_threads(), task) + else if item.usage is threads.length + applyTask = TaskFactory.taskForRemovingCategory + threads: threads + category: item.category + Actions.queueTask(applyTask) else - throw new Error("Invalid organizationUnit") + applyTask = TaskFactory.taskForApplyingCategory + threads: threads + category: item.category + Actions.queueTask(applyTask) @refs.popover.close() diff --git a/internal_packages/category-picker/spec/category-picker-spec.cjsx b/internal_packages/category-picker/spec/category-picker-spec.cjsx index 903a50699..878d9c1e8 100644 --- a/internal_packages/category-picker/spec/category-picker-spec.cjsx +++ b/internal_packages/category-picker/spec/category-picker-spec.cjsx @@ -11,13 +11,12 @@ CategoryPicker = require '../lib/category-picker' Actions, CategoryStore, DatabaseStore, - ChangeLabelsTask, - ChangeFolderTask, + TaskFactory, SyncbackCategoryTask, FocusedMailViewStore, TaskQueueStatusStore} = require 'nylas-exports' -describe 'CategoryPicker', -> +fdescribe 'CategoryPicker', -> beforeEach -> CategoryStore._categoryCache = {} @@ -78,23 +77,6 @@ describe 'CategoryPicker', -> expect(data[2].name).toBeUndefined() expect(data[2].category).toBe @userCategory - xdescribe 'when picking for a single Thread', -> - it 'renders a picker', -> - expect(ReactTestUtils.isCompositeComponentWithType @picker, CategoryPicker).toBe true - - it "does not include a newItem prompt if there's no search", -> - outData = @picker._recalculateState().categoryData - newItem = _.findWhere(outData, newCategoryItem: true) - l1 = _.findWhere(outData, id: 'id-123') - expect(newItem).toBeUndefined() - expect(l1.name).toBe "inbox" - - it "includes a newItem selector with the current search term", -> - - xdescribe 'when picking labels for a single Thread', -> - beforeEach -> - atom.testOrganizationUnit = "label" - describe "'create new' item", -> beforeEach -> setupForCreateNew.call @ @@ -128,156 +110,74 @@ describe 'CategoryPicker', -> expect(count).toBe 1 describe "_onSelectCategory()", -> - describe "using labels", -> + beforeEach -> + setupForCreateNew.call @, "folder" + spyOn(TaskFactory, 'taskForRemovingCategory').andCallThrough() + spyOn(TaskFactory, 'taskForApplyingCategory').andCallThrough() + spyOn(Actions, "queueTask") + + it "closes the popover", -> + spyOn(@popover, "close") + @picker._onSelectCategory { usage: 0, category: "asdf" } + expect(@popover.close).toHaveBeenCalled() + + describe "when selecting a category currently on all the selected items", -> + it "fires a task to remove the category", -> + input = + category: "asdf" + usage: 1 + + @picker._onSelectCategory(input) + expect(TaskFactory.taskForRemovingCategory).toHaveBeenCalledWith + threads: [@testThread] + category: "asdf" + expect(Actions.queueTask).toHaveBeenCalled() + + describe "when selecting a category not on all the selected items", -> + it "fires a task to add the category", -> + input = + category: "asdf" + usage: 0 + + @picker._onSelectCategory(input) + expect(TaskFactory.taskForApplyingCategory).toHaveBeenCalledWith + threads: [@testThread] + category: "asdf" + expect(Actions.queueTask).toHaveBeenCalled() + + describe "when selecting a new category", -> beforeEach -> - setupForCreateNew.call @, "label" - spyOn Actions, "queueTask" - - it "adds a label if it was previously unused", -> - input = { usage: 0, newCategoryItem: undefined, category: "asdf" } - - @picker._onSelectCategory input + input = + newCategoryItem: true + @picker.setState(searchValue: "teSTing!") + @picker._onSelectCategory(input) + it "queues a new syncback task for creating a category", -> expect(Actions.queueTask).toHaveBeenCalled() - - labelsToAdd = Actions.queueTask.calls[0].args[0].labelsToAdd - expect(labelsToAdd.length).toBe 1 - expect(labelsToAdd[0]).toEqual input.category - - threadsToUpdate = Actions.queueTask.calls[0].args[0].threads - expect(threadsToUpdate).toEqual [ @testThread ] - - it "removes a label if it was previously used", -> - input = { usage: 1, newCategoryItem: undefined, category: "asdf" } - - @picker._onSelectCategory input - - expect(Actions.queueTask).toHaveBeenCalled() - - labelsToRemove = Actions.queueTask.calls[0].args[0].labelsToRemove - expect(labelsToRemove.length).toBe 1 - expect(labelsToRemove[0]).toEqual input.category - - threadsToUpdate = Actions.queueTask.calls[0].args[0].threads - expect(threadsToUpdate).toEqual [ @testThread ] - - it "creates a new label task", -> - input = { newCategoryItem: true } - - @picker.setState searchValue: "teSTing!" - - @picker._onSelectCategory input - - expect(Actions.queueTask).toHaveBeenCalled() - syncbackTask = Actions.queueTask.calls[0].args[0] newCategory = syncbackTask.category expect(syncbackTask.organizationUnit).toBe "label" expect(newCategory.displayName).toBe "teSTing!" expect(newCategory.accountId).toBe TEST_ACCOUNT_ID - it "queues a change label task after performRemote for creating it", -> - input = { newCategoryItem: true } - label = new Label(clientId: "local-123") + it "queues a task for applying the category after it has saved", -> + label = new Label(displayName: "teSTing!") spyOn(TaskQueueStatusStore, "waitForPerformRemote").andCallFake (task) -> expect(task instanceof SyncbackCategoryTask).toBe true Promise.resolve() + spyOn(DatabaseStore, "findBy").andCallFake (klass, {clientId}) -> - expect(klass).toBe Label - expect(typeof clientId).toBe "string" - Promise.resolve label + expect(klass).toBe(Label) + expect(typeof clientId).toBe("string") + Promise.resolve(label) + + waitsFor -> + Actions.queueTask.calls.length > 1 + label = Actions.queueTask.calls[0].args[0].category runs -> - @picker.setState searchValue: "teSTing!" - @picker._onSelectCategory input - - waitsFor -> Actions.queueTask.calls.length > 1 - - runs -> - changeLabelsTask = Actions.queueTask.calls[1].args[0] - expect(changeLabelsTask instanceof ChangeLabelsTask).toBe true - expect(changeLabelsTask.labelsToAdd).toEqual [ label ] - expect(changeLabelsTask.threads).toEqual [ @testThread ] - - it "doesn't queue any duplicate syncback tasks", -> - input = { newCategoryItem: true } - label = new Label(clientId: "local-123") - - spyOn(TaskQueueStatusStore, "waitForPerformRemote").andCallFake (task) -> - expect(task instanceof SyncbackCategoryTask).toBe true - Promise.resolve() - spyOn(DatabaseStore, "findBy").andCallFake (klass, {clientId}) -> - expect(klass).toBe Label - expect(typeof clientId).toBe "string" - Promise.resolve label - - runs -> - @picker.setState searchValue: "teSTing!" - @picker._onSelectCategory input - - waitsFor -> Actions.queueTask.calls.length > 1 - - runs -> - allInputs = Actions.queueTask.calls.map (c) -> c.args[0] - syncbackTasks = allInputs.filter (i) -> i instanceof SyncbackCategoryTask - expect(syncbackTasks.length).toBe 1 - - describe "using folders", -> - beforeEach -> - setupForCreateNew.call @, "folder" - spyOn Actions, "queueTask" - spyOn Actions, "moveThread" - spyOn Actions, "moveThreads" - - it "moves a thread if the component has one", -> - input = { category: "blah" } - @picker._onSelectCategory input - expect(Actions.moveThread).toHaveBeenCalled() - - args = Actions.moveThread.calls[0].args - expect(args[0]).toEqual @testThread - expect(args[1].folder).toEqual input.category - expect(args[1].threads).toEqual [ @testThread ] - - it "moves threads if the component has no thread but has items", -> - @picker = ReactTestUtils.renderIntoDocument( - - ) - @popover = ReactTestUtils.findRenderedComponentWithType @picker, Popover - @popover.open() - - input = { category: "blah" } - @picker._onSelectCategory input - expect(Actions.moveThreads).toHaveBeenCalled() - - it "creates a new folder task", -> - input = { newCategoryItem: true } - folder = new Folder(clientId: "local-456", serverId: "yes.") - - spyOn(TaskQueueStatusStore, "waitForPerformRemote").andCallFake (task) -> - expect(task instanceof SyncbackCategoryTask).toBe true - Promise.resolve() - spyOn(DatabaseStore, "findBy").andCallFake (klass, {clientId}) -> - expect(klass).toBe Folder - expect(typeof clientId).toBe "string" - Promise.resolve folder - - runs -> - @picker.setState searchValue: "teSTing!" - @picker._onSelectCategory input - - waitsFor -> Actions.moveThread.calls.length > 0 - - runs -> - changeFoldersTask = Actions.moveThread.calls[0].args[1] - expect(changeFoldersTask instanceof ChangeFolderTask).toBe true - expect(changeFoldersTask.folder).toEqual folder - expect(changeFoldersTask.threads).toEqual [ @testThread ] - - it "closes the popover", -> - setupForCreateNew.call @, "folder" - spyOn @popover, "close" - spyOn Actions, "moveThread" - @picker._onSelectCategory { usage: 0, category: "asdf" } - expect(@popover.close).toHaveBeenCalled() + expect(TaskFactory.taskForApplyingCategory).toHaveBeenCalledWith + threads: [@testThread] + category: label + expect(TaskFactory.taskForApplyingCategory.callCount).toBe(1) diff --git a/internal_packages/message-list/lib/main.cjsx b/internal_packages/message-list/lib/main.cjsx index f5e0f62ec..fb0273258 100644 --- a/internal_packages/message-list/lib/main.cjsx +++ b/internal_packages/message-list/lib/main.cjsx @@ -9,7 +9,8 @@ MessageToolbarItems = require "./message-toolbar-items" SidebarContactList} = require "./sidebar-components" ThreadStarButton = require './thread-star-button' -ThreadRemoveButton = require './thread-remove-button' +ThreadArchiveButton = require './thread-archive-button' +ThreadTrashButton = require './thread-trash-button' ThreadToggleUnreadButton = require './thread-toggle-unread-button' AutolinkerExtension = require './plugins/autolinker-extension' @@ -36,7 +37,10 @@ module.exports = ComponentRegistry.register ThreadStarButton, role: 'message:Toolbar' - ComponentRegistry.register ThreadRemoveButton, + ComponentRegistry.register ThreadArchiveButton, + role: 'message:Toolbar' + + ComponentRegistry.register ThreadTrashButton, role: 'message:Toolbar' ComponentRegistry.register ThreadToggleUnreadButton, @@ -48,7 +52,8 @@ module.exports = deactivate: -> ComponentRegistry.unregister MessageList ComponentRegistry.unregister ThreadStarButton - ComponentRegistry.unregister ThreadRemoveButton + ComponentRegistry.unregister ThreadArchiveButton + ComponentRegistry.unregister ThreadTrashButton ComponentRegistry.unregister ThreadToggleUnreadButton ComponentRegistry.unregister MessageToolbarItems ComponentRegistry.unregister SidebarContactCard diff --git a/internal_packages/message-list/lib/thread-archive-button.cjsx b/internal_packages/message-list/lib/thread-archive-button.cjsx new file mode 100644 index 000000000..a9adf4048 --- /dev/null +++ b/internal_packages/message-list/lib/thread-archive-button.cjsx @@ -0,0 +1,35 @@ +_ = require 'underscore' +React = require 'react' +{RetinaImg} = require 'nylas-component-kit' +{Actions, + TaskFactory, + DOMUtils, + FocusedMailViewStore} = require 'nylas-exports' + +class ThreadArchiveButton extends React.Component + @displayName: "ThreadArchiveButton" + @containerRequired: false + + @propTypes: + thread: React.PropTypes.object.isRequired + + render: => + return false unless FocusedMailViewStore.mailView()?.canArchiveThreads() + + + + _onArchive: (e) => + return unless DOMUtils.nodeIsVisible(e.currentTarget) + task = TaskFactory.taskForArchiving + threads: [@props.thread], + fromView: FocusedMailViewStore.mailView() + Actions.queueTask(task) + e.stopPropagation() + + +module.exports = ThreadArchiveButton diff --git a/internal_packages/message-list/lib/thread-remove-button.cjsx b/internal_packages/message-list/lib/thread-remove-button.cjsx deleted file mode 100644 index d4b5d2807..000000000 --- a/internal_packages/message-list/lib/thread-remove-button.cjsx +++ /dev/null @@ -1,37 +0,0 @@ -_ = require 'underscore' -React = require 'react' -{Actions, - DOMUtils, - RemoveThreadHelper, - FocusedMailViewStore} = require 'nylas-exports' -{RetinaImg} = require 'nylas-component-kit' - -class ThreadRemoveButton extends React.Component - @displayName: "ThreadRemoveButton" - @containerRequired: false - - render: => - focusedMailViewFilter = FocusedMailViewStore.mailView() - return false unless focusedMailViewFilter?.canRemoveThreads() - - if RemoveThreadHelper.removeType() is RemoveThreadHelper.Type.Archive - tooltip = "Archive" - imgName = "toolbar-archive.png" - else if RemoveThreadHelper.removeType() is RemoveThreadHelper.Type.Trash - tooltip = "Trash" - imgName = "toolbar-trash.png" - - - - _onRemove: (e) => - return unless DOMUtils.nodeIsVisible(e.currentTarget) - Actions.removeCurrentlyFocusedThread() - e.stopPropagation() - - -module.exports = ThreadRemoveButton diff --git a/internal_packages/message-list/lib/thread-toggle-unread-button.cjsx b/internal_packages/message-list/lib/thread-toggle-unread-button.cjsx index dfe67757c..f2a877e1c 100644 --- a/internal_packages/message-list/lib/thread-toggle-unread-button.cjsx +++ b/internal_packages/message-list/lib/thread-toggle-unread-button.cjsx @@ -18,12 +18,11 @@ class ThreadToggleUnreadButton extends React.Component _onClick: (e) => - e.stopPropagation() - task = new ChangeUnreadTask thread: @props.thread unread: !@props.thread.unread - Actions.queueTask task + Actions.queueTask(task) Actions.popSheet() + e.stopPropagation() module.exports = ThreadToggleUnreadButton diff --git a/internal_packages/message-list/lib/thread-trash-button.cjsx b/internal_packages/message-list/lib/thread-trash-button.cjsx new file mode 100644 index 000000000..56881ee68 --- /dev/null +++ b/internal_packages/message-list/lib/thread-trash-button.cjsx @@ -0,0 +1,36 @@ +_ = require 'underscore' +React = require 'react' +{Actions, + DOMUtils, + TaskFactory, + FocusedMailViewStore} = require 'nylas-exports' +{RetinaImg} = require 'nylas-component-kit' + +class ThreadTrashButton extends React.Component + @displayName: "ThreadTrashButton" + @containerRequired: false + + @propTypes: + thread: React.PropTypes.object.isRequired + + render: => + focusedMailViewFilter = FocusedMailViewStore.mailView() + return false unless focusedMailViewFilter?.canTrashThreads() + + + + _onRemove: (e) => + return unless DOMUtils.nodeIsVisible(e.currentTarget) + task = TaskFactory.taskForMovingToTrash + threads: [@props.thread], + fromView: FocusedMailViewStore.mailView() + Actions.queueTask(task) + e.stopPropagation() + + +module.exports = ThreadTrashButton diff --git a/internal_packages/thread-list/lib/draft-buttons.cjsx b/internal_packages/thread-list/lib/draft-buttons.cjsx index fcef15476..d29ccb022 100644 --- a/internal_packages/thread-list/lib/draft-buttons.cjsx +++ b/internal_packages/thread-list/lib/draft-buttons.cjsx @@ -14,11 +14,13 @@ class DraftDeleteButton extends React.Component - _destroyDraft: => - Actions.deleteSelection() + _destroySelected: => + for item in @props.selection.items() + Actions.queueTask(new DestroyDraftTask(draftClientId: item.clientId)) + @props.selection.clear() module.exports = {DraftDeleteButton} diff --git a/internal_packages/thread-list/lib/draft-list-store.coffee b/internal_packages/thread-list/lib/draft-list-store.coffee index 11b355461..2cf646d02 100644 --- a/internal_packages/thread-list/lib/draft-list-store.coffee +++ b/internal_packages/thread-list/lib/draft-list-store.coffee @@ -13,7 +13,6 @@ class DraftListStore extends NylasStore constructor: -> @listenTo DatabaseStore, @_onDataChanged @listenTo AccountStore, @_onAccountChanged - @listenTo Actions.deleteSelection, @_onDeleteSelection # It's important to listen to sendDraftSuccess because the # _onDataChanged method will ignore our newly created draft because it @@ -52,12 +51,4 @@ class DraftListStore extends NylasStore return unless containsDraft and @_view @_view.invalidate() - _onDeleteSelection: => - selected = @_view.selection.items() - - for item in selected - Actions.queueTask(new DestroyDraftTask(draftClientId: item.clientId)) - - @_view.selection.clear() - module.exports = new DraftListStore() diff --git a/internal_packages/thread-list/lib/main.cjsx b/internal_packages/thread-list/lib/main.cjsx index ecf82fc66..6e32fb31f 100644 --- a/internal_packages/thread-list/lib/main.cjsx +++ b/internal_packages/thread-list/lib/main.cjsx @@ -2,7 +2,8 @@ _ = require 'underscore' React = require "react" {ComponentRegistry, WorkspaceStore} = require "nylas-exports" -{DownButton, UpButton, ThreadBulkRemoveButton, ThreadBulkStarButton, ThreadBulkToggleUnreadButton} = require "./thread-buttons" +{DownButton, UpButton, ThreadBulkArchiveButton, ThreadBulkTrashButton, + ThreadBulkStarButton, ThreadBulkToggleUnreadButton} = require "./thread-buttons" {DraftDeleteButton} = require "./draft-buttons" ThreadSelectionBar = require './thread-selection-bar' ThreadList = require './thread-list' @@ -44,7 +45,10 @@ module.exports = location: WorkspaceStore.Sheet.Thread.Toolbar.Right modes: ['list'] - ComponentRegistry.register ThreadBulkRemoveButton, + ComponentRegistry.register ThreadBulkArchiveButton, + role: 'thread:BulkAction' + + ComponentRegistry.register ThreadBulkTrashButton, role: 'thread:BulkAction' ComponentRegistry.register ThreadBulkStarButton, @@ -61,7 +65,8 @@ module.exports = ComponentRegistry.unregister DraftSelectionBar ComponentRegistry.unregister ThreadList ComponentRegistry.unregister ThreadSelectionBar - ComponentRegistry.unregister ThreadBulkRemoveButton + ComponentRegistry.unregister ThreadBulkArchiveButton + ComponentRegistry.unregister ThreadBulkTrashButton ComponentRegistry.unregister ThreadBulkToggleUnreadButton ComponentRegistry.unregister DownButton ComponentRegistry.unregister UpButton diff --git a/internal_packages/thread-list/lib/thread-buttons.cjsx b/internal_packages/thread-list/lib/thread-buttons.cjsx index c9da92f1f..1450bea3c 100644 --- a/internal_packages/thread-list/lib/thread-buttons.cjsx +++ b/internal_packages/thread-list/lib/thread-buttons.cjsx @@ -3,37 +3,57 @@ classNames = require 'classnames' ThreadListStore = require './thread-list-store' {RetinaImg} = require 'nylas-component-kit' {Actions, - RemoveThreadHelper, + TaskFactory, + CategoryStore, FocusedContentStore, FocusedMailViewStore} = require "nylas-exports" -class ThreadBulkRemoveButton extends React.Component - @displayName: 'ThreadBulkRemoveButton' +class ThreadBulkArchiveButton extends React.Component + @displayName: 'ThreadBulkArchiveButton' @containerRequired: false @propTypes: selection: React.PropTypes.object.isRequired render: -> - focusedMailViewFilter = FocusedMailViewStore.mailView() - return false unless focusedMailViewFilter?.canRemoveThreads() + return false unless mailViewFilter?.canArchiveThreads() - if RemoveThreadHelper.removeType() is RemoveThreadHelper.Type.Archive - tooltip = "Archive" - imgName = "toolbar-archive.png" - else if RemoveThreadHelper.removeType() is RemoveThreadHelper.Type.Trash - tooltip = "Trash" - imgName = "toolbar-trash.png" + + + _onArchive: => + task = TaskFactory.taskForArchiving + threads: @props.selection.items(), + fromView: FocusedMailViewStore.mailView() + Actions.queueTask(task) + +class ThreadBulkTrashButton extends React.Component + @displayName: 'ThreadBulkTrashButton' + @containerRequired: false + + @propTypes: + selection: React.PropTypes.object.isRequired + + render: -> + mailViewFilter = FocusedMailViewStore.mailView() + return false unless mailViewFilter?.canTrashThreads() _onRemove: => - Actions.removeSelection() + task = TaskFactory.taskForMovingToTrash + threads: @props.selection.items(), + fromView: FocusedMailViewStore.mailView() + Actions.queueTask(task) class ThreadBulkStarButton extends React.Component @@ -52,7 +72,8 @@ class ThreadBulkStarButton extends React.Component _onStar: => - Actions.toggleStarSelection() + task = TaskFactory.taskForInvertingStarred(threads: @props.selection.items()) + Actions.queueTask(task) class ThreadBulkToggleUnreadButton extends React.Component @@ -62,19 +83,9 @@ class ThreadBulkToggleUnreadButton extends React.Component @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" + canMarkUnread = not @props.selection.items().every (s) -> s.unread is true + fragment = if canMarkUnread then "unread" else "read"