mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-09-21 15:56:10 +08:00
feat(snooze): Add snooze date label to snooze threads
- Adds a new InjectedComponentSet for the role 'ThreadList:Label'. - Adds a new label to the thread list indicating the snooze date if the thread has been snoozed - Coerces MailLabel to achieve this. This is a temporary hack, we should design a better view to display snooze date information
This commit is contained in:
parent
f75eddb518
commit
f22fdbae49
|
@ -80,7 +80,13 @@ c3 = new ListTabular.Column
|
||||||
labels.push c3LabelComponentCache[label.id]
|
labels.push c3LabelComponentCache[label.id]
|
||||||
|
|
||||||
<span className="details">
|
<span className="details">
|
||||||
{labels}
|
<InjectedComponentSet
|
||||||
|
inline
|
||||||
|
containerRequired={false}
|
||||||
|
children={labels}
|
||||||
|
matching={role: "ThreadList:Label"}
|
||||||
|
className="thread-injected-mail-labels"
|
||||||
|
exposedProps={thread: thread}/>
|
||||||
<span className="subject">{subject(thread.subject)}</span>
|
<span className="subject">{subject(thread.subject)}</span>
|
||||||
<span className="snippet">{thread.snippet}</span>
|
<span className="snippet">{thread.snippet}</span>
|
||||||
{attachment}
|
{attachment}
|
||||||
|
@ -148,7 +154,13 @@ cNarrow = new ListTabular.Column
|
||||||
<div className="snippet-and-labels">
|
<div className="snippet-and-labels">
|
||||||
<div className="snippet">{thread.snippet} </div>
|
<div className="snippet">{thread.snippet} </div>
|
||||||
<div style={flex: 1, flexShrink: 1}></div>
|
<div style={flex: 1, flexShrink: 1}></div>
|
||||||
{labels}
|
<InjectedComponentSet
|
||||||
|
inline
|
||||||
|
containerRequired={false}
|
||||||
|
children={labels}
|
||||||
|
matching={role: "ThreadList:Label"}
|
||||||
|
className="thread-injected-mail-labels-narrow"
|
||||||
|
exposedProps={thread: thread}/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -239,6 +239,9 @@
|
||||||
.thread-injected-icons {
|
.thread-injected-icons {
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
|
.thread-injected-mail-labels {
|
||||||
|
margin-right: 6px;
|
||||||
|
}
|
||||||
.thread-icon {
|
.thread-icon {
|
||||||
width:25px;
|
width:25px;
|
||||||
height:24px;
|
height:24px;
|
||||||
|
|
|
@ -1,21 +1,24 @@
|
||||||
/** @babel */
|
/** @babel */
|
||||||
import {ComponentRegistry} from 'nylas-exports';
|
import {ComponentRegistry} from 'nylas-exports';
|
||||||
import {ToolbarSnooze, BulkThreadSnooze} from './toolbar-components';
|
import {ToolbarSnooze, BulkThreadSnooze} from './snooze-toolbar-components';
|
||||||
import QuickActionSnoozeButton from './quick-action-snooze-button'
|
import SnoozeQuickActionButton from './snooze-quick-action-button'
|
||||||
|
import SnoozeMailLabel from './snooze-mail-label'
|
||||||
import SnoozeStore from './snooze-store'
|
import SnoozeStore from './snooze-store'
|
||||||
|
|
||||||
|
|
||||||
export function activate() {
|
export function activate() {
|
||||||
this.snoozeStore = new SnoozeStore()
|
this.snoozeStore = new SnoozeStore()
|
||||||
ComponentRegistry.register(ToolbarSnooze, {role: 'message:Toolbar'});
|
ComponentRegistry.register(ToolbarSnooze, {role: 'message:Toolbar'});
|
||||||
ComponentRegistry.register(QuickActionSnoozeButton, {role: 'ThreadListQuickAction'});
|
ComponentRegistry.register(SnoozeQuickActionButton, {role: 'ThreadListQuickAction'});
|
||||||
ComponentRegistry.register(BulkThreadSnooze, {role: 'thread:BulkAction'});
|
ComponentRegistry.register(BulkThreadSnooze, {role: 'thread:BulkAction'});
|
||||||
|
ComponentRegistry.register(SnoozeMailLabel, {role: 'ThreadList:Label'});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deactivate() {
|
export function deactivate() {
|
||||||
ComponentRegistry.unregister(ToolbarSnooze);
|
ComponentRegistry.unregister(ToolbarSnooze);
|
||||||
ComponentRegistry.unregister(QuickActionSnoozeButton);
|
ComponentRegistry.unregister(SnoozeQuickActionButton);
|
||||||
ComponentRegistry.unregister(BulkThreadSnooze);
|
ComponentRegistry.unregister(BulkThreadSnooze);
|
||||||
|
ComponentRegistry.unregister(SnoozeMailLabel);
|
||||||
this.snoozeStore.deactivate()
|
this.snoozeStore.deactivate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,4 +5,4 @@ export const PLUGIN_ID = plugin.appId[NylasEnv.config.get("env")];
|
||||||
export const PLUGIN_NAME = "Snooze Plugin"
|
export const PLUGIN_NAME = "Snooze Plugin"
|
||||||
export const SNOOZE_CATEGORY_NAME = "N1-Snoozed"
|
export const SNOOZE_CATEGORY_NAME = "N1-Snoozed"
|
||||||
export const DATE_FORMAT_LONG = 'ddd, MMM D, YYYY h:mmA'
|
export const DATE_FORMAT_LONG = 'ddd, MMM D, YYYY h:mmA'
|
||||||
export const DATE_FORMAT_SHORT = 'MMM D h:mmA'
|
export const DATE_FORMAT_SHORT = 'MMM D, h:mmA'
|
||||||
|
|
44
internal_packages/thread-snooze/lib/snooze-mail-label.jsx
Normal file
44
internal_packages/thread-snooze/lib/snooze-mail-label.jsx
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
import _ from 'underscore';
|
||||||
|
import React, {Component, PropTypes} from 'react';
|
||||||
|
import {RetinaImg, MailLabel} from 'nylas-component-kit';
|
||||||
|
import {SNOOZE_CATEGORY_NAME, PLUGIN_ID} from './snooze-constants';
|
||||||
|
import {snoozeMessage} from './snooze-utils';
|
||||||
|
|
||||||
|
|
||||||
|
class SnoozeMailLabel extends Component {
|
||||||
|
static displayName = 'SnoozeMailLabel';
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
thread: PropTypes.object,
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {thread} = this.props;
|
||||||
|
if (_.findWhere(thread.categories, {displayName: SNOOZE_CATEGORY_NAME})) {
|
||||||
|
const metadata = thread.metadataForPluginId(PLUGIN_ID);
|
||||||
|
if (metadata) {
|
||||||
|
// TODO this is such a hack
|
||||||
|
const {snoozeDate} = metadata;
|
||||||
|
const message = snoozeMessage(snoozeDate).replace('Snoozed', '')
|
||||||
|
const content = (
|
||||||
|
<span className="snooze-mail-label">
|
||||||
|
<RetinaImg
|
||||||
|
name="icon-snoozed.png"
|
||||||
|
mode={RetinaImg.Mode.ContentIsMask} />
|
||||||
|
<span className="date-message">{message}</span>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
const label = {
|
||||||
|
displayName: content,
|
||||||
|
isLockedCategory: ()=> true,
|
||||||
|
hue: ()=> 259,
|
||||||
|
}
|
||||||
|
return <MailLabel label={label} key={'snooze-message-' + thread.id} />;
|
||||||
|
}
|
||||||
|
return <span />
|
||||||
|
}
|
||||||
|
return <span />
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SnoozeMailLabel;
|
|
@ -1,7 +1,7 @@
|
||||||
/** @babel */
|
/** @babel */
|
||||||
import _ from 'underscore';
|
import _ from 'underscore';
|
||||||
import {Actions, NylasAPI, AccountStore} from 'nylas-exports';
|
import {Actions, NylasAPI, AccountStore} from 'nylas-exports';
|
||||||
import {moveThreadsToSnooze} from './snooze-category-helpers';
|
import {moveThreadsToSnooze, moveThreadsFromSnooze} from './snooze-utils';
|
||||||
import {PLUGIN_ID, PLUGIN_NAME} from './snooze-constants';
|
import {PLUGIN_ID, PLUGIN_NAME} from './snooze-constants';
|
||||||
import SnoozeActions from './snooze-actions';
|
import SnoozeActions from './snooze-actions';
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ class SnoozeStore {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.catch((error)=> {
|
.catch((error)=> {
|
||||||
|
moveThreadsFromSnooze(threads)
|
||||||
Actions.closePopover();
|
Actions.closePopover();
|
||||||
NylasEnv.reportError(error);
|
NylasEnv.reportError(error);
|
||||||
NylasEnv.showErrorDialog(`Sorry, we were unable to save your snooze settings. ${error.message}`);
|
NylasEnv.showErrorDialog(`Sorry, we were unable to save your snooze settings. ${error.message}`);
|
||||||
|
|
|
@ -15,6 +15,25 @@ import {
|
||||||
} from 'nylas-exports';
|
} from 'nylas-exports';
|
||||||
import {SNOOZE_CATEGORY_NAME, DATE_FORMAT_SHORT} from './snooze-constants'
|
import {SNOOZE_CATEGORY_NAME, DATE_FORMAT_SHORT} from './snooze-constants'
|
||||||
|
|
||||||
|
export function snoozeMessage(snoozeDate) {
|
||||||
|
let message = 'Snoozed'
|
||||||
|
if (snoozeDate) {
|
||||||
|
let dateFormat = DATE_FORMAT_SHORT
|
||||||
|
const date = moment(snoozeDate)
|
||||||
|
const now = moment()
|
||||||
|
const hourDifference = moment.duration(date.diff(now)).asHours()
|
||||||
|
|
||||||
|
if (hourDifference < 24) {
|
||||||
|
dateFormat = dateFormat.replace('MMM D, ', '');
|
||||||
|
}
|
||||||
|
if (date.minutes() === 0) {
|
||||||
|
dateFormat = dateFormat.replace(':mm', '');
|
||||||
|
}
|
||||||
|
|
||||||
|
message += ` until ${DateUtils.format(date, dateFormat)}`;
|
||||||
|
}
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
export function createSnoozeCategory(accountId, name = SNOOZE_CATEGORY_NAME) {
|
export function createSnoozeCategory(accountId, name = SNOOZE_CATEGORY_NAME) {
|
||||||
const category = new Category({
|
const category = new Category({
|
||||||
|
@ -76,7 +95,7 @@ export function getSnoozeCategoriesByAccount(accounts = AccountStore.accounts())
|
||||||
|
|
||||||
|
|
||||||
export function groupProcessedThreadsByAccountId(categoriesByAccountId, threads) {
|
export function groupProcessedThreadsByAccountId(categoriesByAccountId, threads) {
|
||||||
return DatabaseStore.modelify(Thread, _.pluck(threads, 'id')).then((updatedThreads)=> {
|
return DatabaseStore.modelify(Thread, _.pluck(threads, 'clientId')).then((updatedThreads)=> {
|
||||||
const threadsByAccountId = {}
|
const threadsByAccountId = {}
|
||||||
updatedThreads.forEach((thread)=> {
|
updatedThreads.forEach((thread)=> {
|
||||||
const accId = thread.accountId
|
const accId = thread.accountId
|
||||||
|
@ -95,15 +114,9 @@ export function groupProcessedThreadsByAccountId(categoriesByAccountId, threads)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export function moveThreads(threads, categoriesByAccountId, {snooze, snoozeDate} = {}) {
|
export function moveThreads(threads, categoriesByAccountId, {snooze, description} = {}) {
|
||||||
const inbox = CategoryStore.getInboxCategory
|
const inbox = CategoryStore.getInboxCategory
|
||||||
const snoozeCat = (accId)=> categoriesByAccountId[accId]
|
const snoozeCat = (accId)=> categoriesByAccountId[accId]
|
||||||
let description = 'Snoozed'
|
|
||||||
if (snoozeDate) {
|
|
||||||
const date = moment(snoozeDate)
|
|
||||||
description += ` until ${DateUtils.format(date, DATE_FORMAT_SHORT)}`
|
|
||||||
}
|
|
||||||
|
|
||||||
const tasks = TaskFactory.tasksForApplyingCategories({
|
const tasks = TaskFactory.tasksForApplyingCategories({
|
||||||
threads,
|
threads,
|
||||||
categoriesToRemove: snooze ? inbox : snoozeCat,
|
categoriesToRemove: snooze ? inbox : snoozeCat,
|
||||||
|
@ -125,7 +138,8 @@ export function moveThreads(threads, categoriesByAccountId, {snooze, snoozeDate}
|
||||||
export function moveThreadsToSnooze(threads, snoozeDate) {
|
export function moveThreadsToSnooze(threads, snoozeDate) {
|
||||||
return getSnoozeCategoriesByAccount()
|
return getSnoozeCategoriesByAccount()
|
||||||
.then((categoriesByAccountId)=> {
|
.then((categoriesByAccountId)=> {
|
||||||
return moveThreads(threads, categoriesByAccountId, {snooze: true, snoozeDate})
|
const description = snoozeMessage(snoozeDate)
|
||||||
|
return moveThreads(threads, categoriesByAccountId, {snooze: true, description})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,6 +147,7 @@ export function moveThreadsToSnooze(threads, snoozeDate) {
|
||||||
export function moveThreadsFromSnooze(threads) {
|
export function moveThreadsFromSnooze(threads) {
|
||||||
return getSnoozeCategoriesByAccount()
|
return getSnoozeCategoriesByAccount()
|
||||||
.then((categoriesByAccountId)=> {
|
.then((categoriesByAccountId)=> {
|
||||||
return moveThreads(threads, categoriesByAccountId, {snooze: false})
|
const description = 'Unsnoozed';
|
||||||
|
return moveThreads(threads, categoriesByAccountId, {snooze: false, description})
|
||||||
})
|
})
|
||||||
}
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
@snooze-color: #472B82;
|
||||||
|
|
||||||
|
.snooze-mail-label {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
img {
|
||||||
|
background-color: @snooze-color;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
BIN
static/images/thread-list/icon-snoozed@1x.png
Normal file
BIN
static/images/thread-list/icon-snoozed@1x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
BIN
static/images/thread-list/icon-snoozed@2x.png
Normal file
BIN
static/images/thread-list/icon-snoozed@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
Loading…
Reference in a new issue