Mailspring/internal_packages/preferences/lib/tabs/preferences-mail-rules.jsx
Halla Moore d03049b403 fix(mail-rules): use the right field name to get an account id
Summary:
With the fix to the delta-processor, this is all that's needed to
get mail rules working! Some places were trying to use 'accountId'
to access an account object's id, but it needs to be 'id' instead.

Test Plan: tested locally

Reviewers: jackie

Reviewed By: jackie

Differential Revision: https://phab.nylas.com/D3525
2016-12-15 14:18:50 -08:00

307 lines
8.9 KiB
JavaScript

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';
const {
ActionTemplatesForAccount,
ConditionTemplatesForAccount,
} = MailRulesTemplates;
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.id);
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.id === accountId);
this.setState({currentAccount: currentAccount}, () => {
this.setState(this._getStateFromStores())
});
}
_onReprocessRules = () => {
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.id)
Actions.queueTask(task);
}
_onAddRule = () => {
Actions.addMailRule({accountId: this.state.currentAccount.id});
}
_onSelectRule = (rule) => {
this.setState({selectedRule: rule});
}
_onReorderRule = (rule, startIdx, endIdx) => {
Actions.reorderMailRule(rule.id, endIdx);
}
_onDeleteRule = (rule) => {
Actions.deleteMailRule(rule.id);
}
_onRuleNameEdited = (newName, rule) => {
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 =>
<option value={account.id} key={account.id}>{account.label}</option>
);
return (
<select
value={this.state.currentAccount.id}
onChange={this._onSelectAccount}
style={{margin: 0, minWidth: 200}}
>
{options}
</select>
);
}
_renderMailRules() {
if (this.state.rules.length === 0) {
return (
<div className="empty-list">
<RetinaImg
className="icon-mail-rules"
name="rules-big.png"
mode={RetinaImg.Mode.ContentDark}
/>
<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}
onSelectItem={this._onSelectRule}
/>
{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}
onChange={(conditions) => Actions.updateMailRule(rule.id, {conditions})}
className="well well-matchers"
/>
<span>Perform the following actions:</span>
<ScenarioEditor
instances={rule.actions}
templates={this.state.actionTemplates}
onChange={(actions) => Actions.updateMailRule(rule.id, {actions})}
className="well well-actions"
/>
</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>
<div style={{flex: 1}} />
<button className="btn btn-sm" onClick={() => Actions.dequeueTask(task.id)}>
Cancel
</button>
</Flexbox>
);
})}
</div>
);
}
render() {
const processDisabled = _.any(this.state.tasks, (task) => {
return (task.accountId === this.state.currentAccount.id);
});
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()}
<Flexbox style={{marginTop: 40, maxWidth: 600}}>
<div>
<button disabled={processDisabled} className="btn" style={{'float': 'right'}} onClick={this._onReprocessRules}>
Process entire inbox
</button>
</div>
{this._renderTasks()}
</Flexbox>
<p style={{marginTop: 10}}>
By default, mail rules are only applied to new mail as it arrives.
Applying rules to your entire inbox may take a long time and
degrade performance.
</p>
</section>
</div>
);
}
}
export default PreferencesMailRules;