mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-11-11 18:32:20 +08:00
af67597f0b
Summary: Originally, this was going to be a totally independent package, but I wasn't able to isolate the functionality and get it tied in to the delta-stream consumption. Here's how it currently works: - The preferences package has a new tab which allows you to edit mail filters. Filters are saved in a new core store, and a new stock component (ScenarioEditor) renders the editor. The editor takes a set of templates that define a value space, and outputs a valid set of values. - A new MailFilterProcessor takes messages and creates tasks to apply the actions from the MailFiltersStore. - The worker-sync package now uses the MailFilterProcessor to apply filters /before/ it calls didPassivelyReceiveNewModels, so filtrs are applied before any notifications are created. - A new task, ReprocessMailFiltersTask allows you to run filters on all of your existing mail. It leverages the existing TaskQueue architecture to: a) resume where it left off if you quit midway, b) be queryable (for status) from all windows and c) cancelable. The TaskQueue is a bit strange because it runs performLocal and performRemote very differently, and I had to use `performRemote`. (todo refactor soon.) This diff also changes the EditableList a bit to behave like a controlled component and render focused / unfocused states. Test Plan: Run tests, only for actual filter processing atm. Reviewers: juan, evan Reviewed By: evan Differential Revision: https://phab.nylas.com/D2379
128 lines
3.5 KiB
CoffeeScript
128 lines
3.5 KiB
CoffeeScript
React = require 'react'
|
|
_ = require 'underscore'
|
|
classNames = require 'classnames'
|
|
NotificationStore = require './notifications-store'
|
|
InitialSyncActivity = require './initial-sync-activity'
|
|
{Actions,
|
|
TaskQueue,
|
|
AccountStore,
|
|
NylasSyncStatusStore,
|
|
TaskQueueStatusStore} = require 'nylas-exports'
|
|
ActivitySidebarLongPollStore = require './activity-sidebar-long-poll-store'
|
|
{TimeoutTransitionGroup, RetinaImg} = require 'nylas-component-kit'
|
|
|
|
class ActivitySidebar extends React.Component
|
|
@displayName: 'ActivitySidebar'
|
|
|
|
@containerRequired: false
|
|
@containerStyles:
|
|
minWidth: 165
|
|
maxWidth: 400
|
|
|
|
constructor: (@props) ->
|
|
@state = @_getStateFromStores()
|
|
|
|
componentDidMount: =>
|
|
@_unlisteners = []
|
|
@_unlisteners.push TaskQueueStatusStore.listen @_onDataChanged
|
|
@_unlisteners.push NotificationStore.listen @_onDataChanged
|
|
@_unlisteners.push NylasSyncStatusStore.listen @_onDataChanged
|
|
@_unlisteners.push ActivitySidebarLongPollStore.listen @_onDeltaReceived
|
|
|
|
componentWillUnmount: =>
|
|
unlisten() for unlisten in @_unlisteners
|
|
|
|
render: =>
|
|
items = [@_renderNotificationActivityItems(), @_renderTaskActivityItems()]
|
|
|
|
if @state.isInitialSyncComplete
|
|
if @state.receivingDelta
|
|
items.push @_renderDeltaSyncActivityItem()
|
|
else
|
|
items.push <InitialSyncActivity key="initial-sync" />
|
|
|
|
|
|
names = classNames
|
|
"sidebar-activity": true
|
|
"sidebar-activity-error": error?
|
|
|
|
wrapperClass = "sidebar-activity-transition-wrapper "
|
|
|
|
if items.length is 0
|
|
wrapperClass += "sidebar-activity-empty"
|
|
else
|
|
inside = <TimeoutTransitionGroup
|
|
className={names}
|
|
leaveTimeout={625}
|
|
enterTimeout={125}
|
|
transitionName="activity-opacity">
|
|
{items}
|
|
</TimeoutTransitionGroup>
|
|
|
|
<TimeoutTransitionGroup
|
|
className={wrapperClass}
|
|
leaveTimeout={625}
|
|
enterTimeout={125}
|
|
transitionName="activity-opacity">
|
|
{inside}
|
|
</TimeoutTransitionGroup>
|
|
|
|
_renderTaskActivityItems: =>
|
|
summary = {}
|
|
|
|
@state.tasks.map (task) ->
|
|
label = task.label?()
|
|
return unless label
|
|
summary[label] ?= 0
|
|
summary[label] += task.numberOfImpactedItems()
|
|
|
|
_.pairs(summary).map ([label, count]) ->
|
|
<div className="item" key={label}>
|
|
<div className="inner">
|
|
<span className="count">({new Number(count).toLocaleString()})</span>
|
|
{label}
|
|
</div>
|
|
</div>
|
|
|
|
_renderDeltaSyncActivityItem: =>
|
|
<div className="item" key="delta-sync-item">
|
|
<div style={padding: "9px 9px 0 12px", float: "left"}>
|
|
<RetinaImg name="sending-spinner.gif" width={18} mode={RetinaImg.Mode.ContentPreserve} />
|
|
</div>
|
|
<div className="inner">
|
|
Syncing your mailbox…
|
|
</div>
|
|
</div>
|
|
|
|
_renderNotificationActivityItems: =>
|
|
@state.notifications.map (notification) ->
|
|
<div className="item" key={notification.id}>
|
|
<div className="inner">
|
|
{notification.message}
|
|
</div>
|
|
</div>
|
|
|
|
_onDataChanged: =>
|
|
@setState(@_getStateFromStores())
|
|
|
|
_getStateFromStores: =>
|
|
notifications: NotificationStore.notifications()
|
|
tasks: TaskQueueStatusStore.queue()
|
|
isInitialSyncComplete: NylasSyncStatusStore.isComplete()
|
|
|
|
_onDeltaReceived: (countDeltas) =>
|
|
tooSmallForNotification = countDeltas <= 10
|
|
return if tooSmallForNotification
|
|
|
|
if @_timeoutId
|
|
clearTimeout @_timeoutId
|
|
|
|
@_timeoutId = setTimeout(( =>
|
|
delete @_timeoutId
|
|
@setState receivingDelta: false
|
|
), 30000)
|
|
|
|
@setState receivingDelta: true
|
|
|
|
|
|
module.exports = ActivitySidebar
|