mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-12-11 23:16:13 +08:00
feat(archive): archive now pops back to thread list
Summary: add spec for message toolbar items add thread list spec Test Plan: edgehill --test Reviewers: bengotow Reviewed By: bengotow Differential Revision: https://review.inboxapp.com/D1344
This commit is contained in:
parent
79ad424849
commit
dc5941f3f1
14 changed files with 194 additions and 46 deletions
|
|
@ -30,9 +30,19 @@ AccountSidebarStore = Reflux.createStore
|
||||||
|
|
||||||
_registerListeners: ->
|
_registerListeners: ->
|
||||||
@listenTo Actions.selectTagId, @_onSelectTagId
|
@listenTo Actions.selectTagId, @_onSelectTagId
|
||||||
|
@listenTo Actions.searchQueryCommitted, @_onSearchQueryCommitted
|
||||||
@listenTo DatabaseStore, @_onDataChanged
|
@listenTo DatabaseStore, @_onDataChanged
|
||||||
@listenTo NamespaceStore, @_onNamespaceChanged
|
@listenTo NamespaceStore, @_onNamespaceChanged
|
||||||
|
|
||||||
|
_onSearchQueryCommitted: (query) ->
|
||||||
|
if query? and query isnt ""
|
||||||
|
@_oldSelectedId = @_selectedId
|
||||||
|
@_selectedId = "search"
|
||||||
|
else
|
||||||
|
@_selectedId = @_oldSelectedId if @_oldSelectedId
|
||||||
|
|
||||||
|
@trigger(@)
|
||||||
|
|
||||||
_populate: ->
|
_populate: ->
|
||||||
namespace = NamespaceStore.current()
|
namespace = NamespaceStore.current()
|
||||||
return unless namespace
|
return unless namespace
|
||||||
|
|
@ -116,6 +126,7 @@ AccountSidebarStore = Reflux.createStore
|
||||||
@_populateDraftsCount()
|
@_populateDraftsCount()
|
||||||
|
|
||||||
_onSelectTagId: (tagId) ->
|
_onSelectTagId: (tagId) ->
|
||||||
|
Actions.searchQueryCommitted('') if @_selectedId is "search"
|
||||||
@_selectedId = tagId
|
@_selectedId = tagId
|
||||||
@trigger(@)
|
@trigger(@)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
React = require 'react'
|
React = require 'react'
|
||||||
{Actions, ThreadStore, Utils} = require 'inbox-exports'
|
{Actions, ThreadStore, Utils, WorkspaceStore} = require 'inbox-exports'
|
||||||
{RetinaImg} = require 'ui-components'
|
{RetinaImg} = require 'ui-components'
|
||||||
|
|
||||||
# Note: These always have a thread, but only sometimes get a
|
# Note: These always have a thread, but only sometimes get a
|
||||||
|
|
@ -46,7 +46,7 @@ ForwardButton = React.createClass
|
||||||
|
|
||||||
ArchiveButton = React.createClass
|
ArchiveButton = React.createClass
|
||||||
render: ->
|
render: ->
|
||||||
<button className="btn btn-toolbar"
|
<button className="btn btn-toolbar btn-archive"
|
||||||
data-tooltip="Archive"
|
data-tooltip="Archive"
|
||||||
onClick={@_onArchive}>
|
onClick={@_onArchive}>
|
||||||
<RetinaImg name="toolbar-archive.png" />
|
<RetinaImg name="toolbar-archive.png" />
|
||||||
|
|
@ -54,13 +54,15 @@ ArchiveButton = React.createClass
|
||||||
|
|
||||||
_onArchive: (e) ->
|
_onArchive: (e) ->
|
||||||
return unless Utils.nodeIsVisible(e.currentTarget)
|
return unless Utils.nodeIsVisible(e.currentTarget)
|
||||||
# Calling archive() sends an Actions.queueTask with an archive task
|
if WorkspaceStore.selectedLayoutMode() is "list"
|
||||||
# TODO Turn into an Action
|
Actions.archiveCurrentThread()
|
||||||
ThreadStore.selectedThread().archive()
|
else if WorkspaceStore.selectedLayoutMode() is "split"
|
||||||
|
Actions.archiveAndNext()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
|
||||||
|
|
||||||
module.exports = React.createClass
|
module.exports =
|
||||||
|
MessageToolbarItems = React.createClass
|
||||||
getInitialState: ->
|
getInitialState: ->
|
||||||
threadIsSelected: ThreadStore.selectedId()?
|
threadIsSelected: ThreadStore.selectedId()?
|
||||||
|
|
||||||
|
|
@ -70,7 +72,7 @@ module.exports = React.createClass
|
||||||
"hidden": !@state.threadIsSelected
|
"hidden": !@state.threadIsSelected
|
||||||
|
|
||||||
<div className={classes}>
|
<div className={classes}>
|
||||||
<ArchiveButton />
|
<ArchiveButton ref="archiveButton" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
componentDidMount: ->
|
componentDidMount: ->
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
React = require 'react/addons'
|
||||||
|
ReactTestUtils = React.addons.TestUtils
|
||||||
|
MessageToolbarItems = require "../lib/message-toolbar-items.cjsx"
|
||||||
|
{WorkspaceStore, Actions} = require 'inbox-exports'
|
||||||
|
|
||||||
|
describe "MessageToolbarItems", ->
|
||||||
|
beforeEach ->
|
||||||
|
@toolbarItems = ReactTestUtils.renderIntoDocument(<MessageToolbarItems />)
|
||||||
|
@archiveButton = @toolbarItems.refs["archiveButton"]
|
||||||
|
spyOn(Actions, "archiveAndNext")
|
||||||
|
spyOn(Actions, "archiveCurrentThread")
|
||||||
|
|
||||||
|
it "renders the archive button", ->
|
||||||
|
btns = ReactTestUtils.scryRenderedDOMComponentsWithClass(@toolbarItems, "btn-archive")
|
||||||
|
expect(btns.length).toBe 1
|
||||||
|
|
||||||
|
it "archives and next in split mode", ->
|
||||||
|
spyOn(WorkspaceStore, "selectedLayoutMode").andReturn "split"
|
||||||
|
ReactTestUtils.Simulate.click(@archiveButton.getDOMNode())
|
||||||
|
expect(Actions.archiveCurrentThread).not.toHaveBeenCalled()
|
||||||
|
expect(Actions.archiveAndNext).toHaveBeenCalled()
|
||||||
|
|
||||||
|
it "archives in list mode", ->
|
||||||
|
spyOn(WorkspaceStore, "selectedLayoutMode").andReturn "list"
|
||||||
|
ReactTestUtils.Simulate.click(@archiveButton.getDOMNode())
|
||||||
|
expect(Actions.archiveCurrentThread).toHaveBeenCalled()
|
||||||
|
expect(Actions.archiveAndNext).not.toHaveBeenCalled()
|
||||||
|
|
@ -307,7 +307,7 @@
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
.sidebar-thread-participants {
|
.sidebar-thread-participants {
|
||||||
padding: @spacing-standard;
|
padding: @spacing-standard;
|
||||||
order: 10;
|
order: 2;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
||||||
.other-contact {
|
.other-contact {
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
border:none;
|
border:none;
|
||||||
|
|
||||||
input {
|
input {
|
||||||
|
padding-top: 3.5px;
|
||||||
padding-left:30px;
|
padding-left:30px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 30px;
|
height: 30px;
|
||||||
|
|
@ -66,6 +67,10 @@
|
||||||
|
|
||||||
&.showing-suggestions {
|
&.showing-suggestions {
|
||||||
.suggestions { display: inherit; }
|
.suggestions { display: inherit; }
|
||||||
|
.clear {
|
||||||
|
color: @input-accessory-color;
|
||||||
|
display: inherit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&.showing-query {
|
&.showing-query {
|
||||||
.clear { display: inherit; }
|
.clear { display: inherit; }
|
||||||
|
|
@ -82,8 +87,8 @@
|
||||||
|
|
||||||
&.clear {
|
&.clear {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: floor(40px - 26px)/2;
|
top: floor(40px - 26px)/2 - 1px;
|
||||||
color: @input-accessory-color;
|
color: @input-cancel-color;
|
||||||
right: @padding-base-horizontal;
|
right: @padding-base-horizontal;
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
.internal-sidebar {
|
.internal-sidebar {
|
||||||
padding: @spacing-standard;
|
padding: @spacing-standard;
|
||||||
padding-bottom: 0;
|
padding-bottom: 0;
|
||||||
order: 2;
|
order: 4;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
|
|
||||||
a{text-decoration: none}
|
a{text-decoration: none}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
_ = require 'underscore-plus'
|
_ = require 'underscore-plus'
|
||||||
React = require 'react'
|
React = require 'react'
|
||||||
{ListTabular} = require 'ui-components'
|
{ListTabular, Spinner} = require 'ui-components'
|
||||||
{timestamp, subject} = require './formatting-utils'
|
{timestamp, subject} = require './formatting-utils'
|
||||||
{Actions, ThreadStore, ComponentRegistry} = require 'inbox-exports'
|
{Actions,
|
||||||
|
ThreadStore,
|
||||||
|
WorkspaceStore,
|
||||||
|
ComponentRegistry} = require 'inbox-exports'
|
||||||
|
|
||||||
module.exports =
|
module.exports =
|
||||||
ThreadList = React.createClass
|
ThreadList = React.createClass
|
||||||
|
|
@ -23,8 +26,9 @@ ThreadList = React.createClass
|
||||||
'application:previous-item': => @_onShiftSelectedIndex(-1)
|
'application:previous-item': => @_onShiftSelectedIndex(-1)
|
||||||
'application:next-item': => @_onShiftSelectedIndex(1)
|
'application:next-item': => @_onShiftSelectedIndex(1)
|
||||||
'application:focus-item': => @_onFocusSelectedIndex()
|
'application:focus-item': => @_onFocusSelectedIndex()
|
||||||
'application:remove-item': @_onArchiveSelected
|
'application:remove-item': @_onArchiveCurrentThread
|
||||||
'application:remove-and-previous': @_onArchiveAndPrevious
|
'application:remove-and-previous': -> Actions.archiveAndPrevious()
|
||||||
|
'application:remove-and-next': -> Actions.archiveAndNext()
|
||||||
'application:reply': @_onReply
|
'application:reply': @_onReply
|
||||||
'application:reply-all': @_onReplyAll
|
'application:reply-all': @_onReplyAll
|
||||||
'application:forward': @_onForward
|
'application:forward': @_onForward
|
||||||
|
|
@ -36,13 +40,15 @@ ThreadList = React.createClass
|
||||||
@body_unsubscriber.dispose()
|
@body_unsubscriber.dispose()
|
||||||
|
|
||||||
render: ->
|
render: ->
|
||||||
<div className="thread-list">
|
classes = React.addons.classSet("thread-list": true, "ready": @state.ready)
|
||||||
|
<div className={classes}>
|
||||||
<ListTabular
|
<ListTabular
|
||||||
columns={@state.columns}
|
columns={@state.columns}
|
||||||
items={@state.items}
|
items={@state.items}
|
||||||
itemClassProvider={ (item) -> if item.isUnread() then 'unread' else '' }
|
itemClassProvider={ (item) -> if item.isUnread() then 'unread' else '' }
|
||||||
selectedId={@state.selectedId}
|
selectedId={@state.selectedId}
|
||||||
onSelect={ (item) -> Actions.selectThreadId(item.id) } />
|
onSelect={ (item) -> Actions.selectThreadId(item.id) } />
|
||||||
|
<Spinner visible={!@state.ready} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
_computeColumns: ->
|
_computeColumns: ->
|
||||||
|
|
@ -106,34 +112,38 @@ ThreadList = React.createClass
|
||||||
index = Math.max(0, Math.min(index + delta, @state.items.length-1))
|
index = Math.max(0, Math.min(index + delta, @state.items.length-1))
|
||||||
Actions.selectThreadId(@state.items[index].id)
|
Actions.selectThreadId(@state.items[index].id)
|
||||||
|
|
||||||
_onArchiveSelected: ->
|
|
||||||
thread = ThreadStore.selectedThread()
|
|
||||||
thread.archive() if thread
|
|
||||||
|
|
||||||
_onStarThread: ->
|
_onStarThread: ->
|
||||||
thread = ThreadStore.selectedThread()
|
thread = ThreadStore.selectedThread()
|
||||||
thread.toggleStar() if thread
|
thread.toggleStar() if thread
|
||||||
|
|
||||||
_onReply: ->
|
_onReply: ->
|
||||||
return unless @state.selectedId?
|
return unless @state.selectedId? and @_actionInVisualScope()
|
||||||
Actions.composeReply(threadId: @state.selectedId)
|
Actions.composeReply(threadId: @state.selectedId)
|
||||||
|
|
||||||
_onReplyAll: ->
|
_onReplyAll: ->
|
||||||
return unless @state.selectedId?
|
return unless @state.selectedId? and @_actionInVisualScope()
|
||||||
Actions.composeReplyAll(threadId: @state.selectedId)
|
Actions.composeReplyAll(threadId: @state.selectedId)
|
||||||
|
|
||||||
_onForward: ->
|
_onForward: ->
|
||||||
return unless @state.selectedId?
|
return unless @state.selectedId? and @_actionInVisualScope()
|
||||||
Actions.composeForward(threadId: @state.selectedId)
|
Actions.composeForward(threadId: @state.selectedId)
|
||||||
|
|
||||||
|
_actionInVisualScope: ->
|
||||||
|
if WorkspaceStore.selectedLayoutMode() is "list"
|
||||||
|
WorkspaceStore.sheet().type is "Thread"
|
||||||
|
else true
|
||||||
|
|
||||||
|
_onArchiveCurrentThread: ->
|
||||||
|
if WorkspaceStore.selectedLayoutMode() is "list"
|
||||||
|
Actions.archiveCurrentThread()
|
||||||
|
else if WorkspaceStore.selectedLayoutMode() is "split"
|
||||||
|
Actions.archiveAndNext()
|
||||||
|
|
||||||
_onChange: ->
|
_onChange: ->
|
||||||
@setState(@_getStateFromStores())
|
@setState(@_getStateFromStores())
|
||||||
|
|
||||||
_onArchiveAndPrevious: ->
|
|
||||||
@_onArchiveSelected()
|
|
||||||
@_onShiftSelectedIndex(-1)
|
|
||||||
|
|
||||||
_getStateFromStores: ->
|
_getStateFromStores: ->
|
||||||
|
ready: not ThreadStore.itemsLoading()
|
||||||
items: ThreadStore.items()
|
items: ThreadStore.items()
|
||||||
columns: @_computeColumns()
|
columns: @_computeColumns()
|
||||||
selectedId: ThreadStore.selectedId()
|
selectedId: ThreadStore.selectedId()
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ ReactTestUtils = _.extend ReactTestUtils, require "jasmine-react-helpers"
|
||||||
Namespace,
|
Namespace,
|
||||||
ThreadStore,
|
ThreadStore,
|
||||||
DatabaseStore,
|
DatabaseStore,
|
||||||
|
WorkspaceStore,
|
||||||
InboxTestUtils,
|
InboxTestUtils,
|
||||||
NamespaceStore,
|
NamespaceStore,
|
||||||
ComponentRegistry} = require "inbox-exports"
|
ComponentRegistry} = require "inbox-exports"
|
||||||
|
|
@ -212,6 +213,9 @@ describe "ThreadList", ->
|
||||||
spyOn(ThreadStore, "_onNamespaceChanged")
|
spyOn(ThreadStore, "_onNamespaceChanged")
|
||||||
spyOn(DatabaseStore, "findAll").andCallFake ->
|
spyOn(DatabaseStore, "findAll").andCallFake ->
|
||||||
new Promise (resolve, reject) -> resolve(test_threads())
|
new Promise (resolve, reject) -> resolve(test_threads())
|
||||||
|
spyOn(Actions, "archiveCurrentThread")
|
||||||
|
spyOn(Actions, "archiveAndNext")
|
||||||
|
spyOn(Actions, "archiveAndPrevious")
|
||||||
ReactTestUtils.spyOnClass(ThreadList, "_computeColumns").andReturn(columns)
|
ReactTestUtils.spyOnClass(ThreadList, "_computeColumns").andReturn(columns)
|
||||||
|
|
||||||
ThreadStore._resetInstanceVars()
|
ThreadStore._resetInstanceVars()
|
||||||
|
|
@ -240,6 +244,47 @@ describe "ThreadList", ->
|
||||||
items = ReactTestUtils.scryRenderedComponentsWithType(@thread_list, ListTabular.Item)
|
items = ReactTestUtils.scryRenderedComponentsWithType(@thread_list, ListTabular.Item)
|
||||||
expect(items.length).toBe 0
|
expect(items.length).toBe 0
|
||||||
|
|
||||||
|
describe "when the workspace is in list mode", ->
|
||||||
|
beforeEach ->
|
||||||
|
spyOn(WorkspaceStore, "selectedLayoutMode").andReturn "list"
|
||||||
|
@thread_list.setState selectedId: "t111"
|
||||||
|
|
||||||
|
it "archives in list mode", ->
|
||||||
|
@thread_list._onArchiveCurrentThread()
|
||||||
|
expect(Actions.archiveCurrentThread).toHaveBeenCalled()
|
||||||
|
expect(Actions.archiveAndNext).not.toHaveBeenCalled()
|
||||||
|
|
||||||
|
it "allows reply only when the sheet type is 'Thread'", ->
|
||||||
|
spyOn(WorkspaceStore, "sheet").andCallFake -> {type: "Thread"}
|
||||||
|
spyOn(Actions, "composeReply")
|
||||||
|
@thread_list._onReply()
|
||||||
|
expect(Actions.composeReply).toHaveBeenCalled()
|
||||||
|
expect(@thread_list._actionInVisualScope()).toBe true
|
||||||
|
|
||||||
|
it "doesn't reply only when the sheet type isnt 'Thread'", ->
|
||||||
|
spyOn(WorkspaceStore, "sheet").andCallFake -> {type: "Root"}
|
||||||
|
spyOn(Actions, "composeReply")
|
||||||
|
@thread_list._onReply()
|
||||||
|
expect(Actions.composeReply).not.toHaveBeenCalled()
|
||||||
|
expect(@thread_list._actionInVisualScope()).toBe false
|
||||||
|
|
||||||
|
describe "when the workspace is in split mode", ->
|
||||||
|
beforeEach ->
|
||||||
|
spyOn(WorkspaceStore, "selectedLayoutMode").andReturn "split"
|
||||||
|
@thread_list.setState selectedId: "t111"
|
||||||
|
|
||||||
|
it "archives and next in split mode", ->
|
||||||
|
@thread_list._onArchiveCurrentThread()
|
||||||
|
expect(Actions.archiveCurrentThread).not.toHaveBeenCalled()
|
||||||
|
expect(Actions.archiveAndNext).toHaveBeenCalled()
|
||||||
|
|
||||||
|
it "allows reply and reply-all regardless of sheet type", ->
|
||||||
|
spyOn(WorkspaceStore, "sheet").andCallFake -> {type: "anything"}
|
||||||
|
spyOn(Actions, "composeReply")
|
||||||
|
@thread_list._onReply()
|
||||||
|
expect(Actions.composeReply).toHaveBeenCalled()
|
||||||
|
expect(@thread_list._actionInVisualScope()).toBe true
|
||||||
|
|
||||||
describe "Populated thread list", ->
|
describe "Populated thread list", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
ThreadStore._items = test_threads()
|
ThreadStore._items = test_threads()
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@
|
||||||
'j' : 'application:next-item' # Gmail
|
'j' : 'application:next-item' # Gmail
|
||||||
'down' : 'application:next-item' # Mac mail
|
'down' : 'application:next-item' # Mac mail
|
||||||
']' : 'application:remove-and-previous' # Gmail
|
']' : 'application:remove-and-previous' # Gmail
|
||||||
'[' : 'application:remove-item' # Gmail
|
'[' : 'application:remove-and-next' # Gmail
|
||||||
'e' : 'application:remove-item' # Gmail
|
'e' : 'application:remove-item' # Gmail
|
||||||
'delete' : 'application:remove-item' # Mac mail
|
'delete' : 'application:remove-item' # Mac mail
|
||||||
'backspace': 'application:remove-item' # Outlook
|
'backspace': 'application:remove-item' # Outlook
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
'/' : 'application:focus-search' # Gmail
|
'/' : 'application:focus-search' # Gmail
|
||||||
|
|
||||||
'r' : 'application:reply' # Gmail
|
'r' : 'application:reply' # Gmail
|
||||||
|
'R' : 'application:reply-all' # Edgehill
|
||||||
'a' : 'application:reply-all' # Gmail
|
'a' : 'application:reply-all' # Gmail
|
||||||
'f' : 'application:forward' # Gmail
|
'f' : 'application:forward' # Gmail
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -70,6 +70,10 @@ windowActions = [
|
||||||
"sendDraft",
|
"sendDraft",
|
||||||
"destroyDraft",
|
"destroyDraft",
|
||||||
|
|
||||||
|
"archiveAndPrevious",
|
||||||
|
"archiveCurrentThread",
|
||||||
|
"archiveAndNext",
|
||||||
|
|
||||||
# Actions for Search
|
# Actions for Search
|
||||||
"searchQueryChanged",
|
"searchQueryChanged",
|
||||||
"searchQueryCommitted",
|
"searchQueryCommitted",
|
||||||
|
|
|
||||||
|
|
@ -232,8 +232,8 @@ class InboxAPI
|
||||||
# API abstraction should not need to know about threads and calendars.
|
# API abstraction should not need to know about threads and calendars.
|
||||||
# They're still here because of their dependency in
|
# They're still here because of their dependency in
|
||||||
# _postLaunchStartStreaming
|
# _postLaunchStartStreaming
|
||||||
getThreads: (namespaceId, params) ->
|
getThreads: (namespaceId, params, requestOptions={}) ->
|
||||||
@getCollection(namespaceId, 'threads', params)
|
@getCollection(namespaceId, 'threads', params, requestOptions)
|
||||||
|
|
||||||
getCalendars: (namespaceId) ->
|
getCalendars: (namespaceId) ->
|
||||||
@getCollection(namespaceId, 'calendars', {})
|
@getCollection(namespaceId, 'calendars', {})
|
||||||
|
|
|
||||||
|
|
@ -61,11 +61,6 @@ class Thread extends Model
|
||||||
isStarred: ->
|
isStarred: ->
|
||||||
@tagIds().indexOf('starred') != -1
|
@tagIds().indexOf('starred') != -1
|
||||||
|
|
||||||
markAsRead: ->
|
|
||||||
MarkThreadReadTask = require '../tasks/mark-thread-read'
|
|
||||||
task = new MarkThreadReadTask(@id)
|
|
||||||
Actions.queueTask(task)
|
|
||||||
|
|
||||||
star: ->
|
star: ->
|
||||||
@addRemoveTags(['starred'], [])
|
@addRemoveTags(['starred'], [])
|
||||||
|
|
||||||
|
|
@ -78,13 +73,6 @@ class Thread extends Model
|
||||||
else
|
else
|
||||||
@star()
|
@star()
|
||||||
|
|
||||||
archive: ->
|
|
||||||
Actions.postNotification({message: "Archived thread", type: 'success'})
|
|
||||||
@addRemoveTags(['archive'], ['inbox'])
|
|
||||||
|
|
||||||
unarchive: ->
|
|
||||||
@addRemoveTags(['inbox'], ['archive'])
|
|
||||||
|
|
||||||
addRemoveTags: (tagIdsToAdd, tagIdsToRemove) ->
|
addRemoveTags: (tagIdsToAdd, tagIdsToRemove) ->
|
||||||
# start web change, which will dispatch more actions
|
# start web change, which will dispatch more actions
|
||||||
AddRemoveTagsTask = require '../tasks/add-remove-tags'
|
AddRemoveTagsTask = require '../tasks/add-remove-tags'
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
Reflux = require 'reflux'
|
Reflux = require 'reflux'
|
||||||
DatabaseStore = require './database-store'
|
DatabaseStore = require './database-store'
|
||||||
NamespaceStore = require './namespace-store'
|
NamespaceStore = require './namespace-store'
|
||||||
|
AddRemoveTagsTask = require '../tasks/add-remove-tags'
|
||||||
|
MarkThreadReadTask = require '../tasks/mark-thread-read'
|
||||||
Actions = require '../actions'
|
Actions = require '../actions'
|
||||||
Thread = require '../models/thread'
|
Thread = require '../models/thread'
|
||||||
_ = require 'underscore-plus'
|
_ = require 'underscore-plus'
|
||||||
|
|
@ -11,6 +13,9 @@ ThreadStore = Reflux.createStore
|
||||||
|
|
||||||
@listenTo Actions.selectThreadId, @_onSelectThreadId
|
@listenTo Actions.selectThreadId, @_onSelectThreadId
|
||||||
@listenTo Actions.selectTagId, @_onSelectTagId
|
@listenTo Actions.selectTagId, @_onSelectTagId
|
||||||
|
@listenTo Actions.archiveAndPrevious, @_onArchiveAndPrevious
|
||||||
|
@listenTo Actions.archiveCurrentThread, @_onArchiveCurrentThread
|
||||||
|
@listenTo Actions.archiveAndNext, @_onArchiveAndNext
|
||||||
@listenTo Actions.searchQueryCommitted, @_onSearchCommitted
|
@listenTo Actions.searchQueryCommitted, @_onSearchCommitted
|
||||||
@listenTo DatabaseStore, @_onDataChanged
|
@listenTo DatabaseStore, @_onDataChanged
|
||||||
@listenTo NamespaceStore, -> @_onNamespaceChanged()
|
@listenTo NamespaceStore, -> @_onNamespaceChanged()
|
||||||
|
|
@ -23,6 +28,9 @@ ThreadStore = Reflux.createStore
|
||||||
@_namespaceId = null
|
@_namespaceId = null
|
||||||
@_tagId = null
|
@_tagId = null
|
||||||
@_searchQuery = null
|
@_searchQuery = null
|
||||||
|
@_itemsLoading = false
|
||||||
|
|
||||||
|
itemsLoading: -> @_itemsLoading
|
||||||
|
|
||||||
fetchFromCache: ->
|
fetchFromCache: ->
|
||||||
return unless @_namespaceId
|
return unless @_namespaceId
|
||||||
|
|
@ -56,16 +64,26 @@ ThreadStore = Reflux.createStore
|
||||||
newSelectedId = null
|
newSelectedId = null
|
||||||
Actions.selectThreadId(newSelectedId)
|
Actions.selectThreadId(newSelectedId)
|
||||||
|
|
||||||
|
@_itemsLoading = false
|
||||||
@trigger()
|
@trigger()
|
||||||
|
|
||||||
fetchFromAPI: ->
|
fetchFromAPI: ->
|
||||||
return unless @_namespaceId
|
return unless @_namespaceId
|
||||||
|
@_itemsLoading = true
|
||||||
if @_searchQuery
|
if @_searchQuery
|
||||||
atom.inbox.getThreadsForSearch @_namespaceId, @_searchQuery, (items) =>
|
atom.inbox.getThreadsForSearch @_namespaceId, @_searchQuery, (items) =>
|
||||||
@_items = items
|
@_items = items
|
||||||
|
@_itemsLoading = false
|
||||||
@trigger()
|
@trigger()
|
||||||
else
|
else
|
||||||
atom.inbox.getThreads(@_namespaceId, {tag: @_tagId})
|
success = =>
|
||||||
|
@_itemsLoading = false
|
||||||
|
@trigger()
|
||||||
|
error = =>
|
||||||
|
@_itemsLoading = false
|
||||||
|
@trigger()
|
||||||
|
atom.inbox.getThreads(@_namespaceId, {tag: @_tagId}, {success: success, error: error})
|
||||||
|
@trigger()
|
||||||
|
|
||||||
# Inbound Events
|
# Inbound Events
|
||||||
|
|
||||||
|
|
@ -83,6 +101,8 @@ ThreadStore = Reflux.createStore
|
||||||
@fetchFromCache()
|
@fetchFromCache()
|
||||||
|
|
||||||
_onSearchCommitted: (query) ->
|
_onSearchCommitted: (query) ->
|
||||||
|
Actions.selectThreadId(null)
|
||||||
|
|
||||||
if query.length > 0
|
if query.length > 0
|
||||||
@_searchQuery = query
|
@_searchQuery = query
|
||||||
@_items = []
|
@_items = []
|
||||||
|
|
@ -93,7 +113,6 @@ ThreadStore = Reflux.createStore
|
||||||
@fetchFromCache()
|
@fetchFromCache()
|
||||||
|
|
||||||
@_lastQuery = query
|
@_lastQuery = query
|
||||||
Actions.selectThreadId(null)
|
|
||||||
@fetchFromAPI()
|
@fetchFromAPI()
|
||||||
|
|
||||||
_onSelectTagId: (id) ->
|
_onSelectTagId: (id) ->
|
||||||
|
|
@ -108,10 +127,45 @@ ThreadStore = Reflux.createStore
|
||||||
|
|
||||||
thread = @selectedThread()
|
thread = @selectedThread()
|
||||||
if thread && thread.isUnread()
|
if thread && thread.isUnread()
|
||||||
thread.markAsRead()
|
Actions.queueTask(new MarkThreadReadTask(thread.id))
|
||||||
|
|
||||||
@trigger()
|
@trigger()
|
||||||
|
|
||||||
|
_onArchiveCurrentThread: ({silent}={}) ->
|
||||||
|
thread = @selectedThread()
|
||||||
|
return unless thread
|
||||||
|
@_archive(thread.id)
|
||||||
|
@_selectedId = null
|
||||||
|
if not silent
|
||||||
|
@trigger()
|
||||||
|
Actions.popSheet()
|
||||||
|
Actions.selectThreadId(null)
|
||||||
|
|
||||||
|
_archive: (threadId) ->
|
||||||
|
Actions.postNotification({message: "Archived thread", type: 'success'})
|
||||||
|
task = new AddRemoveTagsTask(threadId, ['archive'], ['inbox'])
|
||||||
|
Actions.queueTask(task)
|
||||||
|
|
||||||
|
_threadOffsetFromCurrentBy: (offset=0) ->
|
||||||
|
thread = @selectedThread()
|
||||||
|
index = @_items.indexOf(thread)
|
||||||
|
return null if index is -1
|
||||||
|
index += offset
|
||||||
|
index = Math.min(Math.max(index, 0), @_items.length - 1)
|
||||||
|
return @_items[index]
|
||||||
|
|
||||||
|
_onArchiveAndPrevious: ->
|
||||||
|
return unless @_selectedId
|
||||||
|
newSelectedId = @_threadOffsetFromCurrentBy(-1)?.id
|
||||||
|
@_onArchiveCurrentThread(silent: true)
|
||||||
|
Actions.selectThreadId(newSelectedId)
|
||||||
|
|
||||||
|
_onArchiveAndNext: ->
|
||||||
|
return unless @_selectedId
|
||||||
|
newSelectedId = @_threadOffsetFromCurrentBy(1)?.id
|
||||||
|
@_onArchiveCurrentThread(silent: true)
|
||||||
|
Actions.selectThreadId(newSelectedId)
|
||||||
|
|
||||||
# Accessing Data
|
# Accessing Data
|
||||||
|
|
||||||
selectedTagId: ->
|
selectedTagId: ->
|
||||||
|
|
|
||||||
|
|
@ -261,6 +261,7 @@
|
||||||
|
|
||||||
@input-accessory-color-hover: @light-blue;
|
@input-accessory-color-hover: @light-blue;
|
||||||
@input-accessory-color: @cool-gray;
|
@input-accessory-color: @cool-gray;
|
||||||
|
@input-cancel-color: @red;
|
||||||
|
|
||||||
//** Text color for `<input>`s
|
//** Text color for `<input>`s
|
||||||
@input-color: @gray;
|
@input-color: @gray;
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue