feat(popout-threads) Add functionality to open threads in popout windows

Summary:
Threads can now be opened in separate windows. This can be done via the popout
icon next to the print icon, or by double-clicking the thread when in double-
pane mode. Note that the single-click action is still fired, which is why
double-clicking does not work in single-pane mode. The popout icon changes to a
pop-in icon while in the popout window, to allow users to collapse it back into
the main window.

Test Plan: Tested locally

Reviewers: evan, juan

Reviewed By: juan

Subscribers: sdw

Differential Revision: https://phab.nylas.com/D3332
This commit is contained in:
Halla Moore 2016-10-12 13:55:04 -07:00
parent f409160273
commit 1c675935a7
22 changed files with 121 additions and 22 deletions

View file

@ -13,6 +13,7 @@
"windowTypes": {
"default": true,
"composer": true,
"composer-preload": true
"composer-preload": true,
"thread-popout": true
}
}

View file

@ -21,7 +21,8 @@
},
"windowTypes": {
"default": true,
"composer": true
"composer": true,
"thread-popout": true
},
"license": "GPL-3.0"
}

View file

@ -16,7 +16,8 @@
},
"windowTypes": {
"default": true,
"composer": true
"composer": true,
"thread-popout": true
},
"dependencies": {
"marked": "^0.3",

View file

@ -10,7 +10,8 @@
},
"windowTypes": {
"default": true,
"composer": true
"composer": true,
"thread-popout": true
},
"dependencies": {
}

View file

@ -10,7 +10,8 @@
},
"windowTypes": {
"default": true,
"composer": true
"composer": true,
"thread-popout": true
},
"dependencies": {
}

View file

@ -16,6 +16,7 @@
},
"windowTypes": {
"default": true,
"composer": true
"composer": true,
"thread-popout": true
}
}

View file

@ -19,6 +19,7 @@
},
"windowTypes": {
"default": true,
"composer": true
"composer": true,
"thread-popout": true
}
}

View file

@ -115,6 +115,10 @@ export function activate() {
ComponentRegistry.register(ComposeButton, {
location: WorkspaceStore.Location.RootSidebar.Toolbar,
});
} else if (NylasEnv.isThreadWindow()) {
ComponentRegistry.register(ComposerViewForDraftClientId, {
role: 'Composer',
});
} else {
NylasEnv.getCurrentWindow().setMinimumSize(480, 250);
ComponentRegistry.register(ComposerWithWindowProps, {

View file

@ -15,6 +15,7 @@
"windowTypes": {
"default": true,
"composer": true,
"composer-preload": true
"composer-preload": true,
"thread-popout": true
}
}

View file

@ -17,6 +17,7 @@
"license": "GPL-3.0",
"windowTypes": {
"default": true,
"composer": true
"composer": true,
"thread-popout": true
}
}

View file

@ -1,6 +1,9 @@
{ComponentRegistry,
ExtensionRegistry,
WorkspaceStore} = require 'nylas-exports'
WorkspaceStore,
DatabaseStore,
Actions,
Thread} = require 'nylas-exports'
MessageList = require("./message-list")
MessageListHiddenMessagesToggle = require('./message-list-hidden-messages-toggle').default
@ -10,18 +13,27 @@ SidebarParticipantPicker = require('./sidebar-participant-picker').default
module.exports =
activate: ->
# Register Message List Actions we provide globally
ComponentRegistry.register MessageList,
location: WorkspaceStore.Location.MessageList
if NylasEnv.isMainWindow()
# Register Message List Actions we provide globally
ComponentRegistry.register MessageList,
location: WorkspaceStore.Location.MessageList
ComponentRegistry.register SidebarParticipantPicker,
location: WorkspaceStore.Location.MessageListSidebar
ComponentRegistry.register SidebarParticipantPicker,
location: WorkspaceStore.Location.MessageListSidebar
ComponentRegistry.register SidebarPluginContainer,
location: WorkspaceStore.Location.MessageListSidebar
ComponentRegistry.register SidebarPluginContainer,
location: WorkspaceStore.Location.MessageListSidebar
ComponentRegistry.register MessageListHiddenMessagesToggle,
role: 'MessageListHeaders'
ComponentRegistry.register MessageListHiddenMessagesToggle,
role: 'MessageListHeaders'
else
# This is for the thread-popout window.
ComponentRegistry.register(MessageList, {location: WorkspaceStore.Location.Center})
threadId = NylasEnv.getWindowProps().threadId;
# We need to locate the thread and focus it so that the MessageList displays it
DatabaseStore.find(Thread, threadId).then((thread) =>
Actions.setFocus({collection: 'thread', item: thread})
)
deactivate: ->
ComponentRegistry.unregister MessageList

View file

@ -204,6 +204,7 @@ class MessageList extends React.Component
<div onClick={@_onPrintThread}>
<RetinaImg name="print.png" title="Print Thread" mode={RetinaImg.Mode.ContentIsMask}/>
</div>
{@_renderPopoutToggle()}
</div>
_renderExpandToggle: =>
@ -218,6 +219,17 @@ class MessageList extends React.Component
<RetinaImg name={"collapse.png"} title={"Collapse All"} mode={RetinaImg.Mode.ContentIsMask}/>
</div>
_renderPopoutToggle: =>
if NylasEnv.isThreadWindow()
<div onClick={@_onPopThreadIn}>
<RetinaImg name="thread-popin.png" title="Pop thread in" mode={RetinaImg.Mode.ContentIsMask}/>
</div>
else
<div onClick={@_onPopoutThread}>
<RetinaImg name="thread-popout.png" title="Popout thread" mode={RetinaImg.Mode.ContentIsMask}/>
</div>
_renderReplyArea: =>
<div className="footer-reply-area-wrap" onClick={@_onClickReplyArea} key='reply-area'>
<div className="footer-reply-area">
@ -250,6 +262,18 @@ class MessageList extends React.Component
node = ReactDOM.findDOMNode(@)
Actions.printThread(@state.currentThread, node.innerHTML)
_onPopThreadIn: =>
return unless @state.currentThread
Actions.focusThreadMainWindow(@state.currentThread)
NylasEnv.close()
_onPopoutThread: =>
return unless @state.currentThread
Actions.popoutThread(@state.currentThread)
# This returns the single-pane view to the inbox, and does nothing for
# double-pane view because we're at the root sheet.
Actions.popSheet()
_onClickReplyArea: =>
return unless @state.currentThread
Actions.composeReply({

View file

@ -7,5 +7,9 @@
"private": true,
"engines": {
"nylas": "*"
},
"windowTypes": {
"default": true,
"thread-popout": true
}
}

View file

@ -14,7 +14,8 @@
},
"windowTypes": {
"default": true,
"composer": true
"composer": true,
"thread-popout": true
},
"dependencies": {
"tld": "^0.0.2"

View file

@ -10,7 +10,8 @@
},
"windowTypes": {
"default": true,
"composer": true
"composer": true,
"thread-popout": true
},
"dependencies": {
}

View file

@ -101,6 +101,7 @@ class ThreadList extends React.Component
scrollTooltipComponent={ThreadListScrollTooltip}
emptyComponent={EmptyListState}
keymapHandlers={@_keymapHandlers()}
onDoubleClick={(thread) -> Actions.popoutThread(thread)}
onDragStart={@_onDragStart}
onDragEnd={@_onDragEnd}
draggable="true" />

View file

@ -305,6 +305,30 @@ class Actions
###
@printThread: ActionScopeWindow
###
Public: Display the thread in a new popout window
*Scope: Window*
```
thread = <Thread>
Actions.popoutThread(thread)
```
###
@popoutThread: ActionScopeWindow
###
Public: Display the thread in the main window
*Scope: Global*
```
thread = <Thread>
Actions.focusThreadMainWindow(thread)
```
###
@focusThreadMainWindow: ActionScopeGlobal
###
Public: Create a new reply to the provided threadId and messageId and populate
it with the body provided.

View file

@ -107,6 +107,8 @@ class MessageStore extends NylasStore
@listenTo Actions.toggleAllMessagesExpanded, @_onToggleAllMessagesExpanded
@listenTo Actions.toggleHiddenMessages, @_onToggleHiddenMessages
@listenTo FocusedPerspectiveStore, @_onPerspectiveChanged
@listenTo Actions.popoutThread, @_onPopoutThread
@listenTo Actions.focusThreadMainWindow, @_onFocusThreadMainWindow
_onPerspectiveChanged: =>
@trigger()
@ -313,6 +315,20 @@ class MessageStore extends NylasStore
items
_onPopoutThread: (thread) ->
NylasEnv.newWindow
title: false, # MessageList already displays the thread subject
hidden: false,
windowKey: "thread-#{thread.id}",
windowType: 'thread-popout',
windowProps: threadId: thread.id,
_onFocusThreadMainWindow: (thread) ->
if NylasEnv.isMainWindow()
Actions.setFocus({collection: 'thread', item: thread})
NylasEnv.focus()
store = new MessageStore()
store.registerExtension = deprecate(
'MessageStore.registerExtension',

View file

@ -360,6 +360,9 @@ class NylasEnvConstructor
isComposerWindow: ->
@getWindowType() in ["composer", "composer-preload"]
isThreadWindow: ->
@getWindowType() is 'thread-popout'
getWindowType: ->
@getLoadSettings().windowType

@ -1 +1 @@
Subproject commit ddb1789abc9aa34ac9a3fb893e7ee71e7893af67
Subproject commit 26431475c6590262a190e572d0717fd730827cff

Binary file not shown.

After

Width:  |  Height:  |  Size: 678 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 619 B