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:
EthanBlackburn 2015-07-28 14:03:55 -07:00
parent 79dfd0866a
commit c622e2dbeb
10 changed files with 33 additions and 33 deletions

View file

@ -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

View file

@ -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>

View file

@ -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
}) })
] ]

View file

@ -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()

View file

@ -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')

View file

@ -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'})

View file

@ -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']

View file

@ -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

View file

@ -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

View file

@ -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.
# #