From f88b0f3708f848e4f93474df2474857daa2238f1 Mon Sep 17 00:00:00 2001 From: Evan Morikawa Date: Wed, 30 Sep 2015 19:51:48 -0700 Subject: [PATCH] feat(archive): shows trash for non-archive accounts Summary: Fixes T3570 Fixes T3737 Rename ArchiveThreadHelper to RemoveThreadHelper Rename of `getRemovalTask` Remove unarchive from `RemoveThreadHelper`. Pass in mailviewfilter Rename actions Rename archive action renmaing support trash and archive folders in RemoveThreadHelper Move everything over to trash add tests Hide trash and archive Test Plan: new tests Reviewers: dillon, bengotow Reviewed By: dillon, bengotow Maniphest Tasks: T3570, T3737 Differential Revision: https://phab.nylas.com/D2089 --- exports/nylas-exports.coffee | 2 +- internal_packages/message-list/lib/main.cjsx | 6 +- .../lib/thread-archive-button.cjsx | 24 ----- .../lib/thread-remove-button.cjsx | 37 +++++++ internal_packages/thread-list/lib/main.cjsx | 6 +- .../thread-list/lib/thread-buttons.cjsx | 31 ++++-- .../lib/thread-list-quick-actions.cjsx | 61 ++---------- .../thread-list/lib/thread-list-store.coffee | 43 ++++---- .../thread-list/lib/thread-list.cjsx | 17 ++-- .../thread-list/spec/thread-list-spec.cjsx | 6 +- .../tasks/remove-thread-helper-spec.coffee | 88 +++++++++++++++++ src/components/multiselect-action-bar.cjsx | 2 +- src/flux/actions.coffee | 16 +-- src/flux/tasks/archive-thread-helper.coffee | 72 -------------- src/mail-view-filter.coffee | 16 ++- src/services/remove-thread-helper.coffee | 93 ++++++++++++++++++ static/images/toolbar/toolbar-trash@2x.png | Bin 1497 -> 1361 bytes 17 files changed, 316 insertions(+), 204 deletions(-) delete mode 100644 internal_packages/message-list/lib/thread-archive-button.cjsx create mode 100644 internal_packages/message-list/lib/thread-remove-button.cjsx create mode 100644 spec-nylas/tasks/remove-thread-helper-spec.coffee delete mode 100644 src/flux/tasks/archive-thread-helper.coffee create mode 100644 src/services/remove-thread-helper.coffee diff --git a/exports/nylas-exports.coffee b/exports/nylas-exports.coffee index 89ee66108..518dd2f42 100644 --- a/exports/nylas-exports.coffee +++ b/exports/nylas-exports.coffee @@ -90,7 +90,6 @@ class NylasExports @require "ChangeStarredTask", 'flux/tasks/change-starred-task' @require "CreateMetadataTask", 'flux/tasks/create-metadata-task' @require "MarkMessageReadTask", 'flux/tasks/mark-message-read' - @require "ArchiveThreadHelper", 'flux/tasks/archive-thread-helper' @require "DestroyMetadataTask", 'flux/tasks/destroy-metadata-task' # Stores @@ -134,6 +133,7 @@ class NylasExports @load "UndoManager", 'flux/undo-manager' @load "QuotedHTMLParser", 'services/quoted-html-parser' @load "QuotedPlainTextParser", 'services/quoted-plain-text-parser' + @require "RemoveThreadHelper", 'services/remove-thread-helper' # Errors @get "APIError", -> require('../src/flux/errors').APIError diff --git a/internal_packages/message-list/lib/main.cjsx b/internal_packages/message-list/lib/main.cjsx index 64095aa97..f5e0f62ec 100644 --- a/internal_packages/message-list/lib/main.cjsx +++ b/internal_packages/message-list/lib/main.cjsx @@ -9,7 +9,7 @@ MessageToolbarItems = require "./message-toolbar-items" SidebarContactList} = require "./sidebar-components" ThreadStarButton = require './thread-star-button' -ThreadArchiveButton = require './thread-archive-button' +ThreadRemoveButton = require './thread-remove-button' ThreadToggleUnreadButton = require './thread-toggle-unread-button' AutolinkerExtension = require './plugins/autolinker-extension' @@ -36,7 +36,7 @@ module.exports = ComponentRegistry.register ThreadStarButton, role: 'message:Toolbar' - ComponentRegistry.register ThreadArchiveButton, + ComponentRegistry.register ThreadRemoveButton, role: 'message:Toolbar' ComponentRegistry.register ThreadToggleUnreadButton, @@ -48,7 +48,7 @@ module.exports = deactivate: -> ComponentRegistry.unregister MessageList ComponentRegistry.unregister ThreadStarButton - ComponentRegistry.unregister ThreadArchiveButton + ComponentRegistry.unregister ThreadRemoveButton 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 deleted file mode 100644 index cc9dab8b8..000000000 --- a/internal_packages/message-list/lib/thread-archive-button.cjsx +++ /dev/null @@ -1,24 +0,0 @@ -_ = require 'underscore' -React = require 'react' -{Actions, DOMUtils} = require 'nylas-exports' -{RetinaImg} = require 'nylas-component-kit' - -class ThreadArchiveButton extends React.Component - @displayName: "ThreadArchiveButton" - @containerRequired: false - - render: => - - - _onArchive: (e) => - return unless DOMUtils.nodeIsVisible(e.currentTarget) - Actions.archive() - 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 new file mode 100644 index 000000000..d4b5d2807 --- /dev/null +++ b/internal_packages/message-list/lib/thread-remove-button.cjsx @@ -0,0 +1,37 @@ +_ = 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/thread-list/lib/main.cjsx b/internal_packages/thread-list/lib/main.cjsx index 4df4aa631..ecf82fc66 100644 --- a/internal_packages/thread-list/lib/main.cjsx +++ b/internal_packages/thread-list/lib/main.cjsx @@ -2,7 +2,7 @@ _ = require 'underscore' React = require "react" {ComponentRegistry, WorkspaceStore} = require "nylas-exports" -{DownButton, UpButton, ThreadBulkArchiveButton, ThreadBulkStarButton, ThreadBulkToggleUnreadButton} = require "./thread-buttons" +{DownButton, UpButton, ThreadBulkRemoveButton, ThreadBulkStarButton, ThreadBulkToggleUnreadButton} = require "./thread-buttons" {DraftDeleteButton} = require "./draft-buttons" ThreadSelectionBar = require './thread-selection-bar' ThreadList = require './thread-list' @@ -44,7 +44,7 @@ module.exports = location: WorkspaceStore.Sheet.Thread.Toolbar.Right modes: ['list'] - ComponentRegistry.register ThreadBulkArchiveButton, + ComponentRegistry.register ThreadBulkRemoveButton, role: 'thread:BulkAction' ComponentRegistry.register ThreadBulkStarButton, @@ -61,7 +61,7 @@ module.exports = ComponentRegistry.unregister DraftSelectionBar ComponentRegistry.unregister ThreadList ComponentRegistry.unregister ThreadSelectionBar - ComponentRegistry.unregister ThreadBulkArchiveButton + ComponentRegistry.unregister ThreadBulkRemoveButton 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 426942268..c9da92f1f 100644 --- a/internal_packages/thread-list/lib/thread-buttons.cjsx +++ b/internal_packages/thread-list/lib/thread-buttons.cjsx @@ -2,25 +2,38 @@ React = require "react/addons" classNames = require 'classnames' ThreadListStore = require './thread-list-store' {RetinaImg} = require 'nylas-component-kit' -{Actions, FocusedContentStore} = require "nylas-exports" +{Actions, + RemoveThreadHelper, + FocusedContentStore, + FocusedMailViewStore} = require "nylas-exports" -class ThreadBulkArchiveButton extends React.Component - @displayName: 'ThreadBulkArchiveButton' +class ThreadBulkRemoveButton extends React.Component + @displayName: 'ThreadBulkRemoveButton' @containerRequired: false @propTypes: selection: React.PropTypes.object.isRequired 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" + - _onArchive: => - Actions.archiveSelection() + _onRemove: => + Actions.removeSelection() class ThreadBulkStarButton extends React.Component @@ -158,4 +171,4 @@ UpButton = React.createClass UpButton.containerRequired = false DownButton.containerRequired = false -module.exports = {DownButton, UpButton, ThreadBulkArchiveButton, ThreadBulkStarButton, ThreadBulkToggleUnreadButton} +module.exports = {DownButton, UpButton, ThreadBulkRemoveButton, ThreadBulkStarButton, ThreadBulkToggleUnreadButton} diff --git a/internal_packages/thread-list/lib/thread-list-quick-actions.cjsx b/internal_packages/thread-list/lib/thread-list-quick-actions.cjsx index 029ca2c3e..8f3ac4197 100644 --- a/internal_packages/thread-list/lib/thread-list-quick-actions.cjsx +++ b/internal_packages/thread-list/lib/thread-list-quick-actions.cjsx @@ -1,71 +1,30 @@ -_ = require 'underscore' React = require 'react' {Actions, - Utils, - Thread, - ArchiveThreadHelper, - CategoryStore, - ChangeFolderTask, - ChangeLabelsTask, - AccountStore} = require 'nylas-exports' + RemoveThreadHelper, + FocusedMailViewStore} = require 'nylas-exports' class ThreadListQuickActions extends React.Component @displayName: 'ThreadListQuickActions' @propTypes: thread: React.PropTypes.object - categoryId: React.PropTypes.string render: => - actions = [] - if @_shouldDisplayArchiveButton() - actions.push
- else if AccountStore.current().usesLabels() and @props.categoryId == CategoryStore.getStandardCategory('all').id - actions.push
+ focusedMailViewFilter = FocusedMailViewStore.mailView() + return false unless focusedMailViewFilter?.canRemoveThreads() - return false if actions.length is 0 + classNames = "btn action action-#{RemoveThreadHelper.removeType()}"
- {actions} +
shouldComponentUpdate: (newProps, newState) -> newProps.thread.id isnt @props?.thread.id - _shouldDisplayArchiveButton: => - if @props.categoryId not in [CategoryStore.getStandardCategory('archive')?.id, CategoryStore.getStandardCategory('trash')?.id, CategoryStore.getStandardCategory('sent')?.id] - if AccountStore.current().usesLabels() - if @props.thread.labels.length == 1 and (@props.thread.labels[0].name == "archive" or @props.thread.labels[0].name == "all") - return false - return true - else if @props.thread.folders.length == 1 and @props.thread.folders[0].name == "archive" - return false - return true - - return false - - _onTrash: (event) => - params = - thread: @props.thread, - labelsToRemove: [CategoryStore.byId(@props.categoryId)], - labelsToAdd: [CategoryStore.getStandardCategory("trash")] - Actions.queueTask(new ChangeLabelsTask(params)) - # Don't trigger the thread row click - event.stopPropagation() - - - _onForward: (event) => - Actions.composeForward({thread: @props.thread, popout: true}) - # Don't trigger the thread row click - event.stopPropagation() - - _onReply: (event) => - Actions.composeReply({thread: @props.thread, popout: true}) - # Don't trigger the thread row click - event.stopPropagation() - - _onArchive: (event) => - archiveTask = ArchiveThreadHelper.getArchiveTask([@props.thread]) - Actions.queueTask(archiveTask) + _onRemove: (event) => + focusedMailViewFilter = FocusedMailViewStore.mailView() + t = RemoveThreadHelper.getRemovalTask([@props.thread], focusedMailViewFilter) + Actions.queueTask(t) # Don't trigger the thread row click event.stopPropagation() diff --git a/internal_packages/thread-list/lib/thread-list-store.coffee b/internal_packages/thread-list/lib/thread-list-store.coffee index fc6ab0c4c..53d44a5be 100644 --- a/internal_packages/thread-list/lib/thread-list-store.coffee +++ b/internal_packages/thread-list/lib/thread-list-store.coffee @@ -12,7 +12,7 @@ NylasStore = require 'nylas-store' ChangeUnreadTask, ChangeStarredTask, FocusedContentStore, - ArchiveThreadHelper, + RemoveThreadHelper, TaskQueueStatusStore, FocusedMailViewStore} = require 'nylas-exports' @@ -22,14 +22,14 @@ class ThreadListStore extends NylasStore constructor: -> @_resetInstanceVars() - @listenTo Actions.archiveAndPrevious, @_onArchiveAndPrev - @listenTo Actions.archiveAndNext, @_onArchiveAndNext + @listenTo Actions.removeSelection, @_onRemoveSelection - @listenTo Actions.archiveSelection, @_onArchiveSelection - @listenTo Actions.moveThreads, @_onMoveThreads + @listenTo Actions.removeCurrentlyFocusedThread, @_onRemoveAndAuto + @listenTo Actions.removeAndNext, @_onRemoveAndNext + @listenTo Actions.removeAndPrevious, @_onRemoveAndPrev - @listenTo Actions.archive, @_onArchive @listenTo Actions.moveThread, @_onMoveThread + @listenTo Actions.moveThreads, @_onMoveThreads @listenTo Actions.toggleStarSelection, @_onToggleStarSelection @listenTo Actions.toggleStarFocused, @_onToggleStarFocused @@ -158,24 +158,29 @@ class ThreadListStore extends NylasStore task = new ChangeUnreadTask {threads, unread} Actions.queueTask task - _onArchive: -> - @_archiveAndShiftBy('auto') + _onRemoveAndAuto: -> + @_removeAndShiftBy('auto') - _onArchiveAndPrev: -> - @_archiveAndShiftBy(-1) + _onRemoveAndPrev: -> + @_removeAndShiftBy(-1) - _onArchiveAndNext: -> - @_archiveAndShiftBy(1) + _onRemoveAndNext: -> + @_removeAndShiftBy(1) - _archiveAndShiftBy: (offset) -> + _removeAndShiftBy: (offset) -> + mailViewFilter = FocusedMailViewStore.mailView() + return unless mailViewFilter.canApplyToThreads() focused = FocusedContentStore.focused('thread') return unless focused - task = ArchiveThreadHelper.getArchiveTask([focused]) + task = RemoveThreadHelper.getRemovalTask([focused], mailViewFilter) @_moveAndShiftBy(offset, task) - _onArchiveSelection: -> + _onRemoveSelection: -> + mailViewFilter = FocusedMailViewStore.mailView() + return unless mailViewFilter.canApplyToThreads() selectedThreads = @_view.selection.items() - task = ArchiveThreadHelper.getArchiveTask(selectedThreads) + return unless selectedThreads.length > 0 + task = RemoveThreadHelper.getRemovalTask(selectedThreads, mailViewFilter) @_onMoveThreads(selectedThreads, task) _onMoveThread: (thread, task) -> @@ -233,13 +238,13 @@ class ThreadListStore extends NylasStore # Remove the current thread from selection @_view.selection.remove(focused) - # If the user is in list mode and archived without specifically saying - # "archive and next" or "archive and prev", return to the thread list + # If the user is in list mode and removed without specifically saying + # "remove and next" or "remove and prev", return to the thread list # instead of focusing on the next message. if layoutMode is 'list' and not explicitOffset nextFocus = null - # Archive the current thread + # Remove the current thread TaskQueueStatusStore.waitForPerformLocal(task).then => Actions.setFocus(collection: 'thread', item: nextFocus) Actions.setCursorPosition(collection: 'thread', item: nextKeyboard) diff --git a/internal_packages/thread-list/lib/thread-list.cjsx b/internal_packages/thread-list/lib/thread-list.cjsx index 4b73f8e4a..3b2802ede 100644 --- a/internal_packages/thread-list/lib/thread-list.cjsx +++ b/internal_packages/thread-list/lib/thread-list.cjsx @@ -133,8 +133,7 @@ class ThreadList extends React.Component c5 = new ListTabular.Column name: "HoverActions" resolver: (thread) => - currentCategoryId = FocusedMailViewStore.mailView()?.categoryId() - + @wideColumns = [c1, c2, c3, c4, c5] @@ -167,10 +166,10 @@ class ThreadList extends React.Component @narrowColumns = [cNarrow] @commands = - 'core:remove-item': @_onArchive + 'core:remove-item': @_onRemoveItem 'core:star-item': @_onStarItem - 'core:remove-and-previous': -> Actions.archiveAndPrevious() - 'core:remove-and-next': -> Actions.archiveAndNext() + 'core:remove-and-previous': -> Actions.removeAndPrevious() + 'core:remove-and-next': -> Actions.removeAndNext() @itemPropsProvider = (item) -> className: classNames @@ -257,15 +256,15 @@ class ThreadList extends React.Component else Actions.toggleStarFocused() - _onArchive: => + _onRemoveItem: => return unless ThreadListStore.view() if WorkspaceStore.layoutMode() is "list" and WorkspaceStore.topSheet() is WorkspaceStore.Sheet.Thread - Actions.archive() + Actions.removeCurrentlyFocusedThread() else if ThreadListStore.view().selection.count() > 0 - Actions.archiveSelection() + Actions.removeSelection() else - Actions.archive() + Actions.removeCurrentlyFocusedThread() module.exports = ThreadList diff --git a/internal_packages/thread-list/spec/thread-list-spec.cjsx b/internal_packages/thread-list/spec/thread-list-spec.cjsx index 00f0bb498..c2b51a3a8 100644 --- a/internal_packages/thread-list/spec/thread-list-spec.cjsx +++ b/internal_packages/thread-list/spec/thread-list-spec.cjsx @@ -216,9 +216,9 @@ describe "ThreadList", -> spyOn(ThreadStore, "_onAccountChanged") spyOn(DatabaseStore, "findAll").andCallFake -> new Promise (resolve, reject) -> resolve(test_threads()) - spyOn(Actions, "archive") - spyOn(Actions, "archiveAndNext") - spyOn(Actions, "archiveAndPrevious") + spyOn(Actions, "removeCurrentlyFocusedThread") + spyOn(Actions, "removeAndNext") + spyOn(Actions, "removeAndPrevious") ReactTestUtils.spyOnClass(ThreadList, "_prepareColumns").andCallFake -> @_columns = columns diff --git a/spec-nylas/tasks/remove-thread-helper-spec.coffee b/spec-nylas/tasks/remove-thread-helper-spec.coffee new file mode 100644 index 000000000..5c0dfb360 --- /dev/null +++ b/spec-nylas/tasks/remove-thread-helper-spec.coffee @@ -0,0 +1,88 @@ +Account = require '../../src/flux/models/account' +CategoryStore = require '../../src/flux/stores/category-store' +RemoveThreadHelper = require '../../src/services/remove-thread-helper' + +ChangeFolderTask = require '../../src/flux/tasks/change-folder-task' +ChangeLabelsTask = require '../../src/flux/tasks/change-labels-task' + +describe "RemoveThreadHelper", -> + describe "removeType", -> + it "returns null if there's no current account", -> + spyOn(RemoveThreadHelper, "_currentAccount").andReturn null + expect(RemoveThreadHelper.removeType()).toBe null + + it "returns the type if it's saved", -> + spyOn(atom.config, "get").andReturn "trash" + expect(RemoveThreadHelper.removeType()).toBe "trash" + + it "returns the archive category if it exists", -> + spyOn(CategoryStore, "getStandardCategory").andReturn {name: "archive"} + expect(RemoveThreadHelper.removeType()).toBe "archive" + + it "defaults to archive for Gmail", -> + spyOn(RemoveThreadHelper, "_currentAccount").andReturn provider: "gmail" + expect(RemoveThreadHelper.removeType()).toBe "archive" + + it "defaults to trash for everything else", -> + spyOn(RemoveThreadHelper, "_currentAccount").andReturn provider: "eas" + expect(RemoveThreadHelper.removeType()).toBe "trash" + + describe "getRemovalTask", -> + beforeEach -> + spyOn(CategoryStore, "byId").andReturn({id: "inbox-id", name: "inbox"}) + @mailViewFilterStub = categoryId: -> "inbox-id" + @categories = [] + + spyOn(CategoryStore, "getStandardCategory").andCallFake (cat) => + if cat in @categories + return {id: "cat-id", name: cat} + else return null + + afterEach -> + atom.testOrganizationUnit = null + + it "returns null if there's no current account", -> + spyOn(RemoveThreadHelper, "_currentAccount").andReturn null + expect(RemoveThreadHelper.getRemovalTask()).toBe null + + it "creates the task when using labels and trashing", -> + atom.testOrganizationUnit = "label" + spyOn(RemoveThreadHelper, "_currentAccount").andReturn new Account + provider: "eas" + organizationUnit: "label" + @categories = ["all", "trash"] + t = RemoveThreadHelper.getRemovalTask([], @mailViewFilterStub) + expect(t instanceof ChangeLabelsTask).toBe true + expect(t.labelsToRemove[0].name).toBe "inbox" + expect(t.labelsToAdd[0].name).toBe "trash" + + it "creates the task when using labels and archiving", -> + @categories = ["all", "archive", "trash"] + atom.testOrganizationUnit = "label" + spyOn(RemoveThreadHelper, "_currentAccount").andReturn new Account + provider: "gmail" + organizationUnit: "label" + t = RemoveThreadHelper.getRemovalTask([], @mailViewFilterStub) + expect(t instanceof ChangeLabelsTask).toBe true + expect(t.labelsToRemove[0].name).toBe "inbox" + expect(t.labelsToAdd[0].name).toBe "all" + + it "creates the task when using folders and trashing", -> + @categories = ["all", "trash"] + atom.testOrganizationUnit = "folder" + spyOn(RemoveThreadHelper, "_currentAccount").andReturn new Account + provider: "eas" + organizationUnit: "folder" + t = RemoveThreadHelper.getRemovalTask([], @mailViewFilterStub) + expect(t instanceof ChangeFolderTask).toBe true + expect(t.folder.name).toBe "trash" + + it "creates the task when using folders and archiving", -> + @categories = ["all", "archive", "trash"] + atom.testOrganizationUnit = "folder" + spyOn(RemoveThreadHelper, "_currentAccount").andReturn new Account + provider: "gmail" + organizationUnit: "folder" + t = RemoveThreadHelper.getRemovalTask([], @mailViewFilterStub) + expect(t instanceof ChangeFolderTask).toBe true + expect(t.folder.name).toBe "archive" diff --git a/src/components/multiselect-action-bar.cjsx b/src/components/multiselect-action-bar.cjsx index 9be8c4f67..b6e6acabe 100644 --- a/src/components/multiselect-action-bar.cjsx +++ b/src/components/multiselect-action-bar.cjsx @@ -31,7 +31,7 @@ The MultiselectActionBar uses the `ComponentRegistry` to find items to display f collection name. To add an item to the bar created in the example above, register it like this: ```coffee -ComponentRegistry.register ThreadBulkArchiveButton, +ComponentRegistry.register ThreadBulkRemoveButton, role: 'thread:BulkAction' ``` diff --git a/src/flux/actions.coffee b/src/flux/actions.coffee index 877efa1e8..26c3acf37 100644 --- a/src/flux/actions.coffee +++ b/src/flux/actions.coffee @@ -32,7 +32,7 @@ how it propogates between windows. ## Firing Actions ```coffee -Actions.postNotification({message: "Archived Thread", type: 'success'}) +Actions.postNotification({message: "Removed Thread", type: 'success'}) Actions.queueTask(new ChangeStarredTask(thread: @_thread, starred: true)) ``` @@ -305,20 +305,20 @@ class Actions @destroyDraft: ActionScopeWindow ### - Public: Archive the currently focused {Thread}. + Public: Remove the currently focused {Thread}. *Scope: Window* ### - @archive: ActionScopeWindow + @removeCurrentlyFocusedThread: ActionScopeWindow ### - Public: Archives the Thread objects currently selected in the app's main thread list. + Public: Removes the Thread objects currently selected in the app's main thread list. *Scope: Window* ### - @archiveSelection: ActionScopeWindow - @archiveAndNext: ActionScopeWindow - @archiveAndPrevious: ActionScopeWindow + @removeSelection: ActionScopeWindow + @removeAndNext: ActionScopeWindow + @removeAndPrevious: ActionScopeWindow @toggleStarSelection: ActionScopeWindow @toggleStarFocused: ActionScopeWindow @toggleUnreadSelection: ActionScopeWindow @@ -367,7 +367,7 @@ class Actions ``` # A simple notification - Actions.postNotification({message: "Archived Thread", type: 'success'}) + Actions.postNotification({message: "Removed Thread", type: 'success'}) # A sticky notification with actions NOTIF_ACTION_YES = 'YES' diff --git a/src/flux/tasks/archive-thread-helper.coffee b/src/flux/tasks/archive-thread-helper.coffee deleted file mode 100644 index 2bd3be29d..000000000 --- a/src/flux/tasks/archive-thread-helper.coffee +++ /dev/null @@ -1,72 +0,0 @@ -CategoryStore = require '../stores/category-store' -FocusedMailViewStore = require '../stores/focused-mail-view-store' - -ChangeLabelsTask = require './change-labels-task' -ChangeFolderTask = require './change-folder-task' -Actions = require '../actions' - -AccountStore = require '../stores/account-store' - -class ArchiveThreadHelper - - getArchiveTask: (threads) -> - @_getTask(threads, "archive") - - getUnarchiveTask: (threads) -> - @_getTask(threads, "unarchive") - - _getTask: (threads=[], direction) -> - threads = [threads] unless threads instanceof Array - account = AccountStore.current() - return null unless account - - if account.usesFolders() - if direction is "archive" - archiveFolder = CategoryStore.getStandardCategory("archive") - if archiveFolder - return new ChangeFolderTask - folder: archiveFolder - threads: threads - else - # TODO: Implement some sort of UI for people to pick the folder - # they want to use as the Archive. Or better yet, automatically - # add an `Archive` folder first, then move it to there and maybe - # throw up some sort of notifciation. - # - # In the meantime, just throw up a notification so people do it on - # the backend. - Actions.postNotification - type: 'error' - tag: 'noArchive' - sticky: true - message: "You have not created an Archive folder. Please create a folder called 'Archive' with your email provider, restart N1, then try again.", - return null - else if direction is "unarchive" - inboxFolder = CategoryStore.getStandardCategory("inbox") - return new ChangeFolderTask - folder: inboxFolder - threads: threads - - else if account.usesLabels() - viewCategoryId = FocusedMailViewStore.mailView().categoryId() - currentLabel = CategoryStore.byId(viewCategoryId) - currentLabel ?= CategoryStore.getStandardCategory("inbox") - - params = {threads} - if direction is "archive" - params.labelsToRemove = [currentLabel] - else if direction is "unarchive" - params.labelsToAdd = [currentLabel] - - archiveLabel = CategoryStore.getStandardCategory("all") - if archiveLabel - if direction is "archive" - params.labelsToAdd = [archiveLabel] - else if direction is "unarchive" - params.labelsToRemove = [archiveLabel] - - return new ChangeLabelsTask(params) - else - throw new Error("Invalid organizationUnit") - -module.exports = new ArchiveThreadHelper() diff --git a/src/mail-view-filter.coffee b/src/mail-view-filter.coffee index eb6acebcc..3d7174d90 100644 --- a/src/mail-view-filter.coffee +++ b/src/mail-view-filter.coffee @@ -48,10 +48,13 @@ class MailViewFilter canApplyToThreads: -> throw new Error("canApplyToThreads: Not implemented in base class.") + # Whether or not the current MailViewFilter can "archive" or "trash" + canRemoveThreads: -> + throw new Error("canRemoveThreads: Not implemented in base class.") + applyToThreads: (threadsOrIds) -> throw new Error("applyToThreads: Not implemented in base class.") - class SearchMailViewFilter extends MailViewFilter constructor: (@searchQuery) -> @ @@ -65,6 +68,9 @@ class SearchMailViewFilter extends MailViewFilter canApplyToThreads: -> false + canRemoveThreads: -> + false + categoryId: -> null @@ -84,6 +90,9 @@ class StarredMailViewFilter extends MailViewFilter canApplyToThreads: -> true + canRemoveThreads: -> + true + applyToThreads: (threadsOrIds) -> ChangeStarredTask = require './flux/tasks/change-starred-task' task = new ChangeStarredTask({threads:threadsOrIds, starred: true}) @@ -119,6 +128,11 @@ class CategoryMailViewFilter extends MailViewFilter canApplyToThreads: -> not (@category.name in CategoryStore.LockedCategoryNames) + canRemoveThreads: -> + return false if @category.name in ["archive", "trash", "sent", "all"] + return false if @category.displayName is atom.config.get("core.archiveFolder") + return true + applyToThreads: (threadsOrIds) -> if AccountStore.current().usesLabels() FocusedMailViewStore = require './flux/stores/focused-mail-view-store' diff --git a/src/services/remove-thread-helper.coffee b/src/services/remove-thread-helper.coffee new file mode 100644 index 000000000..814a80239 --- /dev/null +++ b/src/services/remove-thread-helper.coffee @@ -0,0 +1,93 @@ +_ = require 'underscore' +CategoryStore = require '../stores/category-store' + +ChangeLabelsTask = require './change-labels-task' +ChangeFolderTask = require './change-folder-task' +Actions = require '../actions' + +AccountStore = require '../stores/account-store' + +class RemoveThreadHelper + + Type: + Trash: "trash" + Archive: "archive" + + removeType: -> + currentAccount = @_currentAccount() + return null unless currentAccount + savedType = atom.config.get("core.#{currentAccount.id}.removeType") + return savedType if savedType + + archiveCategory = CategoryStore.getStandardCategory("archive") + return @Type.Archive if archiveCategory + + if currentAccount.provider is "gmail" + return @Type.Archive + else + return @Type.Trash + + _currentAccount: -> AccountStore.current() # To stub in testing + + # In the case of folders, "removing" means moving the message to a + # particular folder + removalFolder: -> + if @removeType() is @Type.Trash + CategoryStore.getStandardCategory("trash") + else if @removeType() is @Type.Archive + CategoryStore.getStandardCategory("archive") + + # In the case of labels, "removing" means removing the current label and + # applying a new label indicating it's in the "removed" state. + removalLabelToAdd: -> + if @removeType() is @Type.Trash + CategoryStore.getStandardCategory("trash") + else if @removeType() is @Type.Archive + CategoryStore.getStandardCategory("all") + + getRemovalTask: (threads=[], focusedMailViewFilter) -> + threads = [threads] unless threads instanceof Array + account = @_currentAccount() + return null unless account + + if account.usesFolders() + removalFolder = @removalFolder() + if removalFolder + return new ChangeFolderTask + folder: removalFolder + threads: threads + else + @_notifyFolderRemovalError() + return null + + else if account.usesLabels() + viewCategoryId = focusedMailViewFilter.categoryId() + currentLabel = CategoryStore.byId(viewCategoryId) + currentLabel ?= CategoryStore.getStandardCategory("inbox") + + params = {threads} + params.labelsToRemove = [currentLabel] + + removalLabelToAdd = @removalLabelToAdd() + if removalLabelToAdd + params.labelsToAdd = [removalLabelToAdd] + + return new ChangeLabelsTask(params) + else + throw new Error("Invalid organizationUnit") + + _notifyFolderRemovalError: -> + # In the onboarding flow, users should have already created their + # Removal folder. This should only happen for legacy users or if + # there's an error somewhere. + if @removeType() is @Type.Trash + msg = "There is no Trash folder. Please create a folder called 'Trash' and try again." + else if @removeType() is @Type.Archive + msg = "We can't archive your messages because you have no 'Archive' folder. Please create a folder called 'Archive' and try again" + Actions.postNotification + type: 'error' + tag: 'noRemovalFolder' + sticky: true + message: msg + +module.exports = new RemoveThreadHelper() diff --git a/static/images/toolbar/toolbar-trash@2x.png b/static/images/toolbar/toolbar-trash@2x.png index d1d998924d7d87bcce6eb3a5edb27449e2bf7209..6506eae0607763e7f3acb2d02e62b5ddfd1c28cb 100644 GIT binary patch delta 584 zcmcb~eUVGCGr-TCmrII^fq{Y7)59eQNb7(w2OE%-Yl&imn%#QVY{MeKj7#Pbv zT^vIyZoP>-$k(jEv$cDArO5NloB#grFAMr&QC>XbN{hja(g33?YQ3C>U*3MK2w{6{ zk*0Z6(_3c}^PKh>EDRpIf<6VWcY3CLxYlURh|LWJi6;6cfOT5JGm@ye?7msLW9iH>W-@VTYvKA!k+;&gY`l0XeZ0GEyetk?kwi~W# zls)Tf6umI_&c=l&CjAiSoz7+%$uWI}B;$1%y+F4D&Yj+#9@D*9dKR#^_Z%n?4HELN zpW1wC^QokR{`HnNTyv@qL^m+%l#-$ue;d_&S&H{H9zbN6l%)K z%w{m}nY2T~ben2t%~BPXr-u%I?R+euZyDRPm~oY5%p&irsxDd$w>k6_o%446?AdR0 zk7cjNb{Fs7o^OpOYg1XL9OLTSznAX-`-2@H#l#XA0&Gv1Jo7%z4NM#ip00i_>zopr E03Y+>-T(jq delta 651 zcmV;60(AY+3fT)GiBL{Q4GJ0x0000DNk~Le0000m0000m2nGNE09OL}hmj#D0eF#0 zk{~fOAU8QKF*PSR2AZ^q-c zERN$wnWfn%xwK>-FvfDfWcQ$Vr)mG>;og7GGf>8qmZgO_)O_x=a0-86^@j$JUyxBq zQ@UtR8Dn{W7$+U}Pz* z+8CD}zdeT05!WZR{u$R_LO