mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-09-07 13:14:47 +08:00
Threads now sorted by receivedrecetndate
Summary: Threads are now sorted using the thread's receivedrecentdate instead of recentdate Test Plan: Tested Manually Reviewers: bengotow Reviewed By: bengotow Subscribers: mg Differential Revision: https://phab.nylas.com/D1812
This commit is contained in:
parent
79dfd0866a
commit
c622e2dbeb
10 changed files with 33 additions and 33 deletions
|
@ -57,7 +57,7 @@ SearchSuggestionStore = Reflux.createStore
|
||||||
|
|
||||||
@_threadQueryInFlight = true
|
@_threadQueryInFlight = true
|
||||||
DatabaseStore.findAll(Thread, [Thread.attributes.subject.like(val)])
|
DatabaseStore.findAll(Thread, [Thread.attributes.subject.like(val)])
|
||||||
.order(Thread.attributes.lastMessageTimestamp.descending())
|
.order(Thread.attributes.lastMessageReceivedTimestamp.descending())
|
||||||
.limit(4)
|
.limit(4)
|
||||||
.then (results) =>
|
.then (results) =>
|
||||||
@_threadQueryInFlight = false
|
@_threadQueryInFlight = false
|
||||||
|
|
|
@ -42,7 +42,7 @@ class ThreadListScrollTooltip extends React.Component
|
||||||
|
|
||||||
render: ->
|
render: ->
|
||||||
if @state.item
|
if @state.item
|
||||||
content = timestamp(@state.item.lastMessageTimestamp)
|
content = timestamp(@state.item.lastMessageReceivedTimestamp)
|
||||||
else
|
else
|
||||||
content = "Loading..."
|
content = "Loading..."
|
||||||
<div className="scroll-tooltip">
|
<div className="scroll-tooltip">
|
||||||
|
@ -111,7 +111,7 @@ class ThreadList extends React.Component
|
||||||
c4 = new ListTabular.Column
|
c4 = new ListTabular.Column
|
||||||
name: "Date"
|
name: "Date"
|
||||||
resolver: (thread) =>
|
resolver: (thread) =>
|
||||||
<span className="timestamp">{timestamp(thread.lastMessageTimestamp)}</span>
|
<span className="timestamp">{timestamp(thread.lastMessageReceivedTimestamp)}</span>
|
||||||
|
|
||||||
c5 = new ListTabular.Column
|
c5 = new ListTabular.Column
|
||||||
name: "HoverActions"
|
name: "HoverActions"
|
||||||
|
@ -141,7 +141,7 @@ class ThreadList extends React.Component
|
||||||
{pencil}
|
{pencil}
|
||||||
<span style={flex:1}></span>
|
<span style={flex:1}></span>
|
||||||
{attachment}
|
{attachment}
|
||||||
<span className="timestamp">{timestamp(thread.lastMessageTimestamp)}</span>
|
<span className="timestamp">{timestamp(thread.lastMessageReceivedTimestamp)}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="subject">{subject(thread.subject)}</div>
|
<div className="subject">{subject(thread.subject)}</div>
|
||||||
<div className="snippet">{thread.snippet}</div>
|
<div className="snippet">{thread.snippet}</div>
|
||||||
|
|
|
@ -96,7 +96,7 @@ test_threads = -> [
|
||||||
"email": "user2@nylas.com"
|
"email": "user2@nylas.com"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"last_message_timestamp": 1415742036
|
"last_message_received_timestamp": 1415742036
|
||||||
}),
|
}),
|
||||||
(new Thread).fromJSON({
|
(new Thread).fromJSON({
|
||||||
"id": "222",
|
"id": "222",
|
||||||
|
@ -146,7 +146,7 @@ test_threads = -> [
|
||||||
"email": "user3@nylas.com"
|
"email": "user3@nylas.com"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"last_message_timestamp": 1415741913
|
"last_message_received_timestamp": 1415741913
|
||||||
}),
|
}),
|
||||||
(new Thread).fromJSON({
|
(new Thread).fromJSON({
|
||||||
"id": "333",
|
"id": "333",
|
||||||
|
@ -190,7 +190,7 @@ test_threads = -> [
|
||||||
"email": "user4@nylas.com"
|
"email": "user4@nylas.com"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"last_message_timestamp": 1415741837
|
"last_message_received_timestamp": 1415741837
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
@ -133,12 +133,12 @@ describe "DatabaseView", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@inbox = new Label(id: 'l-1', name: 'inbox', displayName: 'Inbox')
|
@inbox = new Label(id: 'l-1', name: 'inbox', displayName: 'Inbox')
|
||||||
@archive = new Label(id: 'l-2', name: 'archive', displayName: 'archive')
|
@archive = new Label(id: 'l-2', name: 'archive', displayName: 'archive')
|
||||||
@a = new Thread(id: 'a', subject: 'a', labels:[@inbox], lastMessageTimestamp: new Date(1428526885604))
|
@a = new Thread(id: 'a', subject: 'a', labels:[@inbox], lastMessageReceivedTimestamp: new Date(1428526885604))
|
||||||
@b = new Thread(id: 'b', subject: 'b', labels:[@inbox], lastMessageTimestamp: new Date(1428526885604))
|
@b = new Thread(id: 'b', subject: 'b', labels:[@inbox], lastMessageReceivedTimestamp: new Date(1428526885604))
|
||||||
@c = new Thread(id: 'c', subject: 'c', labels:[@inbox], lastMessageTimestamp: new Date(1428526885604))
|
@c = new Thread(id: 'c', subject: 'c', labels:[@inbox], lastMessageReceivedTimestamp: new Date(1428526885604))
|
||||||
@d = new Thread(id: 'd', subject: 'd', labels:[@inbox], lastMessageTimestamp: new Date(1428526885604))
|
@d = new Thread(id: 'd', subject: 'd', labels:[@inbox], lastMessageReceivedTimestamp: new Date(1428526885604))
|
||||||
@e = new Thread(id: 'e', subject: 'e', labels:[@inbox], lastMessageTimestamp: new Date(1428526885604))
|
@e = new Thread(id: 'e', subject: 'e', labels:[@inbox], lastMessageReceivedTimestamp: new Date(1428526885604))
|
||||||
@f = new Thread(id: 'f', subject: 'f', labels:[@inbox], lastMessageTimestamp: new Date(1428526885604))
|
@f = new Thread(id: 'f', subject: 'f', labels:[@inbox], lastMessageReceivedTimestamp: new Date(1428526885604))
|
||||||
|
|
||||||
@view = new DatabaseView Thread,
|
@view = new DatabaseView Thread,
|
||||||
matchers: [Thread.attributes.labels.contains('l-1')]
|
matchers: [Thread.attributes.labels.contains('l-1')]
|
||||||
|
@ -164,13 +164,13 @@ describe "DatabaseView", ->
|
||||||
expect(@view.invalidateRetainedRange).toHaveBeenCalled()
|
expect(@view.invalidateRetainedRange).toHaveBeenCalled()
|
||||||
|
|
||||||
it "should invalidate the entire range if a provided item is not in the set but matches the set", ->
|
it "should invalidate the entire range if a provided item is not in the set but matches the set", ->
|
||||||
incoming = new Thread(id: 'a', subject: 'a', labels:[@inbox], lastMessageTimestamp: new Date())
|
incoming = new Thread(id: 'a', subject: 'a', labels:[@inbox], lastMessageReceivedTimestamp: new Date())
|
||||||
@view.invalidateAfterDatabaseChange({objects:[incoming], type:'persist'})
|
@view.invalidateAfterDatabaseChange({objects:[incoming], type:'persist'})
|
||||||
expect(@view.invalidateRetainedRange).toHaveBeenCalled()
|
expect(@view.invalidateRetainedRange).toHaveBeenCalled()
|
||||||
|
|
||||||
it "should invalidate the entire range if a provided item matches the set and the value of it's sorting attribute has changed", ->
|
it "should invalidate the entire range if a provided item matches the set and the value of it's sorting attribute has changed", ->
|
||||||
a = new Thread(@a)
|
a = new Thread(@a)
|
||||||
a.lastMessageTimestamp = new Date(1428526909533)
|
a.lastMessageReceivedTimestamp = new Date(1428526909533)
|
||||||
@view.invalidateAfterDatabaseChange({objects:[a], type:'persist'})
|
@view.invalidateAfterDatabaseChange({objects:[a], type:'persist'})
|
||||||
expect(@view.invalidateRetainedRange).toHaveBeenCalled()
|
expect(@view.invalidateRetainedRange).toHaveBeenCalled()
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ TestModel.configureWithAdditionalSQLiteConfig = ->
|
||||||
modelKey: 'body'
|
modelKey: 'body'
|
||||||
TestModel.additionalSQLiteConfig =
|
TestModel.additionalSQLiteConfig =
|
||||||
setup: ->
|
setup: ->
|
||||||
['CREATE INDEX IF NOT EXISTS ThreadListIndex ON Thread(last_message_timestamp DESC, namespace_id, id)']
|
['CREATE INDEX IF NOT EXISTS ThreadListIndex ON Thread(last_message_received_timestamp DESC, namespace_id, id)']
|
||||||
writeModel: jasmine.createSpy('additionalWriteModel')
|
writeModel: jasmine.createSpy('additionalWriteModel')
|
||||||
deleteModel: jasmine.createSpy('additionalDeleteModel')
|
deleteModel: jasmine.createSpy('additionalDeleteModel')
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ describe "ModelQuery", ->
|
||||||
expect(@q._matchers[1]).toBe(@m2)
|
expect(@q._matchers[1]).toBe(@m2)
|
||||||
|
|
||||||
it "should accept a shorthand format", ->
|
it "should accept a shorthand format", ->
|
||||||
@q.where({id: 4, lastMessageTimestamp: 1234})
|
@q.where({id: 4, lastMessageReceivedTimestamp: 1234})
|
||||||
expect(@q._matchers.length).toBe(2)
|
expect(@q._matchers.length).toBe(2)
|
||||||
expect(@q._matchers[0].attr.modelKey).toBe('id')
|
expect(@q._matchers[0].attr.modelKey).toBe('id')
|
||||||
expect(@q._matchers[0].comparator).toBe('=')
|
expect(@q._matchers[0].comparator).toBe('=')
|
||||||
|
@ -51,7 +51,7 @@ describe "ModelQuery", ->
|
||||||
describe "order", ->
|
describe "order", ->
|
||||||
beforeEach ->
|
beforeEach ->
|
||||||
@q = new ModelQuery(Thread, @db)
|
@q = new ModelQuery(Thread, @db)
|
||||||
@o1 = Thread.attributes.lastMessageTimestamp.descending()
|
@o1 = Thread.attributes.lastMessageReceivedTimestamp.descending()
|
||||||
@o2 = Thread.attributes.subject.descending()
|
@o2 = Thread.attributes.subject.descending()
|
||||||
|
|
||||||
it "should accept an array of SortOrders", ->
|
it "should accept an array of SortOrders", ->
|
||||||
|
@ -126,7 +126,7 @@ describe "ModelQuery", ->
|
||||||
builder: (q) -> q.where({namespaceId: 'abcd'}).one()
|
builder: (q) -> q.where({namespaceId: 'abcd'}).one()
|
||||||
sql: "SELECT `Thread`.`data` FROM `Thread` \
|
sql: "SELECT `Thread`.`data` FROM `Thread` \
|
||||||
WHERE `Thread`.`namespace_id` = 'abcd' \
|
WHERE `Thread`.`namespace_id` = 'abcd' \
|
||||||
ORDER BY `Thread`.`last_message_timestamp` DESC LIMIT 1"
|
ORDER BY `Thread`.`last_message_received_timestamp` DESC LIMIT 1"
|
||||||
|
|
||||||
it "should correctly generate `contains` queries using JOINS", ->
|
it "should correctly generate `contains` queries using JOINS", ->
|
||||||
@runScenario Thread,
|
@runScenario Thread,
|
||||||
|
@ -134,7 +134,7 @@ describe "ModelQuery", ->
|
||||||
sql: "SELECT `Thread`.`data` FROM `Thread` \
|
sql: "SELECT `Thread`.`data` FROM `Thread` \
|
||||||
INNER JOIN `Thread-Label` AS `M1` ON `M1`.`id` = `Thread`.`id` \
|
INNER JOIN `Thread-Label` AS `M1` ON `M1`.`id` = `Thread`.`id` \
|
||||||
WHERE `M1`.`value` = 'label-id' AND `Thread`.`id` = '1234' \
|
WHERE `M1`.`value` = 'label-id' AND `Thread`.`id` = '1234' \
|
||||||
ORDER BY `Thread`.`last_message_timestamp` DESC"
|
ORDER BY `Thread`.`last_message_received_timestamp` DESC"
|
||||||
|
|
||||||
@runScenario Thread,
|
@runScenario Thread,
|
||||||
builder: (q) -> q.where([Thread.attributes.labels.contains('l-1'), Thread.attributes.labels.contains('l-2')])
|
builder: (q) -> q.where([Thread.attributes.labels.contains('l-1'), Thread.attributes.labels.contains('l-2')])
|
||||||
|
@ -142,20 +142,20 @@ describe "ModelQuery", ->
|
||||||
INNER JOIN `Thread-Label` AS `M1` ON `M1`.`id` = `Thread`.`id` \
|
INNER JOIN `Thread-Label` AS `M1` ON `M1`.`id` = `Thread`.`id` \
|
||||||
INNER JOIN `Thread-Label` AS `M2` ON `M2`.`id` = `Thread`.`id` \
|
INNER JOIN `Thread-Label` AS `M2` ON `M2`.`id` = `Thread`.`id` \
|
||||||
WHERE `M1`.`value` = 'l-1' AND `M2`.`value` = 'l-2' \
|
WHERE `M1`.`value` = 'l-1' AND `M2`.`value` = 'l-2' \
|
||||||
ORDER BY `Thread`.`last_message_timestamp` DESC"
|
ORDER BY `Thread`.`last_message_received_timestamp` DESC"
|
||||||
|
|
||||||
it "should correctly generate queries with the class's naturalSortOrder when one is available and no other orders are provided", ->
|
it "should correctly generate queries with the class's naturalSortOrder when one is available and no other orders are provided", ->
|
||||||
@runScenario Thread,
|
@runScenario Thread,
|
||||||
builder: (q) -> q.where({namespaceId: 'abcd'})
|
builder: (q) -> q.where({namespaceId: 'abcd'})
|
||||||
sql: "SELECT `Thread`.`data` FROM `Thread` \
|
sql: "SELECT `Thread`.`data` FROM `Thread` \
|
||||||
WHERE `Thread`.`namespace_id` = 'abcd' \
|
WHERE `Thread`.`namespace_id` = 'abcd' \
|
||||||
ORDER BY `Thread`.`last_message_timestamp` DESC"
|
ORDER BY `Thread`.`last_message_received_timestamp` DESC"
|
||||||
|
|
||||||
@runScenario Thread,
|
@runScenario Thread,
|
||||||
builder: (q) -> q.where({namespaceId: 'abcd'}).order(Thread.attributes.lastMessageTimestamp.ascending())
|
builder: (q) -> q.where({namespaceId: 'abcd'}).order(Thread.attributes.lastMessageReceivedTimestamp.ascending())
|
||||||
sql: "SELECT `Thread`.`data` FROM `Thread` \
|
sql: "SELECT `Thread`.`data` FROM `Thread` \
|
||||||
WHERE `Thread`.`namespace_id` = 'abcd' \
|
WHERE `Thread`.`namespace_id` = 'abcd' \
|
||||||
ORDER BY `Thread`.`last_message_timestamp` ASC"
|
ORDER BY `Thread`.`last_message_received_timestamp` ASC"
|
||||||
|
|
||||||
@runScenario Namespace,
|
@runScenario Namespace,
|
||||||
builder: (q) -> q.where({id: 'abcd'})
|
builder: (q) -> q.where({id: 'abcd'})
|
||||||
|
|
|
@ -55,7 +55,7 @@ describe "DatabaseConnection", ->
|
||||||
spyOn(TestModel.additionalSQLiteConfig, 'setup').andCallThrough()
|
spyOn(TestModel.additionalSQLiteConfig, 'setup').andCallThrough()
|
||||||
queries = @connection._setupQueriesForTable(TestModel)
|
queries = @connection._setupQueriesForTable(TestModel)
|
||||||
expect(TestModel.additionalSQLiteConfig.setup).toHaveBeenCalledWith()
|
expect(TestModel.additionalSQLiteConfig.setup).toHaveBeenCalledWith()
|
||||||
expect(queries.pop()).toBe('CREATE INDEX IF NOT EXISTS ThreadListIndex ON Thread(last_message_timestamp DESC, namespace_id, id)')
|
expect(queries.pop()).toBe('CREATE INDEX IF NOT EXISTS ThreadListIndex ON Thread(last_message_received_timestamp DESC, namespace_id, id)')
|
||||||
|
|
||||||
it "should not fail if additional config is present, but setup is undefined", ->
|
it "should not fail if additional config is present, but setup is undefined", ->
|
||||||
delete TestModel.additionalSQLiteConfig['setup']
|
delete TestModel.additionalSQLiteConfig['setup']
|
||||||
|
|
|
@ -25,7 +25,7 @@ This is equivalent to writing the following SQL:
|
||||||
SELECT `Thread`.`data` FROM `Thread`
|
SELECT `Thread`.`data` FROM `Thread`
|
||||||
INNER JOIN `Thread-Label` AS `M1` ON `M1`.`id` = `Thread`.`id`
|
INNER JOIN `Thread-Label` AS `M1` ON `M1`.`id` = `Thread`.`id`
|
||||||
WHERE `M1`.`value` = 'inbox'
|
WHERE `M1`.`value` = 'inbox'
|
||||||
ORDER BY `Thread`.`last_message_timestamp` DESC
|
ORDER BY `Thread`.`last_message_received_timestamp` DESC
|
||||||
```
|
```
|
||||||
|
|
||||||
The value of this attribute is always an array of ff other model objects. To use
|
The value of this attribute is always an array of ff other model objects. To use
|
||||||
|
|
|
@ -24,7 +24,7 @@ query.then (thread) ->
|
||||||
```coffee
|
```coffee
|
||||||
query = DatabaseStore.findAll(Thread)
|
query = DatabaseStore.findAll(Thread)
|
||||||
query.where([Thread.attributes.labels.contains('label-id')])
|
query.where([Thread.attributes.labels.contains('label-id')])
|
||||||
.order([Thread.attributes.lastMessageTimestamp.descending()])
|
.order([Thread.attributes.lastMessageReceivedTimestamp.descending()])
|
||||||
.limit(100).offset(50)
|
.limit(100).offset(50)
|
||||||
.then (threads) ->
|
.then (threads) ->
|
||||||
# array of threads
|
# array of threads
|
||||||
|
|
|
@ -32,7 +32,7 @@ For more information about Threads on the Nylas Platform, read the
|
||||||
representing the participants in the thread.
|
representing the participants in the thread.
|
||||||
Note: Contacts on Threads do not have IDs.
|
Note: Contacts on Threads do not have IDs.
|
||||||
|
|
||||||
`lastMessageTimestamp`: {AttributeDateTime} The timestamp of the
|
`lastMessageReceivedTimestamp`: {AttributeDateTime} The timestamp of the
|
||||||
last message on the thread.
|
last message on the thread.
|
||||||
|
|
||||||
This class also inherits attributes from {Model}
|
This class also inherits attributes from {Model}
|
||||||
|
@ -74,17 +74,17 @@ class Thread extends Model
|
||||||
modelKey: 'participants'
|
modelKey: 'participants'
|
||||||
itemClass: Contact
|
itemClass: Contact
|
||||||
|
|
||||||
'lastMessageTimestamp': Attributes.DateTime
|
'lastMessageReceivedTimestamp': Attributes.DateTime
|
||||||
queryable: true
|
queryable: true
|
||||||
modelKey: 'lastMessageTimestamp'
|
modelKey: 'lastMessageReceivedTimestamp'
|
||||||
jsonKey: 'last_message_timestamp'
|
jsonKey: 'last_message_received_timestamp'
|
||||||
|
|
||||||
@naturalSortOrder: ->
|
@naturalSortOrder: ->
|
||||||
Thread.attributes.lastMessageTimestamp.descending()
|
Thread.attributes.lastMessageReceivedTimestamp.descending()
|
||||||
|
|
||||||
@additionalSQLiteConfig:
|
@additionalSQLiteConfig:
|
||||||
setup: ->
|
setup: ->
|
||||||
['CREATE INDEX IF NOT EXISTS ThreadListIndex ON Thread(last_message_timestamp DESC, namespace_id, id)']
|
['CREATE INDEX IF NOT EXISTS ThreadListIndex ON Thread(last_message_received_timestamp DESC, namespace_id, id)']
|
||||||
|
|
||||||
# Public: Returns true if the thread has a {Category} with the given ID.
|
# Public: Returns true if the thread has a {Category} with the given ID.
|
||||||
#
|
#
|
||||||
|
|
Loading…
Add table
Reference in a new issue