Mailspring/internal_packages/thread-list/lib/thread-list-store.coffee

91 lines
2.9 KiB
CoffeeScript
Raw Normal View History

_ = require 'underscore'
NylasStore = require 'nylas-store'
{Rx,
Thread,
Message,
Actions,
DatabaseStore,
WorkspaceStore,
feat(thread-list): Multiple selection, bulk actions, refactoring Summary: This diff provides multi-selection in the thread list powered by a new ModelList component that implements selection on top of ListTabular (or soon another List component). It includes business logic for single selection, shift selection, command-click selection, etc. This diff also improves the performance of DatabaseView by assessing whether updates are required based on specific database changes and skipping queries in many scenarios. WIP WIP Move selection into modelView instead of store WIP Preparing to convert to ModelList mixin Make ThreadStore => ThreadListStore Break the DraftStore in two (new DraftListStore) to avoid keeping all drafts in all windows Get rid of unread instance variable in favor of getter that falls through to isUnread() Much smarter logic in DatabaseView to prevent needless queries (especially counts and full invalidation of retained range) Squashed commit of the following: commit 486516b540e659735675765ca8b20d8a107ee2a9 Author: Ben Gotow <bengotow@gmail.com> Date: Tue Apr 7 17:30:23 2015 -0700 Invalidate the retained range debounced commit 7ac80403f52d108696c555f79c4c687d969f0228 Author: Ben Gotow <bengotow@gmail.com> Date: Tue Apr 7 17:30:16 2015 -0700 Wait until after the view updates to move focus commit 88d66eb19a9710847ff98bea22045bb686f30cc6 Author: Ben Gotow <bengotow@gmail.com> Date: Tue Apr 7 17:28:01 2015 -0700 Bail out early when loading data if a reload has been requested commit a49bedc44687040f7c675ff298376917a0b5fdcb Author: Ben Gotow <bengotow@gmail.com> Date: Tue Apr 7 16:38:58 2015 -0700 Log query data when in a query is being logged commit c64a9e02f9072fd30edb98c45be581d6ac00c48a Author: Ben Gotow <bengotow@gmail.com> Date: Tue Apr 7 16:38:45 2015 -0700 Mark thread and messages as read in parallel instead of in sequence commit 4b227100a795e20257cda0d60b00cc75b0000b0f Author: Ben Gotow <bengotow@gmail.com> Date: Tue Apr 7 16:38:32 2015 -0700 Don't load tags with hardcoded IDs from the database, and load them in parallel instead of in sequence commit aeb7f1d646786cfa1c247fe78ce5467da07c4446 Author: Ben Gotow <bengotow@gmail.com> Date: Tue Apr 7 16:37:54 2015 -0700 Pass objects instead of ids to thread methods—since we always have the most current thread anyway, this makes things a bit faster commit e70889d1d05ece81a081b8b3f27b62491429b6f9 Author: Ben Gotow <bengotow@gmail.com> Date: Mon Apr 6 16:41:49 2015 -0700 [icon] Paper airplanes Restyle account sidebar, optimize tag count queries a bit more Fix initialization issue with webkit image mask Can't compare dates with is/isnt Assets for check boxes Bug fixes Wrap ModelList instead of providing props Verbose mode for database view Fix existing specs Six new specs covering invalidateIfItemsInconsistent Test Plan: Run 40+ new tests Reviewers: evan Reviewed By: evan Differential Revision: https://review.inboxapp.com/D1410
2015-04-09 10:25:00 +08:00
FocusedContentStore,
TaskQueueStatusStore,
FocusedPerspectiveStore} = require 'nylas-exports'
2016-01-26 08:36:56 +08:00
{ListTabular} = require 'nylas-component-kit'
ThreadListDataSource = require './thread-list-data-source'
Merging in new observables for thread list commit 7a67c1fd349c575a91b162024cc03050e86574c9 Author: Ben Gotow <bengotow@gmail.com> Date: Fri Jan 8 11:14:07 2016 -0800 WIP commit 891f23487827a447ec95406ef26f1473a0c07de6 Author: Ben Gotow <bengotow@gmail.com> Date: Wed Jan 6 15:25:09 2016 -0800 WIP commit 3c323cd4beb2df2fae2439a556d3129404d942cc Author: Ben Gotow <bengotow@gmail.com> Date: Mon Jan 4 17:46:11 2016 -0800 WIP commit ec7090ea9e1969fea2ea583f80a9a2ac41e6c8b0 Author: Ben Gotow <bengotow@gmail.com> Date: Mon Jan 4 17:22:07 2016 -0800 Remove unused LRUCache commit e10c3919559d3c364cb7bb94d19094a2444c10f3 Author: Ben Gotow <bengotow@gmail.com> Date: Mon Jan 4 16:21:37 2016 -0800 rm(database-view): Performance refactor of thread-list Summary: This diff removes the old DatabaseView class, which included lots of gross optimizations that have since been duplicated in QuerySubscription and makes the thread list use the QuerySubscription class. This diff also substantially replaces the QuerySubscription class. The new implementation actually makes more queries but is less gross and more straightforward. It leverages a couple findings from database profiling: - Because of the sqlite page cache, asking for ids you've previously asked for is very fast. + Don't bother sorting in memory to avoid a query, just ask for ids again and fill in any missing objects. - Loading and inflating models is 4x+ slower than just grabbing ids I've also added more convenience classes around database queries: - QueryRange: Represents {offset, limit}, and can do boolean intersections - QueryResultSet: Better than passing an array of 50 items when you really mean items 150-200. Also tries hard to be immutable. This diff doesn't fully remove the concept of a "ModelView" because it's used /everywhere/ in the multiselect list source. There's a small shim that we can remove when we refactor that code. Ideally, I think we should rename ModelView to "MultiselectListDataSource" to follow iOS conventions (eg UITableViewDataSource). RIP 80char lines? Test Plan: They've gone to hell. WIP. Reviewers: evan, juan Differential Revision: https://phab.nylas.com/D2408 commit 32607eee8aafb7fa98b866347bdd2c0b963a602c Author: Ben Gotow <bengotow@gmail.com> Date: Mon Jan 4 09:56:34 2016 -0800 WIP commit 5ab5fe74e94db6904bd77d224720ad9fc69fe6a7 Author: Ben Gotow <bengotow@gmail.com> Date: Wed Dec 30 22:56:46 2015 -0800 redo scrollbars to not require counts commit 361bb192d072dc8a69fd3ef143cad7bed214ebdc Author: Ben Gotow <bengotow@gmail.com> Date: Wed Dec 30 17:50:57 2015 -0800 wip commit 079394de1cc3344fb6568efe00a52d7fc97fbd27 Author: Ben Gotow <bengotow@gmail.com> Date: Wed Dec 30 13:49:11 2015 -0800 wip commit 65142be03c27c653fe1147fdde6c2f9b046ade22 Author: Ben Gotow <bengotow@gmail.com> Date: Wed Dec 30 01:23:20 2015 -0800 wip commit 5d412ec276be1104175ad0f43c9d54e1cea857bf Author: Ben Gotow <bengotow@gmail.com> Date: Tue Dec 29 22:49:58 2015 -0800 Refactor start commit d2b6eea884fcd2bd81ebe3985f2b2636a510c493 Author: Ben Gotow <bengotow@gmail.com> Date: Tue Dec 29 18:51:53 2015 -0800 RIP DatabaseView
2016-01-09 06:31:33 +08:00
class ThreadListStore extends NylasStore
constructor: ->
@listenTo FocusedPerspectiveStore, @_onPerspectiveChanged
2016-01-15 07:04:17 +08:00
@createListDataSource()
dataSource: =>
2016-01-15 07:04:17 +08:00
@_dataSource
createListDataSource: =>
@_dataSourceUnlisten?()
2016-01-26 08:36:56 +08:00
@_dataSource = null
threadsSubscription = FocusedPerspectiveStore.current().threads()
if threadsSubscription
@_dataSource = new ThreadListDataSource(threadsSubscription)
@_dataSourceUnlisten = @_dataSource.listen(@_onDataChanged, @)
else
@_dataSource = new ListTabular.DataSource.Empty()
@trigger(@)
2016-01-15 07:04:17 +08:00
Actions.setFocus(collection: 'thread', item: null)
selectionObservable: =>
return Rx.Observable.fromListSelection(@)
# Inbound Events
_onPerspectiveChanged: =>
if FocusedPerspectiveStore.current().searchQuery is undefined
Actions.dismissNotificationsMatching({tag: 'search-error'})
2016-01-15 07:04:17 +08:00
@createListDataSource()
2016-01-15 07:04:17 +08:00
_onDataChanged: ({previous, next} = {}) =>
# This code keeps the focus and keyboard cursor in sync with the thread list.
# When the thread list changes, it looks to see if the focused thread is gone,
# or no longer matches the query criteria and advances the focus to the next
# thread.
# This means that removing a thread from view in any way causes selection
# to advance to the adjacent thread. Nice and declarative.
Merging in new observables for thread list commit 7a67c1fd349c575a91b162024cc03050e86574c9 Author: Ben Gotow <bengotow@gmail.com> Date: Fri Jan 8 11:14:07 2016 -0800 WIP commit 891f23487827a447ec95406ef26f1473a0c07de6 Author: Ben Gotow <bengotow@gmail.com> Date: Wed Jan 6 15:25:09 2016 -0800 WIP commit 3c323cd4beb2df2fae2439a556d3129404d942cc Author: Ben Gotow <bengotow@gmail.com> Date: Mon Jan 4 17:46:11 2016 -0800 WIP commit ec7090ea9e1969fea2ea583f80a9a2ac41e6c8b0 Author: Ben Gotow <bengotow@gmail.com> Date: Mon Jan 4 17:22:07 2016 -0800 Remove unused LRUCache commit e10c3919559d3c364cb7bb94d19094a2444c10f3 Author: Ben Gotow <bengotow@gmail.com> Date: Mon Jan 4 16:21:37 2016 -0800 rm(database-view): Performance refactor of thread-list Summary: This diff removes the old DatabaseView class, which included lots of gross optimizations that have since been duplicated in QuerySubscription and makes the thread list use the QuerySubscription class. This diff also substantially replaces the QuerySubscription class. The new implementation actually makes more queries but is less gross and more straightforward. It leverages a couple findings from database profiling: - Because of the sqlite page cache, asking for ids you've previously asked for is very fast. + Don't bother sorting in memory to avoid a query, just ask for ids again and fill in any missing objects. - Loading and inflating models is 4x+ slower than just grabbing ids I've also added more convenience classes around database queries: - QueryRange: Represents {offset, limit}, and can do boolean intersections - QueryResultSet: Better than passing an array of 50 items when you really mean items 150-200. Also tries hard to be immutable. This diff doesn't fully remove the concept of a "ModelView" because it's used /everywhere/ in the multiselect list source. There's a small shim that we can remove when we refactor that code. Ideally, I think we should rename ModelView to "MultiselectListDataSource" to follow iOS conventions (eg UITableViewDataSource). RIP 80char lines? Test Plan: They've gone to hell. WIP. Reviewers: evan, juan Differential Revision: https://phab.nylas.com/D2408 commit 32607eee8aafb7fa98b866347bdd2c0b963a602c Author: Ben Gotow <bengotow@gmail.com> Date: Mon Jan 4 09:56:34 2016 -0800 WIP commit 5ab5fe74e94db6904bd77d224720ad9fc69fe6a7 Author: Ben Gotow <bengotow@gmail.com> Date: Wed Dec 30 22:56:46 2015 -0800 redo scrollbars to not require counts commit 361bb192d072dc8a69fd3ef143cad7bed214ebdc Author: Ben Gotow <bengotow@gmail.com> Date: Wed Dec 30 17:50:57 2015 -0800 wip commit 079394de1cc3344fb6568efe00a52d7fc97fbd27 Author: Ben Gotow <bengotow@gmail.com> Date: Wed Dec 30 13:49:11 2015 -0800 wip commit 65142be03c27c653fe1147fdde6c2f9b046ade22 Author: Ben Gotow <bengotow@gmail.com> Date: Wed Dec 30 01:23:20 2015 -0800 wip commit 5d412ec276be1104175ad0f43c9d54e1cea857bf Author: Ben Gotow <bengotow@gmail.com> Date: Tue Dec 29 22:49:58 2015 -0800 Refactor start commit d2b6eea884fcd2bd81ebe3985f2b2636a510c493 Author: Ben Gotow <bengotow@gmail.com> Date: Tue Dec 29 18:51:53 2015 -0800 RIP DatabaseView
2016-01-09 06:31:33 +08:00
if previous and next
focused = FocusedContentStore.focused('thread')
keyboard = FocusedContentStore.keyboardCursor('thread')
viewModeAutofocuses = WorkspaceStore.layoutMode() is 'split' or WorkspaceStore.topSheet().root is true
matchers = next.query()?.matchers()
focusedIndex = if focused then previous.offsetOfId(focused.id) else -1
keyboardIndex = if keyboard then previous.offsetOfId(keyboard.id) else -1
nextItemFromIndex = (i) =>
Merging in new observables for thread list commit 7a67c1fd349c575a91b162024cc03050e86574c9 Author: Ben Gotow <bengotow@gmail.com> Date: Fri Jan 8 11:14:07 2016 -0800 WIP commit 891f23487827a447ec95406ef26f1473a0c07de6 Author: Ben Gotow <bengotow@gmail.com> Date: Wed Jan 6 15:25:09 2016 -0800 WIP commit 3c323cd4beb2df2fae2439a556d3129404d942cc Author: Ben Gotow <bengotow@gmail.com> Date: Mon Jan 4 17:46:11 2016 -0800 WIP commit ec7090ea9e1969fea2ea583f80a9a2ac41e6c8b0 Author: Ben Gotow <bengotow@gmail.com> Date: Mon Jan 4 17:22:07 2016 -0800 Remove unused LRUCache commit e10c3919559d3c364cb7bb94d19094a2444c10f3 Author: Ben Gotow <bengotow@gmail.com> Date: Mon Jan 4 16:21:37 2016 -0800 rm(database-view): Performance refactor of thread-list Summary: This diff removes the old DatabaseView class, which included lots of gross optimizations that have since been duplicated in QuerySubscription and makes the thread list use the QuerySubscription class. This diff also substantially replaces the QuerySubscription class. The new implementation actually makes more queries but is less gross and more straightforward. It leverages a couple findings from database profiling: - Because of the sqlite page cache, asking for ids you've previously asked for is very fast. + Don't bother sorting in memory to avoid a query, just ask for ids again and fill in any missing objects. - Loading and inflating models is 4x+ slower than just grabbing ids I've also added more convenience classes around database queries: - QueryRange: Represents {offset, limit}, and can do boolean intersections - QueryResultSet: Better than passing an array of 50 items when you really mean items 150-200. Also tries hard to be immutable. This diff doesn't fully remove the concept of a "ModelView" because it's used /everywhere/ in the multiselect list source. There's a small shim that we can remove when we refactor that code. Ideally, I think we should rename ModelView to "MultiselectListDataSource" to follow iOS conventions (eg UITableViewDataSource). RIP 80char lines? Test Plan: They've gone to hell. WIP. Reviewers: evan, juan Differential Revision: https://phab.nylas.com/D2408 commit 32607eee8aafb7fa98b866347bdd2c0b963a602c Author: Ben Gotow <bengotow@gmail.com> Date: Mon Jan 4 09:56:34 2016 -0800 WIP commit 5ab5fe74e94db6904bd77d224720ad9fc69fe6a7 Author: Ben Gotow <bengotow@gmail.com> Date: Wed Dec 30 22:56:46 2015 -0800 redo scrollbars to not require counts commit 361bb192d072dc8a69fd3ef143cad7bed214ebdc Author: Ben Gotow <bengotow@gmail.com> Date: Wed Dec 30 17:50:57 2015 -0800 wip commit 079394de1cc3344fb6568efe00a52d7fc97fbd27 Author: Ben Gotow <bengotow@gmail.com> Date: Wed Dec 30 13:49:11 2015 -0800 wip commit 65142be03c27c653fe1147fdde6c2f9b046ade22 Author: Ben Gotow <bengotow@gmail.com> Date: Wed Dec 30 01:23:20 2015 -0800 wip commit 5d412ec276be1104175ad0f43c9d54e1cea857bf Author: Ben Gotow <bengotow@gmail.com> Date: Tue Dec 29 22:49:58 2015 -0800 Refactor start commit d2b6eea884fcd2bd81ebe3985f2b2636a510c493 Author: Ben Gotow <bengotow@gmail.com> Date: Tue Dec 29 18:51:53 2015 -0800 RIP DatabaseView
2016-01-09 06:31:33 +08:00
if i > 0 and (next.modelAtOffset(i - 1)?.unread or i >= next.count())
nextIndex = i - 1
else
nextIndex = i
# May return null if no thread is loaded at the next index
next.modelAtOffset(nextIndex)
notInSet = (model) ->
if matchers
return model.matches(matchers) is false
else
return next.offsetOfId(model.id) is -1
if viewModeAutofocuses and focused and notInSet(focused)
Actions.setFocus(collection: 'thread', item: nextItemFromIndex(focusedIndex))
if keyboard and notInSet(keyboard)
Actions.setCursorPosition(collection: 'thread', item: nextItemFromIndex(keyboardIndex))
module.exports = new ThreadListStore()