2016-04-01 06:52:03 +08:00
|
|
|
import React from 'react';
|
|
|
|
import _ from 'underscore';
|
|
|
|
|
2017-09-27 02:33:08 +08:00
|
|
|
import {
|
|
|
|
Actions,
|
2016-04-01 06:52:03 +08:00
|
|
|
AccountStore,
|
|
|
|
MailRulesStore,
|
|
|
|
MailRulesTemplates,
|
2017-06-23 06:07:04 +08:00
|
|
|
TaskQueue,
|
2017-09-27 02:33:08 +08:00
|
|
|
ReprocessMailRulesTask,
|
|
|
|
} from 'nylas-exports';
|
2016-04-01 06:52:03 +08:00
|
|
|
|
2017-09-27 02:33:08 +08:00
|
|
|
import {
|
|
|
|
Flexbox,
|
2016-04-01 06:52:03 +08:00
|
|
|
EditableList,
|
|
|
|
RetinaImg,
|
|
|
|
ScrollRegion,
|
2017-09-27 02:33:08 +08:00
|
|
|
ScenarioEditor,
|
|
|
|
} from 'nylas-component-kit';
|
2016-04-01 06:52:03 +08:00
|
|
|
|
2017-09-27 02:33: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));
|
2017-06-23 06:07:04 +08:00
|
|
|
this._unsubscribers.push(TaskQueue.listen(this._onTasksChanged));
|
2016-04-01 06:52:03 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
componentWillUnmount() {
|
|
|
|
this._unsubscribers.forEach(unsubscribe => unsubscribe());
|
|
|
|
}
|
|
|
|
|
|
|
|
_getStateFromStores() {
|
|
|
|
const accounts = AccountStore.accounts();
|
|
|
|
const state = this.state || {};
|
2017-09-27 02:33:08 +08:00
|
|
|
let { currentAccount } = state;
|
2016-04-01 06:52:03 +08:00
|
|
|
if (!accounts.find(acct => acct === currentAccount)) {
|
|
|
|
currentAccount = accounts[0];
|
|
|
|
}
|
2016-12-15 07:34:49 +08:00
|
|
|
const rules = MailRulesStore.rulesForAccountId(currentAccount.id);
|
2017-09-27 02:33:08 +08:00
|
|
|
const selectedRule =
|
|
|
|
this.state && this.state.selectedRule
|
|
|
|
? rules.find(r => r.id === this.state.selectedRule.id)
|
|
|
|
: rules[0];
|
2016-04-01 06:52:03 +08:00
|
|
|
|
|
|
|
return {
|
|
|
|
accounts: accounts,
|
|
|
|
currentAccount: currentAccount,
|
|
|
|
rules: rules,
|
|
|
|
selectedRule: selectedRule,
|
2017-07-17 05:01:20 +08:00
|
|
|
tasks: TaskQueue.findTasks(ReprocessMailRulesTask, {}),
|
2016-04-01 06:52:03 +08:00
|
|
|
actionTemplates: ActionTemplatesForAccount(currentAccount),
|
|
|
|
conditionTemplates: ConditionTemplatesForAccount(currentAccount),
|
2017-09-27 02:33:08 +08:00
|
|
|
};
|
2016-04-01 06:52:03 +08:00
|
|
|
}
|
|
|
|
|
2017-09-27 02:33:08 +08:00
|
|
|
_onSelectAccount = event => {
|
2016-04-01 06:52:03 +08:00
|
|
|
const accountId = event.target.value;
|
2016-12-15 07:34:49 +08:00
|
|
|
const currentAccount = this.state.accounts.find(acct => acct.id === accountId);
|
2017-09-27 02:33:08 +08:00
|
|
|
this.setState({ currentAccount: currentAccount }, () => {
|
|
|
|
this.setState(this._getStateFromStores());
|
2016-04-01 06:52:03 +08:00
|
|
|
});
|
2017-09-27 02:33:08 +08:00
|
|
|
};
|
2016-04-01 06:52:03 +08:00
|
|
|
|
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;
|
2017-09-27 02:33:08 +08:00
|
|
|
};
|
2016-04-01 06:52:03 +08:00
|
|
|
|
|
|
|
if (needsMessageBodies()) {
|
2017-09-27 02:33:08 +08:00
|
|
|
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."
|
|
|
|
);
|
2016-04-01 06:52:03 +08:00
|
|
|
}
|
|
|
|
|
2017-09-27 02:33:08 +08:00
|
|
|
const task = new ReprocessMailRulesTask(this.state.currentAccount.id);
|
2016-04-01 06:52:03 +08:00
|
|
|
Actions.queueTask(task);
|
2017-09-27 02:33:08 +08:00
|
|
|
};
|
2016-04-01 06:52:03 +08:00
|
|
|
|
|
|
|
_onAddRule = () => {
|
2017-09-27 02:33:08 +08:00
|
|
|
Actions.addMailRule({ accountId: this.state.currentAccount.id });
|
|
|
|
};
|
2016-04-01 06:52:03 +08:00
|
|
|
|
2017-09-27 02:33:08 +08:00
|
|
|
_onSelectRule = rule => {
|
|
|
|
this.setState({ selectedRule: rule });
|
|
|
|
};
|
2016-04-01 06:52:03 +08:00
|
|
|
|
2016-06-01 07:42:03 +08:00
|
|
|
_onReorderRule = (rule, startIdx, endIdx) => {
|
|
|
|
Actions.reorderMailRule(rule.id, endIdx);
|
2017-09-27 02:33:08 +08:00
|
|
|
};
|
2016-04-01 06:52:03 +08:00
|
|
|
|
2017-09-27 02:33:08 +08:00
|
|
|
_onDeleteRule = rule => {
|
2016-04-01 06:52:03 +08:00
|
|
|
Actions.deleteMailRule(rule.id);
|
2017-09-27 02:33:08 +08:00
|
|
|
};
|
2016-04-01 06:52:03 +08:00
|
|
|
|
2016-04-06 03:01:48 +08:00
|
|
|
_onRuleNameEdited = (newName, rule) => {
|
2017-09-27 02:33:08 +08:00
|
|
|
Actions.updateMailRule(rule.id, { name: newName });
|
|
|
|
};
|
2016-04-01 06:52:03 +08:00
|
|
|
|
2017-09-27 02:33:08 +08:00
|
|
|
_onRuleConditionModeEdited = event => {
|
|
|
|
Actions.updateMailRule(this.state.selectedRule.id, { conditionMode: event.target.value });
|
|
|
|
};
|
2016-04-01 06:52:03 +08:00
|
|
|
|
|
|
|
_onRuleEnabled = () => {
|
2017-09-27 02:33:08 +08:00
|
|
|
Actions.updateMailRule(this.state.selectedRule.id, { disabled: false, disabledReason: null });
|
|
|
|
};
|
2016-04-01 06:52:03 +08:00
|
|
|
|
|
|
|
_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);
|
2017-09-27 02:33:08 +08:00
|
|
|
};
|
2016-04-01 06:52:03 +08:00
|
|
|
|
|
|
|
_onTasksChanged = () => {
|
2017-09-27 02:33:08 +08:00
|
|
|
this.setState({ tasks: TaskQueue.findTasks(ReprocessMailRulesTask, {}) });
|
|
|
|
};
|
2016-04-01 06:52:03 +08:00
|
|
|
|
|
|
|
_renderAccountPicker() {
|
2017-09-27 02:33:08 +08:00
|
|
|
const options = this.state.accounts.map(account => (
|
|
|
|
<option value={account.id} key={account.id}>
|
|
|
|
{account.label}
|
|
|
|
</option>
|
|
|
|
));
|
2016-04-01 06:52:03 +08:00
|
|
|
|
|
|
|
return (
|
|
|
|
<select
|
2016-12-15 07:34:49 +08:00
|
|
|
value={this.state.currentAccount.id}
|
2016-04-01 06:52:03 +08:00
|
|
|
onChange={this._onSelectAccount}
|
2017-09-27 02:33:08 +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>
|
2017-09-05 13:42:08 +08:00
|
|
|
<button className="btn btn-small" onClick={this._onAddRule}>
|
2016-04-01 06:52:03 +08:00
|
|
|
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) {
|
2017-09-27 02:33:08 +08:00
|
|
|
return <div className="item-rule-disabled">{rule.name}</div>;
|
2016-04-01 06:52:03 +08:00
|
|
|
}
|
|
|
|
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}
|
2017-09-27 02:33:08 +08:00
|
|
|
onChange={conditions => Actions.updateMailRule(rule.id, { conditions })}
|
2016-05-07 07:23:48 +08:00
|
|
|
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}
|
2017-09-27 02:33:08 +08:00
|
|
|
onChange={actions => Actions.updateMailRule(rule.id, { actions })}
|
2016-05-07 07:23:48 +08:00
|
|
|
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">
|
2017-09-27 02:33:08 +08:00
|
|
|
<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.
|
2016-04-01 06:52:03 +08:00
|
|
|
<div>({this.state.selectedRule.disabledReason})</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
_renderTasks() {
|
|
|
|
if (this.state.tasks.length === 0) return false;
|
|
|
|
return (
|
2017-09-27 02:33:08 +08:00
|
|
|
<div style={{ flex: 1, paddingLeft: 20 }}>
|
|
|
|
{this.state.tasks.map(task => {
|
2016-04-01 06:52:03 +08:00
|
|
|
return (
|
2017-09-27 02:33:08 +08:00
|
|
|
<Flexbox style={{ alignItems: 'baseline' }}>
|
|
|
|
<div style={{ paddingRight: '12px' }}>
|
|
|
|
<RetinaImg
|
|
|
|
name="sending-spinner.gif"
|
|
|
|
width={18}
|
|
|
|
mode={RetinaImg.Mode.ContentPreserve}
|
|
|
|
/>
|
2016-04-01 06:52:03 +08:00
|
|
|
</div>
|
|
|
|
<div>
|
|
|
|
<strong>{AccountStore.accountForId(task.accountId).emailAddress}</strong>
|
|
|
|
{` — ${Number(task.numberOfImpactedItems()).toLocaleString()} processed...`}
|
|
|
|
</div>
|
2017-09-27 02:33:08 +08:00
|
|
|
<div style={{ flex: 1 }} />
|
2017-07-31 07:52:58 +08:00
|
|
|
<button className="btn btn-sm" onClick={() => Actions.cancelTask(task)}>
|
2016-05-07 07:23:48 +08:00
|
|
|
Cancel
|
|
|
|
</button>
|
2016-04-01 06:52:03 +08:00
|
|
|
</Flexbox>
|
|
|
|
);
|
|
|
|
})}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
render() {
|
2017-09-27 02:33:08 +08:00
|
|
|
const processDisabled = this.state.tasks.some(
|
|
|
|
task => task.accountId === this.state.currentAccount.id
|
2017-07-08 07:35:52 +08:00
|
|
|
);
|
2016-04-06 10:16:58 +08:00
|
|
|
|
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()}
|
|
|
|
|
2017-09-27 02:33:08 +08:00
|
|
|
<Flexbox style={{ marginTop: 40, maxWidth: 600 }}>
|
2016-04-01 06:52:03 +08:00
|
|
|
<div>
|
2017-09-27 02:33:08 +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>
|
|
|
|
|
2017-09-27 02:33:08 +08:00
|
|
|
<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.
|
2016-04-01 06:52:03 +08:00
|
|
|
</p>
|
|
|
|
</section>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export default PreferencesMailRules;
|