diff --git a/internal_packages/account-sidebar/lib/account-sidebar-store.coffee b/internal_packages/account-sidebar/lib/account-sidebar-store.coffee
index 29af93421..a7ec5b3cd 100644
--- a/internal_packages/account-sidebar/lib/account-sidebar-store.coffee
+++ b/internal_packages/account-sidebar/lib/account-sidebar-store.coffee
@@ -44,11 +44,8 @@ class AccountSidebarStore extends NylasStore
account = AccountStore.current()
return unless account
- viewFilterForCategory = (cat) ->
- return MailViewFilter.forCategory(cat)
-
userCategories = CategoryStore.getUserCategories()
- userCategoryViews = _.map(userCategories, viewFilterForCategory)
+ userCategoryItems = _.map(userCategories, @_sidebarItemForCategory)
# Our drafts are displayed via the `DraftListSidebarItem` which
# is loading into the `Drafts` Sheet.
@@ -56,30 +53,33 @@ class AccountSidebarStore extends NylasStore
standardCategories = _.reject standardCategories, (category) =>
category.name is "drafts"
- standardViews = _.map(standardCategories, viewFilterForCategory)
-
- starredView = MailViewFilter.forStarred()
- standardViews.splice(1, 0, starredView)
+ standardCategoryItems = _.map(standardCategories, @_sidebarItemForCategory)
+ starredItem = @_sidebarItemForMailView('starred', MailViewFilter.forStarred())
# Find root views and add them to the bottom of the list (Drafts, etc.)
- _.each WorkspaceStore.Sheet, (sheet) ->
- if sheet.root and sheet.name
- standardViews.push(sheet)
+ standardItems = standardCategoryItems
+ standardItems.splice(1, 0, starredItem)
+ standardItems.push(WorkspaceStore.sidebarItems()...)
@_sections = []
@_sections.push
label: 'Mailboxes'
- items: standardViews
+ items: standardItems
type: 'mailboxes'
@_sections.push
label: CategoryStore.categoryLabel()
- items: userCategoryViews
+ items: userCategoryItems
type: 'category'
@trigger()
- _isStandardCategory: (category) =>
- category.name and category.name in CategoryStore.standardCategories
+ _sidebarItemForMailView: (id, filter) =>
+ new WorkspaceStore.SidebarItem({id: id, name: filter.name, mailViewFilter: filter})
+
+ _sidebarItemForCategory: (category) =>
+ filter = MailViewFilter.forCategory(category)
+ @_sidebarItemForMailView(category.id, filter)
+
module.exports = new AccountSidebarStore()
diff --git a/internal_packages/account-sidebar/lib/account-sidebar.cjsx b/internal_packages/account-sidebar/lib/account-sidebar.cjsx
index 13425d5bc..b08828890 100644
--- a/internal_packages/account-sidebar/lib/account-sidebar.cjsx
+++ b/internal_packages/account-sidebar/lib/account-sidebar.cjsx
@@ -1,13 +1,12 @@
React = require 'react'
-{Actions, MailViewFilter, AccountStore} = require("nylas-exports")
+{Actions, MailViewFilter, WorkspaceStore} = require("nylas-exports")
{ScrollRegion} = require("nylas-component-kit")
SidebarDividerItem = require("./account-sidebar-divider-item")
SidebarSheetItem = require("./account-sidebar-sheet-item")
+AccountSwitcher = require ("./account-switcher")
AccountSidebarStore = require ("./account-sidebar-store")
AccountSidebarMailViewItem = require("./account-sidebar-mail-view-item")
-crypto = require 'crypto'
{RetinaImg} = require 'nylas-component-kit'
-classNames = require 'classnames'
class AccountSidebar extends React.Component
@displayName: 'AccountSidebar'
@@ -19,169 +18,64 @@ class AccountSidebar extends React.Component
constructor: (@props) ->
@state = @_getStateFromStores()
- @state.showing = false
componentDidMount: =>
@unsubscribers = []
@unsubscribers.push AccountSidebarStore.listen @_onStoreChange
- @unsubscribers.push AccountStore.listen @_onStoreChange
- # It's important that every React class explicitly stops listening to
- # atom events before it unmounts. Thank you event-kit
- # This can be fixed via a Reflux mixin
componentWillUnmount: =>
unsubscribe() for unsubscribe in @unsubscribers
render: =>
- _accountSwitcher: =>
- return undefined if @state.accounts.length < 1
-
-
- {@_renderAccount @state.account, true}
- {@_renderDropdown()}
-
-
- _renderAccount: (account, isPrimaryItem) =>
- classes = classNames
- "account": true
- "item": true
- "dropdown-item-padding": not isPrimaryItem
- "active": account is @state.account
- "bg-color-hover": not isPrimaryItem
- "primary-item": isPrimaryItem
- "account-option": not isPrimaryItem
-
- email = account.emailAddress.trim().toLowerCase()
-
- if isPrimaryItem
- dropdownClasses = classNames
- "account-switcher-dropdown": true,
- "account-switcher-dropdown-hidden": @state.showing
-
- dropdownArrow =
-
-
-
- onClick = @_toggleDropdown
-
- else
- onClick = =>
- @_onSwitchAccount account
-
-
-
- {dropdownArrow}
-
- {email}
-
-
-
-
-
- _renderNewAccountOption: =>
-
-
-
-
-
- Add account…
-
-
-
-
-
- _renderDropdown: =>
- display = if @state.showing then "block" else "none"
- # display = "block"
-
- accounts = @state.accounts.map (a) =>
- @_renderAccount(a)
-
-
- {accounts}
- {@_renderNewAccountOption()}
-
-
- _toggleDropdown: =>
- @setState showing: !@state.showing
-
- _gravatarUrl: (email) =>
- hash = crypto.createHash('md5').update(email, 'utf8').digest('hex')
-
- "url(http://www.gravatar.com/avatar/#{hash}?d=blank&s=56)"
-
_sections: =>
- return @state.sections.map (section) =>
+ @state.sections.map (section) =>
{section.label}
{@_itemComponents(section)}
_itemComponents: (section) =>
- section.items?.map (item) =>
- return unless item
- if item instanceof MailViewFilter
-
- else
- if item.sidebarComponent
- itemClass = item.sidebarComponent
- else
- itemClass = SidebarSheetItem
+ section.items.map (item) =>
+ unless item instanceof WorkspaceStore.SidebarItem
+ throw new Error("AccountSidebar:_itemComponents: sections contained an \
+ item which was not a SidebarItem")
-
+ select={item.id is @state.selected?.id } />
+
+ else if item.mailViewFilter
+
+
+ else if item.sheet
+
+
+ else
+ throw new Error("AccountSidebar:_itemComponents: each item must have a \
+ custom component, or a sheet or mailViewFilter")
_onStoreChange: =>
@setState @_getStateFromStores()
- _onBlur: (e) =>
- target = e.nativeEvent.relatedTarget
- if target? and React.findDOMNode(@refs.button).contains(target)
- return
- @setState(showing: false)
-
- _onSwitchAccount: (account) =>
- Actions.selectAccountId(account.id)
- @setState(showing: false)
-
- _onAddAccount: =>
- require('remote').getGlobal('application').windowManager.newOnboardingWindow()
- @setState showing: false
-
_getStateFromStores: =>
sections: AccountSidebarStore.sections()
selected: AccountSidebarStore.selected()
- accounts: AccountStore.items()
- account: AccountStore.current()
module.exports = AccountSidebar
diff --git a/internal_packages/account-sidebar/lib/account-switcher.cjsx b/internal_packages/account-sidebar/lib/account-switcher.cjsx
new file mode 100644
index 000000000..c9634399d
--- /dev/null
+++ b/internal_packages/account-sidebar/lib/account-switcher.cjsx
@@ -0,0 +1,136 @@
+React = require 'react'
+{Actions, AccountStore} = require("nylas-exports")
+{ScrollRegion} = require("nylas-component-kit")
+crypto = require 'crypto'
+{RetinaImg} = require 'nylas-component-kit'
+classNames = require 'classnames'
+
+class AccountSwitcher extends React.Component
+ @displayName: 'AccountSwitcher'
+
+ constructor: (@props) ->
+ @state = @_getStateFromStores()
+ @state.showing = false
+
+ componentDidMount: =>
+ @unsubscribers = []
+ @unsubscribers.push AccountStore.listen @_onStoreChange
+
+ componentWillUnmount: =>
+ unsubscribe() for unsubscribe in @unsubscribers
+
+ render: =>
+ return undefined if @state.accounts.length < 1
+
+
+ {@_renderAccount(@state.account, true)}
+ {@_renderDropdown()}
+
+
+ _renderAccount: (account, isPrimaryItem) =>
+ classes = classNames
+ "account": true
+ "item": true
+ "dropdown-item-padding": not isPrimaryItem
+ "active": account is @state.account
+ "bg-color-hover": not isPrimaryItem
+ "primary-item": isPrimaryItem
+ "account-option": not isPrimaryItem
+
+ email = account.emailAddress.trim().toLowerCase()
+
+ if isPrimaryItem
+ dropdownClasses = classNames
+ "account-switcher-dropdown": true,
+ "account-switcher-dropdown-hidden": @state.showing
+
+ dropdownArrow =
+
+
+
+ onClick = @_toggleDropdown
+
+ else
+ onClick = =>
+ @_onSwitchAccount account
+
+
+
+ {dropdownArrow}
+
+ {email}
+
+
+
+
+
+ _renderNewAccountOption: =>
+
+
+
+
+
+ Add account…
+
+
+
+
+
+ _renderDropdown: =>
+ display = if @state.showing then "block" else "none"
+ # display = "block"
+
+ accounts = @state.accounts.map (a) =>
+ @_renderAccount(a)
+
+
+ {accounts}
+ {@_renderNewAccountOption()}
+
+
+ _toggleDropdown: =>
+ @setState showing: !@state.showing
+
+ _gravatarUrl: (email) =>
+ hash = crypto.createHash('md5').update(email, 'utf8').digest('hex')
+ "url(http://www.gravatar.com/avatar/#{hash}?d=blank&s=56)"
+
+ _onStoreChange: =>
+ @setState @_getStateFromStores()
+
+ _onBlur: (e) =>
+ target = e.nativeEvent.relatedTarget
+ if target? and React.findDOMNode(@refs.button).contains(target)
+ return
+ @setState(showing: false)
+
+ _onSwitchAccount: (account) =>
+ Actions.selectAccountId(account.id)
+ @setState(showing: false)
+
+ _onAddAccount: =>
+ require('remote').getGlobal('application').windowManager.newOnboardingWindow()
+ @setState showing: false
+
+ _getStateFromStores: =>
+ accounts: AccountStore.items()
+ account: AccountStore.current()
+
+
+module.exports = AccountSwitcher
diff --git a/internal_packages/settings/lib/main.cjsx b/internal_packages/settings/lib/main.cjsx
index b6937cf5b..ccd5a2104 100644
--- a/internal_packages/settings/lib/main.cjsx
+++ b/internal_packages/settings/lib/main.cjsx
@@ -7,7 +7,7 @@ SettingsTabsView = require "./settings-tabs-view"
module.exports =
activate: (@state={}) ->
- WorkspaceStore.defineSheet 'Settings', {root: true, supportedModes: ['list'], name: 'Plugins'},
+ WorkspaceStore.defineSheet 'Settings', {root: true, supportedModes: ['list']},
list: ['RootSidebar', 'SettingsSidebar', 'Settings']
ComponentRegistry.register SettingsTabsView,
diff --git a/internal_packages/thread-list/lib/draft-list-sidebar-item.cjsx b/internal_packages/thread-list/lib/draft-list-sidebar-item.cjsx
index 888e43fbc..f656afe0a 100644
--- a/internal_packages/thread-list/lib/draft-list-sidebar-item.cjsx
+++ b/internal_packages/thread-list/lib/draft-list-sidebar-item.cjsx
@@ -34,11 +34,11 @@ class DraftListSidebarItem extends React.Component
{unread}
-
{@props.item.name}
+
Drafts
_onClick: (event) =>
event.preventDefault()
- Actions.selectRootSheet(@props.item)
+ Actions.selectRootSheet(WorkspaceStore.Sheet.Drafts)
module.exports = DraftListSidebarItem
diff --git a/internal_packages/thread-list/lib/main.cjsx b/internal_packages/thread-list/lib/main.cjsx
index 29a7d3c00..8c4f0a6e4 100644
--- a/internal_packages/thread-list/lib/main.cjsx
+++ b/internal_packages/thread-list/lib/main.cjsx
@@ -1,6 +1,6 @@
_ = require 'underscore'
React = require "react"
-{ComponentRegistry, WorkspaceStore} = require "nylas-exports"
+{MailViewFilter, ComponentRegistry, WorkspaceStore} = require "nylas-exports"
{DownButton, UpButton, ThreadBulkArchiveButton, ThreadBulkStarButton, ThreadBulkToggleUnreadButton} = require "./thread-buttons"
{DraftDeleteButton} = require "./draft-buttons"
@@ -13,9 +13,17 @@ DraftList = require './draft-list'
module.exports =
activate: (@state={}) ->
- WorkspaceStore.defineSheet 'Drafts', {root: true, name: 'Drafts', sidebarComponent: DraftListSidebarItem},
+ WorkspaceStore.defineSheet 'Drafts', {root: true},
list: ['RootSidebar', 'DraftList']
+ @sidebarItem = new WorkspaceStore.SidebarItem
+ component: DraftListSidebarItem
+ sheet: WorkspaceStore.Sheet.Drafts
+ id: 'Drafts'
+ name: 'Drafts'
+
+ WorkspaceStore.addSidebarItem(@sidebarItem)
+
ComponentRegistry.register ThreadList,
location: WorkspaceStore.Location.ThreadList
diff --git a/src/flux/stores/workspace-store.coffee b/src/flux/stores/workspace-store.coffee
index f7ced57c7..8a0d42a51 100644
--- a/src/flux/stores/workspace-store.coffee
+++ b/src/flux/stores/workspace-store.coffee
@@ -5,6 +5,13 @@ NylasStore = require 'nylas-store'
Sheet = {}
Location = {}
+SidebarItems = {}
+
+class WorkspaceSidebarItem
+ constructor: ({@id, @component, @name, @sheet, @mailViewFilter}) ->
+ if not @sheet and not @mailViewFilter and not @component
+ throw new Error("WorkspaceSidebarItem: You must provide either a sheet \
+ component, or a mailViewFilter for the sidebar item named #{@name}")
###
Public: The WorkspaceStore manages Sheets and layout modes in the application.
@@ -40,6 +47,9 @@ class WorkspaceStore extends NylasStore
@Location = Location = {}
@Sheet = Sheet = {}
+ @SidebarItem = WorkspaceSidebarItem
+ @SidebarItems = SidebarItems = {}
+
@_hiddenLocations = {}
@_sheetStack = []
@@ -137,6 +147,20 @@ class WorkspaceStore extends NylasStore
return false unless loc
@_hiddenLocations[loc.id]?
+
+ sidebarItems: =>
+ _.values(@SidebarItems)
+
+ addSidebarItem: (item) =>
+ unless item instanceof WorkspaceSidebarItem
+ throw new Error("WorkspaceStore::addSidebarItem requires a `WorkspaceSidebarItem`")
+ @SidebarItems[item.id] = item
+ @triggerDebounced()
+
+ removeSidebarItem: (item) =>
+ delete @SidebarItems[item.id]
+ @triggerDebounced()
+
###
Managing Sheets
###