@@ -154,13 +120,7 @@ cNarrow = new ListTabular.Column
diff --git a/internal_packages/thread-list/stylesheets/thread-list.less b/internal_packages/thread-list/stylesheets/thread-list.less
index cf361eef1..63790f961 100644
--- a/internal_packages/thread-list/stylesheets/thread-list.less
+++ b/internal_packages/thread-list/stylesheets/thread-list.less
@@ -446,6 +446,12 @@ body.platform-win32 {
padding: 1px 8px;
font-size: 0.8em;
line-height: 17px;
+ .inner {
+ position: inherit;
+ }
+ .x {
+ display: none;
+ }
}
.snippet {
font-size: @font-size-small;
diff --git a/internal_packages/thread-snooze/lib/main.js b/internal_packages/thread-snooze/lib/main.js
index 74fbd7c08..6b2775db6 100644
--- a/internal_packages/thread-snooze/lib/main.js
+++ b/internal_packages/thread-snooze/lib/main.js
@@ -11,7 +11,7 @@ export function activate() {
ComponentRegistry.register(ToolbarSnooze, {role: 'message:Toolbar'});
ComponentRegistry.register(SnoozeQuickActionButton, {role: 'ThreadListQuickAction'});
ComponentRegistry.register(BulkThreadSnooze, {role: 'thread:BulkAction'});
- ComponentRegistry.register(SnoozeMailLabel, {role: 'ThreadList:Label'});
+ ComponentRegistry.register(SnoozeMailLabel, {role: 'Thread:MailLabel'});
}
export function deactivate() {
diff --git a/spec/mailbox-perspective-spec.coffee b/spec/mailbox-perspective-spec.coffee
index 0148011a7..8db33bf17 100644
--- a/spec/mailbox-perspective-spec.coffee
+++ b/spec/mailbox-perspective-spec.coffee
@@ -37,7 +37,6 @@ describe 'MailboxPerspective', ->
@perspective = MailboxPerspective.forCategories(@categories)
describe 'canReceiveThreads', ->
-
it 'returns true if the thread account ids are included in the current account ids', ->
expect(@perspective.canReceiveThreads(['a2'])).toBe true
@@ -52,6 +51,22 @@ describe 'MailboxPerspective', ->
)
expect(@perspective.canReceiveThreads(['a2'])).toBe false
+ describe 'categoriesSharedName', ->
+ it "returns the name if all the categories on the perspective have the same name", ->
+ expect(MailboxPerspective.forCategories([
+ new Category(name: 'c1', accountId: 'a1')
+ new Category(name: 'c1', accountId: 'a2')
+ ]).categoriesSharedName()).toEqual('c1')
+
+ it "returns null if there are no categories", ->
+ expect(MailboxPerspective.forStarred(['a1', 'a2']).categoriesSharedName()).toEqual(null)
+
+ it "returns null if the categories have different names", ->
+ expect(MailboxPerspective.forCategories([
+ new Category(name: 'c1', accountId: 'a1')
+ new Category(name: 'c2', accountId: 'a2')
+ ]).categoriesSharedName()).toEqual(null)
+
describe 'receiveThreads', ->
# TODO
diff --git a/src/components/mail-label-set.jsx b/src/components/mail-label-set.jsx
new file mode 100644
index 000000000..36723fd87
--- /dev/null
+++ b/src/components/mail-label-set.jsx
@@ -0,0 +1,68 @@
+import React from 'react';
+import FocusedPerspectiveStore from '../flux/stores/focused-perspective-store';
+import CategoryStore from '../flux/stores/category-store';
+import MessageStore from '../flux/stores/message-store';
+import AccountStore from '../flux/stores/account-store';
+import {MailLabel} from './mail-label';
+import Actions from '../flux/actions';
+import ChangeLabelsTask from '../flux/tasks/change-labels-task';
+import InjectedComponentSet from './injected-component-set';
+
+const LabelComponentCache = {};
+
+export default class MailLabelSet extends React.Component {
+ static displayName = 'MailLabelSet';
+
+ static propTypes = {
+ thread: React.PropTypes.object.isRequired,
+ includeCurrentCategories: React.PropTypes.boolean,
+ };
+
+ _onRemoveLabel(label) {
+ const task = new ChangeLabelsTask({
+ thread: this.props.thread,
+ labelsToRemove: [label],
+ });
+ Actions.queueTask(task);
+ }
+
+ render() {
+ const {thread, includeCurrentCategories} = this.props;
+ const labels = [];
+
+ if (AccountStore.accountForId(thread.accountId).usesLabels()) {
+ const hidden = CategoryStore.hiddenCategories(thread.accountId);
+ let current = FocusedPerspectiveStore.current().categories();
+
+ if (includeCurrentCategories || !current) {
+ current = [];
+ }
+
+ const ignoredIds = [].concat(hidden, current).map(l=> l.id);
+ const ignoredNames = MessageStore.CategoryNamesHiddenByDefault;
+
+ for (const label of thread.sortedCategories()) {
+ if (ignoredNames.includes(label.name) || ignoredIds.includes(label.id)) {
+ continue;
+ }
+ if (LabelComponentCache[label.id] === undefined) {
+ LabelComponentCache[label.id] = (
+
this._onRemoveLabel(label)}/>
+ );
+ }
+ labels.push(LabelComponentCache[label.id]);
+ }
+ }
+ return (
+ );
+ }
+}
diff --git a/src/flux/actions.coffee b/src/flux/actions.coffee
index b1b57557b..ee0a4a7be 100644
--- a/src/flux/actions.coffee
+++ b/src/flux/actions.coffee
@@ -263,6 +263,12 @@ class Actions
###
@toggleMessageIdExpanded: ActionScopeWindow
+ ###
+ Public: Toggle whether messages from trash and spam are shown in the current
+ message view.
+ ###
+ @toggleHiddenMessages: ActionScopeWindow
+
###
Public: This action toggles wether to collapse or expand all messages in a
thread depending on if there are currently collapsed messages.
diff --git a/src/flux/models/message.coffee b/src/flux/models/message.coffee
index b13283122..e23578435 100644
--- a/src/flux/models/message.coffee
+++ b/src/flux/models/message.coffee
@@ -148,11 +148,10 @@ class Message extends ModelWithMetadata
modelKey: 'replyToMessageId'
jsonKey: 'reply_to_message_id'
- 'folder': Attributes.Object
- modelKey: 'folder'
+ 'categories': Attributes.Collection
+ modelKey: 'categories'
itemClass: Category
-
@naturalSortOrder: ->
Message.attributes.date.ascending()
@@ -174,6 +173,7 @@ class Message extends ModelWithMetadata
@files ||= []
@uploads ||= []
@events ||= []
+ @categories ||= []
@
toJSON: (options) ->
@@ -192,7 +192,12 @@ class Message extends ModelWithMetadata
if json.object?
@draft = (json.object is 'draft')
- for attr in ['to', 'from', 'cc', 'bcc', 'files']
+ if json['folder']
+ @categories = @constructor.attributes.categories.fromJSON([json['folder']])
+ else if json['labels']
+ @categories = @constructor.attributes.categories.fromJSON(json['labels'])
+
+ for attr in ['to', 'from', 'cc', 'bcc', 'files', 'categories']
values = @[attr]
continue unless values and values instanceof Array
item.accountId = @accountId for item in values
diff --git a/src/flux/stores/database-store.coffee b/src/flux/stores/database-store.coffee
index 652df380e..8899bfc80 100644
--- a/src/flux/stores/database-store.coffee
+++ b/src/flux/stores/database-store.coffee
@@ -16,7 +16,7 @@ DatabaseTransaction = require './database-transaction'
{ipcRenderer} = require 'electron'
-DatabaseVersion = 18
+DatabaseVersion = 19
DatabasePhase =
Setup: 'setup'
Ready: 'ready'
diff --git a/src/flux/stores/message-store.coffee b/src/flux/stores/message-store.coffee
index b6a1742ef..9d75fa2f1 100644
--- a/src/flux/stores/message-store.coffee
+++ b/src/flux/stores/message-store.coffee
@@ -5,6 +5,7 @@ Thread = require "../models/thread"
Utils = require '../models/utils'
DatabaseStore = require "./database-store"
AccountStore = require "./account-store"
+FocusedPerspectiveStore = require './focused-perspective-store'
FocusedContentStore = require "./focused-content-store"
ChangeUnreadTask = require '../tasks/change-unread-task'
NylasAPI = require '../nylas-api'
@@ -13,6 +14,8 @@ ExtensionRegistry = require '../../extension-registry'
async = require 'async'
_ = require 'underscore'
+CategoryNamesHiddenByDefault = ['spam', 'trash']
+
class MessageStore extends NylasStore
constructor: ->
@@ -22,7 +25,16 @@ class MessageStore extends NylasStore
########### PUBLIC #####################################################
items: ->
- @_items
+ return @_items if @_showingHiddenItems
+
+ viewing = FocusedPerspectiveStore.current().categoriesSharedName()
+ viewingHidden = viewing in CategoryNamesHiddenByDefault
+
+ return @_items.filter (item) ->
+ inHidden = _.any item.categories, (cat) -> cat.name in CategoryNamesHiddenByDefault
+ return false if viewingHidden and not inHidden
+ return false if not viewingHidden and inHidden
+ return true
threadId: -> @_thread?.id
@@ -36,6 +48,9 @@ class MessageStore extends NylasStore
hasCollapsedItems: ->
_.size(@_itemsExpanded) < @_items.length
+ numberOfHiddenItems: ->
+ @_items.length - @items().length
+
itemClientIds: ->
_.pluck(@_items, "clientId")
@@ -79,6 +94,7 @@ class MessageStore extends NylasStore
@_items = []
@_itemsExpanded = {}
@_itemsLoading = false
+ @_showingHiddenItems = false
@_thread = null
@_inflight = {}
@@ -88,6 +104,11 @@ class MessageStore extends NylasStore
@listenTo FocusedContentStore, @_onFocusChanged
@listenTo Actions.toggleMessageIdExpanded, @_onToggleMessageIdExpanded
@listenTo Actions.toggleAllMessagesExpanded, @_onToggleAllMessagesExpanded
+ @listenTo Actions.toggleHiddenMessages, @_onToggleHiddenMessages
+ @listenTo FocusedPerspectiveStore, @_onPerspectiveChanged
+
+ _onPerspectiveChanged: =>
+ @trigger()
_onDataChanged: (change) =>
return unless @_thread
@@ -151,6 +172,7 @@ class MessageStore extends NylasStore
@_thread = focused
@_items = []
@_itemsLoading = true
+ @_showingHiddenItems = false
@_itemsExpanded = {}
@trigger()
@@ -187,6 +209,13 @@ class MessageStore extends NylasStore
@_items[...-1].forEach @_collapseItem
@trigger()
+ _onToggleHiddenMessages: =>
+ @_showingHiddenItems = !@_showingHiddenItems
+ @_expandItemsToDefault()
+ @_fetchExpandedBodies(@_items)
+ @_fetchExpandedAttachments(@_items)
+ @trigger()
+
_onToggleMessageIdExpanded: (id) =>
item = _.findWhere(@_items, {id})
return unless item
@@ -269,8 +298,9 @@ class MessageStore extends NylasStore
# Expand all unread messages, all drafts, and the last message
_expandItemsToDefault: ->
- for item, idx in @_items
- if item.unread or item.draft or idx is @_items.length - 1
+ visibleItems = @items()
+ for item, idx in visibleItems
+ if item.unread or item.draft or idx is visibleItems.length - 1
@_itemsExpanded[item.id] = "default"
_fetchMessages: ->
@@ -327,4 +357,6 @@ store.unregisterExtension = deprecate(
store,
store.unregisterExtension
)
+store.CategoryNamesHiddenByDefault = CategoryNamesHiddenByDefault
+
module.exports = store
diff --git a/src/global/nylas-component-kit.coffee b/src/global/nylas-component-kit.coffee
index 4ef18a29f..e8e7d0a41 100644
--- a/src/global/nylas-component-kit.coffee
+++ b/src/global/nylas-component-kit.coffee
@@ -44,6 +44,7 @@ class NylasComponentKit
@loadFrom "MailLabel", "mail-label"
@loadFrom "LabelColorizer", "mail-label"
+ @load "MailLabelSet", "mail-label-set"
@load "MailImportantIcon", 'mail-important-icon'
@loadFrom "FormItem", "generated-form"
diff --git a/src/mailbox-perspective.coffee b/src/mailbox-perspective.coffee
index 9a6608a97..3051879c9 100644
--- a/src/mailbox-perspective.coffee
+++ b/src/mailbox-perspective.coffee
@@ -81,6 +81,13 @@ class MailboxPerspective
categories: =>
[]
+ categoriesSharedName: =>
+ cats = @categories()
+ return null unless cats and cats.length > 0
+ name = cats[0].name
+ return null unless _.every cats, (cat) -> cat.name is name
+ return name
+
category: =>
return null unless @categories().length is 1
return @categories()[0]
@@ -282,7 +289,7 @@ class CategoryMailboxPerspective extends MailboxPerspective
@_categories
isInbox: =>
- @_categories[0].name is 'inbox'
+ @categoriesSharedName() is 'inbox'
canReceiveThreads: =>
super and not _.any @_categories, (c) -> c.isLockedCategory()