mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-09-04 11:44:47 +08:00
fix(getting-started): New menu item, sample package for devs
This commit is contained in:
parent
72dd3171ad
commit
f13d0e04a6
11 changed files with 176 additions and 37 deletions
|
@ -58,9 +58,9 @@ Exports =
|
|||
WorkspaceStore: require '../src/flux/stores/workspace-store'
|
||||
FocusedTagStore: require '../src/flux/stores/focused-tag-store'
|
||||
FocusedContentStore: require '../src/flux/stores/focused-content-store'
|
||||
FocusedContactsStore: require '../src/flux/stores/focused-contacts-store'
|
||||
FileUploadStore: require '../src/flux/stores/file-upload-store'
|
||||
FileDownloadStore: require '../src/flux/stores/file-download-store'
|
||||
FocusedContactsStore: require '../src/flux/stores/focused-contacts-store'
|
||||
UnreadCountStore: require '../src/flux/stores/unread-count-store'
|
||||
|
||||
# Errors
|
||||
|
|
|
@ -25,6 +25,9 @@ SettingsPackagesStore = Reflux.createStore
|
|||
@listenTo SettingsActions.refreshFeaturedPackages, @_refreshFeatured
|
||||
@listenTo SettingsActions.refreshInstalledPackages, @_refreshInstalled
|
||||
|
||||
atom.commands.add 'body',
|
||||
'application:create-package': => @_onCreatePackage()
|
||||
|
||||
@listenTo SettingsActions.createPackage, @_onCreatePackage
|
||||
@listenTo SettingsActions.updatePackage, @_onUpdatePackage
|
||||
@listenTo SettingsActions.setGlobalSearchValue, @_onGlobalSearchChange
|
||||
|
|
|
@ -54,13 +54,14 @@
|
|||
submenu: [
|
||||
{ label: 'Toggle Hacker Theme', command: 'application:toggle-theme' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Open In Dev Mode...', command: 'application:open-dev' }
|
||||
{ label: 'Relaunch with Debug Flags...', command: 'application:open-dev' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Open Detailed Logs', command: 'window:open-errorreporter-logs' }
|
||||
{ label: 'Ship Detailed Logs to Nylas', command: 'application:ship-logs' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Create a Package...', command: 'application:create-package' }
|
||||
{ label: 'Run Package Specs...', command: 'application:run-package-specs' }
|
||||
{ label: 'Run Nylas Mail Specs', command: 'application:run-all-specs' }
|
||||
{ label: 'Run Package Specs', command: 'application:run-package-specs' }
|
||||
{ label: 'Toggle Developer Tools', command: 'window:toggle-dev-tools' }
|
||||
]
|
||||
}
|
||||
|
|
|
@ -37,13 +37,14 @@
|
|||
submenu: [
|
||||
{ label: 'Toggle Hacker Theme', command: 'application:toggle-theme' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Open In &Dev Mode...', command: 'application:open-dev' }
|
||||
{ label: 'Relaunch with &Debug Flags...', command: 'application:open-dev' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Open Detailed Logs', command: 'window:open-errorreporter-logs' }
|
||||
{ label: 'Ship Detailed Logs to Nylas', command: 'application:ship-logs' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Create a Package...', command: 'application:create-package' }
|
||||
{ label: 'Run Package &Specs...', command: 'application:run-package-specs' }
|
||||
{ label: 'Run &Nylas Mail Specs', command: 'application:run-all-specs' }
|
||||
{ label: 'Run Package &Specs', command: 'application:run-package-specs' }
|
||||
{ label: 'Toggle Developer &Tools', command: 'window:toggle-dev-tools' }
|
||||
]
|
||||
}
|
||||
|
|
|
@ -39,13 +39,14 @@
|
|||
submenu: [
|
||||
{ label: 'Toggle Hacker Theme', command: 'application:toggle-theme' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Open In &Dev Mode...', command: 'application:open-dev' }
|
||||
{ label: 'Relaunch with &Debug Flags...', command: 'application:open-dev' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Open Detailed Logs', command: 'window:open-errorreporter-logs' }
|
||||
{ label: 'Ship Detailed Logs to Nylas', command: 'application:ship-logs' }
|
||||
{ type: 'separator' }
|
||||
{ label: 'Run &Atom Specs', command: 'application:run-all-specs' }
|
||||
{ label: 'Run Package &Specs', command: 'application:run-package-specs' }
|
||||
{ label: 'Create a Package...', command: 'application:create-package' }
|
||||
{ label: 'Run Package &Specs...', command: 'application:run-package-specs' }
|
||||
{ label: 'Run &Nylas Mail Specs', command: 'application:run-all-specs' }
|
||||
{ label: 'Toggle Developer &Tools', command: 'window:toggle-dev-tools' }
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
## My Package
|
||||
|
||||
A sample package for Nylas Mail.
|
||||
A sample package for Nylas Mail. It demonstrates how to add components to the composer's action bar and the message sidebar. Enjoy!
|
|
@ -1,30 +1,19 @@
|
|||
{Utils, React, ComponentRegistry} = require 'nylas-exports'
|
||||
{RetinaImg} = require 'nylas-component-kit'
|
||||
{ComponentRegistry} = require 'nylas-exports'
|
||||
|
||||
class MyButton extends React.Component
|
||||
|
||||
# Adding a `displayName` makes debugging React easier
|
||||
@displayName: 'MyButton'
|
||||
|
||||
render: =>
|
||||
<div className="my-package">
|
||||
<button className="btn btn-toolbar" onClick={@_onClick}>
|
||||
Hello World
|
||||
</button>
|
||||
</div>
|
||||
#
|
||||
_onClick: =>
|
||||
dialog = require('remote').require('dialog')
|
||||
dialog.showErrorBox('Success!', 'Button was clicked.')
|
||||
MyComposerButton = require './my-composer-button'
|
||||
MyMessageSidebar = require './my-message-sidebar'
|
||||
|
||||
module.exports =
|
||||
# Activate is called when the package is loaded. If your package previously
|
||||
# saved state using `serialize` it is provided.
|
||||
#
|
||||
activate: (@state) ->
|
||||
ComponentRegistry.register MyButton,
|
||||
ComponentRegistry.register MyComposerButton,
|
||||
role: 'Composer:ActionButton'
|
||||
|
||||
ComponentRegistry.register MyMessageSidebar,
|
||||
role: 'sidebar:focusedContactInfo'
|
||||
|
||||
# Serialize is called when your package is about to be unmounted.
|
||||
# You can return a state object that will be passed back to your package
|
||||
# when it is re-activated.
|
||||
|
@ -37,4 +26,5 @@ module.exports =
|
|||
# subscribing to events, release them here.
|
||||
#
|
||||
deactivate: ->
|
||||
ComponentRegistry.unregister(MyButton)
|
||||
ComponentRegistry.unregister(MyComposerButton)
|
||||
ComponentRegistry.unregister(MyMessageSidebar)
|
||||
|
|
43
static/package-template/lib/my-composer-button.cjsx
Normal file
43
static/package-template/lib/my-composer-button.cjsx
Normal file
|
@ -0,0 +1,43 @@
|
|||
{Utils, DraftStore, React} = require 'nylas-exports'
|
||||
{RetinaImg} = require 'nylas-component-kit'
|
||||
|
||||
class MyComposerButton extends React.Component
|
||||
|
||||
# Note: You should assign a new displayName to avoid naming
|
||||
# conflicts when injecting your item
|
||||
@displayName: 'MyComposerButton'
|
||||
|
||||
# When you register as a composer button, you receive a
|
||||
# reference to the draft, and you can look it up to perform
|
||||
# actions and retrieve data.
|
||||
@propTypes:
|
||||
draftLocalId: React.PropTypes.string.isRequired
|
||||
|
||||
render: =>
|
||||
<div className="my-package">
|
||||
<button className="btn btn-toolbar" onClick={ => @_onClick()} ref="button">
|
||||
Hello World
|
||||
</button>
|
||||
</div>
|
||||
|
||||
_onClick: =>
|
||||
# To retrieve information about the draft, we fetch the current editing
|
||||
# session from the draft store. We can access attributes of the draft
|
||||
# and add changes to the session which will be appear immediately.
|
||||
DraftStore.sessionForLocalId(@props.draftLocalId).then (session) =>
|
||||
newSubject = "#{session.draft().subject} - It Worked!"
|
||||
|
||||
dialog = @_getDialog()
|
||||
dialog.showMessageBox
|
||||
title: 'Here we go...'
|
||||
detail: "Adjusting the subject line To `#{newSubject}`"
|
||||
buttons: ['OK']
|
||||
type: 'info'
|
||||
|
||||
session.changes.add({subject: newSubject})
|
||||
|
||||
_getDialog: =>
|
||||
require('remote').require('dialog')
|
||||
|
||||
|
||||
module.exports = MyComposerButton
|
68
static/package-template/lib/my-message-sidebar.cjsx
Normal file
68
static/package-template/lib/my-message-sidebar.cjsx
Normal file
|
@ -0,0 +1,68 @@
|
|||
{Utils,
|
||||
React,
|
||||
FocusedContactsStore} = require 'nylas-exports'
|
||||
{RetinaImg} = require 'nylas-component-kit'
|
||||
|
||||
class MyMessageSidebar extends React.Component
|
||||
@displayName: 'MyMessageSidebar'
|
||||
|
||||
# Providing container styles tells the app how to constrain
|
||||
# the column your component is being rendered in. The min and
|
||||
# max size of the column are chosen automatically based on
|
||||
# these values.
|
||||
@containerStyles:
|
||||
order: 1
|
||||
maxWidth: 300
|
||||
minWidth: 200
|
||||
flexShrink: 0
|
||||
|
||||
# This sidebar component listens to the FocusedContactStore,
|
||||
# which gives us access to the Contact object of the currently
|
||||
# selected person in the conversation. If you wanted to take
|
||||
# the contact and fetch your own data, you'd want to create
|
||||
# your own store, so the flow of data would be:
|
||||
#
|
||||
# FocusedContactStore => Your Store => Your Component
|
||||
#
|
||||
constructor: (@props) ->
|
||||
@state = @_getStateFromStores()
|
||||
|
||||
componentDidMount: =>
|
||||
@unsubscribe = FocusedContactsStore.listen(@_onChange)
|
||||
|
||||
componentWillUnmount: =>
|
||||
@unsubscribe()
|
||||
|
||||
render: =>
|
||||
if @state.contact
|
||||
content = @_renderContent()
|
||||
else
|
||||
content = @_renderPlaceholder()
|
||||
|
||||
<div className="my-message-sidebar">
|
||||
{content}
|
||||
</div>
|
||||
|
||||
_renderContent: =>
|
||||
# Want to include images or other static assets in your components?
|
||||
# Reference them using the nylas:// URL scheme:
|
||||
#
|
||||
# <RetinaImg
|
||||
# url="nylas://<<package.name>>/assets/checkmark_template@2x.png"
|
||||
# mode={RetinaImg.Mode.ContentIsMask}/>
|
||||
#
|
||||
<div className="header">
|
||||
<h1>Hi there {@state.contact.name}!</h1>
|
||||
</div>
|
||||
|
||||
_renderPlaceholder: =>
|
||||
<div> No Data Available </div>
|
||||
|
||||
_onChange: =>
|
||||
@setState(@_getStateFromStores())
|
||||
|
||||
_getStateFromStores: =>
|
||||
contact: FocusedContactsStore.focusedContact()
|
||||
|
||||
|
||||
module.exports = MyMessageSidebar
|
|
@ -1,12 +1,19 @@
|
|||
describe "AccountSidebarStore", ->
|
||||
xit "should update it's selected ID when the focusTag action fires", ->
|
||||
true
|
||||
{ComponentRegistry} = require 'nylas-exports'
|
||||
{activate, deactivate} = require '../lib/main'
|
||||
|
||||
xit "should update when the DatabaseStore emits changes to tags", ->
|
||||
true
|
||||
MyMessageSidebar = require '../lib/my-message-sidebar'
|
||||
MyComposerButton = require '../lib/my-composer-button'
|
||||
|
||||
xit "should update when the NamespaceStore emits", ->
|
||||
true
|
||||
describe "activate", ->
|
||||
it "should register the composer button and sidebar", ->
|
||||
spyOn(ComponentRegistry, 'register')
|
||||
activate()
|
||||
expect(ComponentRegistry.register).toHaveBeenCalledWith(MyComposerButton, {role: 'Composer:ActionButton'})
|
||||
expect(ComponentRegistry.register).toHaveBeenCalledWith(MyMessageSidebar, {role: 'sidebar:focusedContactInfo'})
|
||||
|
||||
xit "should provide an array of sections to the sidebar view", ->
|
||||
true
|
||||
describe "deactivate", ->
|
||||
it "should unregister the composer button and sidebar", ->
|
||||
spyOn(ComponentRegistry, 'unregister')
|
||||
deactivate()
|
||||
expect(ComponentRegistry.unregister).toHaveBeenCalledWith(MyComposerButton)
|
||||
expect(ComponentRegistry.unregister).toHaveBeenCalledWith(MyMessageSidebar)
|
||||
|
|
25
static/package-template/spec/my-composer-button-spec.cjsx
Normal file
25
static/package-template/spec/my-composer-button-spec.cjsx
Normal file
|
@ -0,0 +1,25 @@
|
|||
{React} = require 'nylas-exports'
|
||||
ReactTestUtils = React.addons.TestUtils
|
||||
|
||||
MyComposerButton = require '../lib/my-composer-button'
|
||||
|
||||
dialogStub =
|
||||
showMessageBox: jasmine.createSpy('showMessageBox')
|
||||
|
||||
describe "MyComposerButton", ->
|
||||
beforeEach ->
|
||||
@component = ReactTestUtils.renderIntoDocument(
|
||||
<MyComposerButton draftLocalId="test" />
|
||||
)
|
||||
|
||||
it "should render into the page", ->
|
||||
expect(@component).toBeDefined()
|
||||
|
||||
it "should have a displayName", ->
|
||||
expect(MyComposerButton.displayName).toBe('MyComposerButton')
|
||||
|
||||
it "should show a dialog box when clicked", ->
|
||||
spyOn(@component, '_onClick')
|
||||
buttonNode = React.findDOMNode(@component.refs.button)
|
||||
ReactTestUtils.Simulate.click(buttonNode)
|
||||
expect(@component._onClick).toHaveBeenCalled()
|
Loading…
Add table
Reference in a new issue