2016-04-01 06:52:03 +08:00
import React from 'react' ;
import _ from 'underscore' ;
import { Actions ,
AccountStore ,
MailRulesStore ,
MailRulesTemplates ,
TaskQueueStatusStore ,
ReprocessMailRulesTask } from 'nylas-exports' ;
import { Flexbox ,
EditableList ,
RetinaImg ,
ScrollRegion ,
ScenarioEditor } from 'nylas-component-kit' ;
2016-04-06 02:28:08 +08:00
const {
ActionTemplatesForAccount ,
ConditionTemplatesForAccount ,
} = MailRulesTemplates ;
2016-04-01 06:52:03 +08:00
class PreferencesMailRules extends React . Component {
static displayName = 'PreferencesMailRules' ;
constructor ( ) {
super ( ) ;
this . state = this . _getStateFromStores ( ) ;
}
componentDidMount ( ) {
this . _unsubscribers = [ ] ;
this . _unsubscribers . push ( MailRulesStore . listen ( this . _onRulesChanged ) ) ;
this . _unsubscribers . push ( TaskQueueStatusStore . listen ( this . _onTasksChanged ) ) ;
}
componentWillUnmount ( ) {
this . _unsubscribers . forEach ( unsubscribe => unsubscribe ( ) ) ;
}
_getStateFromStores ( ) {
const accounts = AccountStore . accounts ( ) ;
const state = this . state || { } ;
let { currentAccount } = state ;
if ( ! accounts . find ( acct => acct === currentAccount ) ) {
currentAccount = accounts [ 0 ] ;
}
const rules = MailRulesStore . rulesForAccountId ( currentAccount . accountId ) ;
const selectedRule = this . state && this . state . selectedRule ? _ . findWhere ( rules , { id : this . state . selectedRule . id } ) : rules [ 0 ] ;
return {
accounts : accounts ,
currentAccount : currentAccount ,
rules : rules ,
selectedRule : selectedRule ,
tasks : TaskQueueStatusStore . tasksMatching ( ReprocessMailRulesTask , { } ) ,
actionTemplates : ActionTemplatesForAccount ( currentAccount ) ,
conditionTemplates : ConditionTemplatesForAccount ( currentAccount ) ,
}
}
_onSelectAccount = ( event ) => {
const accountId = event . target . value ;
const currentAccount = this . state . accounts . find ( acct => acct . accountId === accountId ) ;
this . setState ( { currentAccount : currentAccount } , ( ) => {
this . setState ( this . _getStateFromStores ( ) )
} ) ;
}
2016-04-06 02:28:08 +08:00
_onReprocessRules = ( ) => {
2016-04-01 06:52:03 +08:00
const needsMessageBodies = ( ) => {
for ( const rule of this . state . rules ) {
for ( const condition of rule . conditions ) {
if ( condition . templateKey === 'body' ) {
return true ;
}
}
}
return false ;
}
if ( needsMessageBodies ( ) ) {
NylasEnv . showErrorDialog ( "One or more of your mail rules requires the bodies of messages being processed. These rules can't be run on your entire mailbox." ) ;
}
const task = new ReprocessMailRulesTask ( this . state . currentAccount . accountId )
Actions . queueTask ( task ) ;
}
_onAddRule = ( ) => {
Actions . addMailRule ( { accountId : this . state . currentAccount . accountId } ) ;
}
_onSelectRule = ( rule ) => {
this . setState ( { selectedRule : rule } ) ;
}
2016-06-01 07:42:03 +08:00
_onReorderRule = ( rule , startIdx , endIdx ) => {
Actions . reorderMailRule ( rule . id , endIdx ) ;
2016-04-01 06:52:03 +08:00
}
2016-04-06 03:01:48 +08:00
_onDeleteRule = ( rule ) => {
2016-04-01 06:52:03 +08:00
Actions . deleteMailRule ( rule . id ) ;
}
2016-04-06 03:01:48 +08:00
_onRuleNameEdited = ( newName , rule ) => {
2016-04-01 06:52:03 +08:00
Actions . updateMailRule ( rule . id , { name : newName } ) ;
}
_onRuleConditionModeEdited = ( event ) => {
Actions . updateMailRule ( this . state . selectedRule . id , { conditionMode : event . target . value } ) ;
}
_onRuleEnabled = ( ) => {
Actions . updateMailRule ( this . state . selectedRule . id , { disabled : false , disabledReason : null } ) ;
}
_onRulesChanged = ( ) => {
const next = this . _getStateFromStores ( ) ;
const nextRules = next . rules ;
const prevRules = this . state . rules ? this . state . rules : [ ] ;
const added = _ . difference ( nextRules , prevRules ) ;
if ( added . length === 1 ) {
next . selectedRule = added [ 0 ] ;
}
this . setState ( next ) ;
}
_onTasksChanged = ( ) => {
this . setState ( { tasks : TaskQueueStatusStore . tasksMatching ( ReprocessMailRulesTask , { } ) } )
}
_renderAccountPicker ( ) {
const options = this . state . accounts . map ( account =>
2016-06-09 06:17:06 +08:00
< option value = { account . accountId } key = { account . accountId } > { account . label } < / option >
2016-04-01 06:52:03 +08:00
) ;
return (
< select
value = { this . state . currentAccount . accountId }
onChange = { this . _onSelectAccount }
2016-06-09 06:17:06 +08:00
style = { { margin : 0 , minWidth : 200 } }
2016-05-07 07:23:48 +08:00
>
2016-04-01 06:52:03 +08:00
{ options }
< / select >
) ;
}
_renderMailRules ( ) {
if ( this . state . rules . length === 0 ) {
return (
< div className = "empty-list" >
< RetinaImg
className = "icon-mail-rules"
name = "rules-big.png"
2016-05-07 07:23:48 +08:00
mode = { RetinaImg . Mode . ContentDark }
/ >
2016-04-01 06:52:03 +08:00
< h2 > No rules < / h2 >
< button className = "btn btn-small" onMouseDown = { this . _onAddRule } >
Create a new rule
< / button >
< / div >
) ;
}
return (
< Flexbox >
< EditableList
showEditIcon
className = "rule-list"
items = { this . state . rules }
itemContent = { this . _renderListItemContent }
onCreateItem = { this . _onAddRule }
onReorderItem = { this . _onReorderRule }
onDeleteItem = { this . _onDeleteRule }
onItemEdited = { this . _onRuleNameEdited }
selected = { this . state . selectedRule }
2016-05-07 07:23:48 +08:00
onSelectItem = { this . _onSelectRule }
/ >
2016-04-01 06:52:03 +08:00
{ this . _renderDetail ( ) }
< / Flexbox >
) ;
}
_renderListItemContent ( rule ) {
if ( rule . disabled ) {
return ( < div className = "item-rule-disabled" > { rule . name } < / div > ) ;
}
return rule . name ;
}
_renderDetail ( ) {
const rule = this . state . selectedRule ;
if ( rule ) {
return (
< ScrollRegion className = "rule-detail" >
{ this . _renderDetailDisabledNotice ( ) }
< div className = "inner" >
< span > If < / span >
< select value = { rule . conditionMode } onChange = { this . _onRuleConditionModeEdited } >
< option value = "any" > Any < / option >
< option value = "all" > All < / option >
< / select >
< span > of the following conditions are met : < / span >
< ScenarioEditor
instances = { rule . conditions }
templates = { this . state . conditionTemplates }
2016-05-07 07:23:48 +08:00
onChange = { ( conditions ) => Actions . updateMailRule ( rule . id , { conditions } ) }
className = "well well-matchers"
/ >
2016-04-01 06:52:03 +08:00
< span > Perform the following actions : < / span >
< ScenarioEditor
instances = { rule . actions }
templates = { this . state . actionTemplates }
2016-05-07 07:23:48 +08:00
onChange = { ( actions ) => Actions . updateMailRule ( rule . id , { actions } ) }
className = "well well-actions"
/ >
2016-04-01 06:52:03 +08:00
< / div >
< / ScrollRegion >
) ;
}
return (
< div className = "rule-detail" >
< div className = "no-selection" > Create a rule or select one to get started < / div >
< / div >
) ;
}
_renderDetailDisabledNotice ( ) {
if ( ! this . state . selectedRule . disabled ) return false ;
return (
< div className = "disabled-reason" >
< button className = "btn" onClick = { this . _onRuleEnabled } > Enable < / button >
This rule has been disabled . Make sure the actions below are valid
and re - enable the rule .
< div > ( { this . state . selectedRule . disabledReason } ) < / div >
< / div >
) ;
}
_renderTasks ( ) {
if ( this . state . tasks . length === 0 ) return false ;
return (
< div style = { { flex : 1 , paddingLeft : 20 } } >
{ this . state . tasks . map ( ( task ) => {
return (
< Flexbox style = { { alignItems : 'baseline' } } >
< div style = { { paddingRight : "12px" } } >
< RetinaImg name = "sending-spinner.gif" width = { 18 } mode = { RetinaImg . Mode . ContentPreserve } / >
< / div >
< div >
< strong > { AccountStore . accountForId ( task . accountId ) . emailAddress } < / strong >
{ ` — ${ Number ( task . numberOfImpactedItems ( ) ) . toLocaleString ( ) } processed... ` }
< / div >
2016-10-18 08:59:33 +08:00
< div style = { { flex : 1 } } / >
2016-05-07 07:23:48 +08:00
< button className = "btn btn-sm" onClick = { ( ) => Actions . dequeueTask ( task . id ) } >
Cancel
< / button >
2016-04-01 06:52:03 +08:00
< / Flexbox >
) ;
} ) }
< / div >
) ;
}
render ( ) {
2016-04-06 10:16:58 +08:00
const processDisabled = _ . any ( this . state . tasks , ( task ) => {
return ( task . accountId === this . state . currentAccount . id ) ;
} ) ;
2016-04-01 06:52:03 +08:00
return (
< div className = "container-mail-rules" >
< section >
< Flexbox className = "container-dropdown" >
< div > Account : < / div >
< div className = "dropdown" > { this . _renderAccountPicker ( ) } < / div >
< / Flexbox >
< p > Rules only apply to the selected account . < / p >
{ this . _renderMailRules ( ) }
2016-04-06 03:01:48 +08:00
< Flexbox style = { { marginTop : 40 , maxWidth : 600 } } >
2016-04-01 06:52:03 +08:00
< div >
2016-05-07 07:23:48 +08:00
< button disabled = { processDisabled } className = "btn" style = { { 'float' : 'right' } } onClick = { this . _onReprocessRules } >
2016-04-06 10:16:58 +08:00
Process entire inbox
2016-04-01 06:52:03 +08:00
< / button >
< / div >
{ this . _renderTasks ( ) }
< / Flexbox >
< p style = { { marginTop : 10 } } >
By default , mail rules are only applied to new mail as it arrives .
2016-04-06 10:16:58 +08:00
Applying rules to your entire inbox may take a long time and
2016-04-01 06:52:03 +08:00
degrade performance .
< / p >
< / section >
< / div >
) ;
}
}
export default PreferencesMailRules ;