mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-03-09 06:23:30 +08:00
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
This commit is contained in:
parent
b1724b9e47
commit
f88b0f3708
17 changed files with 316 additions and 204 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: =>
|
||||
<button className="btn btn-toolbar btn-archive"
|
||||
style={order: -106}
|
||||
data-tooltip="Archive"
|
||||
onClick={@_onArchive}>
|
||||
<RetinaImg name="toolbar-archive.png" mode={RetinaImg.Mode.ContentIsMask}/>
|
||||
</button>
|
||||
|
||||
_onArchive: (e) =>
|
||||
return unless DOMUtils.nodeIsVisible(e.currentTarget)
|
||||
Actions.archive()
|
||||
e.stopPropagation()
|
||||
|
||||
|
||||
module.exports = ThreadArchiveButton
|
37
internal_packages/message-list/lib/thread-remove-button.cjsx
Normal file
37
internal_packages/message-list/lib/thread-remove-button.cjsx
Normal file
|
@ -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"
|
||||
|
||||
<button className="btn btn-toolbar"
|
||||
style={order: -106}
|
||||
data-tooltip={tooltip}
|
||||
onClick={@_onRemove}>
|
||||
<RetinaImg name={imgName} mode={RetinaImg.Mode.ContentIsMask}/>
|
||||
</button>
|
||||
|
||||
_onRemove: (e) =>
|
||||
return unless DOMUtils.nodeIsVisible(e.currentTarget)
|
||||
Actions.removeCurrentlyFocusedThread()
|
||||
e.stopPropagation()
|
||||
|
||||
|
||||
module.exports = ThreadRemoveButton
|
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
||||
<button style={order:-106}
|
||||
className="btn btn-toolbar"
|
||||
data-tooltip="Archive"
|
||||
onClick={@_onArchive}>
|
||||
<RetinaImg name="toolbar-archive.png" mode={RetinaImg.Mode.ContentIsMask} />
|
||||
data-tooltip={tooltip}
|
||||
onClick={@_onRemove}>
|
||||
<RetinaImg name={imgName} mode={RetinaImg.Mode.ContentIsMask} />
|
||||
</button>
|
||||
|
||||
_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}
|
||||
|
|
|
@ -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 <div key="archive" className="btn action action-archive" onClick={@_onArchive}></div>
|
||||
else if AccountStore.current().usesLabels() and @props.categoryId == CategoryStore.getStandardCategory('all').id
|
||||
actions.push <div key="trash" className="btn action action-trash" onClick={@_onTrash}></div>
|
||||
focusedMailViewFilter = FocusedMailViewStore.mailView()
|
||||
return false unless focusedMailViewFilter?.canRemoveThreads()
|
||||
|
||||
return false if actions.length is 0
|
||||
classNames = "btn action action-#{RemoveThreadHelper.removeType()}"
|
||||
|
||||
<div className="inner">
|
||||
{actions}
|
||||
<div key="remove" className={classNames} onClick={@_onRemove}></div>
|
||||
</div>
|
||||
|
||||
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()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -133,8 +133,7 @@ class ThreadList extends React.Component
|
|||
c5 = new ListTabular.Column
|
||||
name: "HoverActions"
|
||||
resolver: (thread) =>
|
||||
currentCategoryId = FocusedMailViewStore.mailView()?.categoryId()
|
||||
<ThreadListQuickActions thread={thread} categoryId={currentCategoryId}/>
|
||||
<ThreadListQuickActions thread={thread} />
|
||||
|
||||
@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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
88
spec-nylas/tasks/remove-thread-helper-spec.coffee
Normal file
88
spec-nylas/tasks/remove-thread-helper-spec.coffee
Normal file
|
@ -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"
|
|
@ -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'
|
||||
```
|
||||
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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()
|
|
@ -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'
|
||||
|
|
93
src/services/remove-thread-helper.coffee
Normal file
93
src/services/remove-thread-helper.coffee
Normal file
|
@ -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()
|
Binary file not shown.
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.3 KiB |
Loading…
Reference in a new issue