mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-10-05 19:06:47 +08:00
fix(template): Rewrite in ES6, add missing windowTypes
This commit is contained in:
parent
fce1673aac
commit
9e3dbd3873
11 changed files with 213 additions and 184 deletions
|
@ -232,7 +232,10 @@ PackagesStore = Reflux.createStore
|
|||
type: 'git'
|
||||
url: ''
|
||||
engines:
|
||||
nylas: ">=#{NylasEnv.getVersion()}"
|
||||
nylas: ">=#{NylasEnv.getVersion().split('-')[0]}"
|
||||
windowTypes:
|
||||
default: true
|
||||
composer: true
|
||||
description: "Enter a description of your package!"
|
||||
dependencies: {}
|
||||
license: "MIT"
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
{ComponentRegistry} = require 'nylas-exports'
|
||||
|
||||
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 MyComposerButton,
|
||||
role: 'Composer:ActionButton'
|
||||
|
||||
ComponentRegistry.register MyMessageSidebar,
|
||||
role: 'MessageListSidebar:ContactCard'
|
||||
|
||||
# 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.
|
||||
#
|
||||
serialize: ->
|
||||
|
||||
# This **optional** method is called when the window is shutting down,
|
||||
# or when your package is being updated or disabled. If your package is
|
||||
# watching any files, holding external resources, providing commands or
|
||||
# subscribing to events, release them here.
|
||||
#
|
||||
deactivate: ->
|
||||
ComponentRegistry.unregister(MyComposerButton)
|
||||
ComponentRegistry.unregister(MyMessageSidebar)
|
33
static/package-template/lib/main.es6
Normal file
33
static/package-template/lib/main.es6
Normal file
|
@ -0,0 +1,33 @@
|
|||
import {ComponentRegistry} from 'nylas-exports';
|
||||
|
||||
import MyComposerButton from './my-composer-button';
|
||||
import MyMessageSidebar from './my-message-sidebar';
|
||||
|
||||
// Activate is called when the package is loaded. If your package previously
|
||||
// saved state using `serialize` it is provided.
|
||||
//
|
||||
export function activate() {
|
||||
ComponentRegistry.register(MyComposerButton, {
|
||||
role: 'Composer:ActionButton',
|
||||
});
|
||||
ComponentRegistry.register(MyMessageSidebar, {
|
||||
role: 'MessageListSidebar:ContactCard',
|
||||
});
|
||||
}
|
||||
|
||||
// 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.
|
||||
//
|
||||
export function serialize() {
|
||||
}
|
||||
|
||||
// This **optional** method is called when the window is shutting down,
|
||||
// or when your package is being updated or disabled. If your package is
|
||||
// watching any files, holding external resources, providing commands or
|
||||
// subscribing to events, release them here.
|
||||
//
|
||||
export function deactivate() {
|
||||
ComponentRegistry.unregister(MyComposerButton);
|
||||
ComponentRegistry.unregister(MyMessageSidebar);
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
{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:
|
||||
draftClientId: 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.sessionForClientId(@props.draftClientId).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
|
48
static/package-template/lib/my-composer-button.jsx
Normal file
48
static/package-template/lib/my-composer-button.jsx
Normal file
|
@ -0,0 +1,48 @@
|
|||
import {DraftStore, React} from 'nylas-exports';
|
||||
|
||||
export default class MyComposerButton extends React.Component {
|
||||
|
||||
// Note: You should assign a new displayName to avoid naming
|
||||
// conflicts when injecting your item
|
||||
static 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.
|
||||
static propTypes = {
|
||||
draftClientId: React.PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
_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.sessionForClientId(this.props.draftClientId).then((session) => {
|
||||
const newSubject = `${session.draft().subject} - It Worked!`;
|
||||
|
||||
const dialog = this._getDialog();
|
||||
dialog.showMessageBox({
|
||||
title: 'Here we go...',
|
||||
detail: "Adjusting the subject line To `#{newSubject}`",
|
||||
buttons: ['OK'],
|
||||
type: 'info',
|
||||
});
|
||||
|
||||
session.changes.add({subject: newSubject});
|
||||
});
|
||||
}
|
||||
|
||||
_getDialog() {
|
||||
return require('remote').require('dialog');
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="my-package">
|
||||
<button className="btn btn-toolbar" onClick={() => this._onClick()} ref="button">
|
||||
Hello World
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
{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
|
||||
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>{@state.contact.displayName()} is the focused contact.</h1>
|
||||
</div>
|
||||
|
||||
_renderPlaceholder: =>
|
||||
<div> No Data Available </div>
|
||||
|
||||
_onChange: =>
|
||||
@setState(@_getStateFromStores())
|
||||
|
||||
_getStateFromStores: =>
|
||||
contact: FocusedContactsStore.focusedContact()
|
||||
|
||||
|
||||
module.exports = MyMessageSidebar
|
78
static/package-template/lib/my-message-sidebar.jsx
Normal file
78
static/package-template/lib/my-message-sidebar.jsx
Normal file
|
@ -0,0 +1,78 @@
|
|||
import {
|
||||
React,
|
||||
FocusedContactsStore,
|
||||
} from 'nylas-exports';
|
||||
|
||||
export default class MyMessageSidebar extends React.Component {
|
||||
static displayName = 'MyMessageSidebar';
|
||||
|
||||
// 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) {
|
||||
super(props);
|
||||
this.state = this._getStateFromStores();
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.unsubscribe = FocusedContactsStore.listen(this._onChange);
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.unsubscribe();
|
||||
}
|
||||
|
||||
_onChange = () => {
|
||||
this.setState(this._getStateFromStores());
|
||||
}
|
||||
|
||||
_getStateFromStores = () => {
|
||||
return {
|
||||
contact: FocusedContactsStore.focusedContact(),
|
||||
};
|
||||
}
|
||||
|
||||
_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_templatethis.2x.png"
|
||||
// mode={RetinaImg.Mode.ContentIsMask}/>
|
||||
//
|
||||
return (
|
||||
<div className="header">
|
||||
<h1>{this.state.contact.displayName()} is the focused contact.</h1>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
_renderPlaceholder() {
|
||||
return (
|
||||
<div> No Data Available </div>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
const content = (this.state.contact) ? this._renderContent() : this._renderPlaceholder();
|
||||
return (
|
||||
<div className="my-message-sidebar">
|
||||
{content}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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.
|
||||
MyMessageSidebar.containerStyles = {
|
||||
order: 1,
|
||||
flexShrink: 0,
|
||||
};
|
|
@ -1,19 +0,0 @@
|
|||
{ComponentRegistry} = require 'nylas-exports'
|
||||
{activate, deactivate} = require '../lib/main'
|
||||
|
||||
MyMessageSidebar = require '../lib/my-message-sidebar'
|
||||
MyComposerButton = require '../lib/my-composer-button'
|
||||
|
||||
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: 'MessageListSidebar:ContactCard'})
|
||||
|
||||
describe "deactivate", ->
|
||||
it "should unregister the composer button and sidebar", ->
|
||||
spyOn(ComponentRegistry, 'unregister')
|
||||
deactivate()
|
||||
expect(ComponentRegistry.unregister).toHaveBeenCalledWith(MyComposerButton)
|
||||
expect(ComponentRegistry.unregister).toHaveBeenCalledWith(MyMessageSidebar)
|
23
static/package-template/spec/main-spec.es6
Normal file
23
static/package-template/spec/main-spec.es6
Normal file
|
@ -0,0 +1,23 @@
|
|||
import {ComponentRegistry} from 'nylas-exports';
|
||||
import {activate, deactivate} from '../lib/main';
|
||||
|
||||
import MyMessageSidebar from '../lib/my-message-sidebar';
|
||||
import MyComposerButton from '../lib/my-composer-button';
|
||||
|
||||
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: 'MessageListSidebar:ContactCard'});
|
||||
});
|
||||
});
|
||||
|
||||
describe("deactivate", () => {
|
||||
it("should unregister the composer button and sidebar", () => {
|
||||
spyOn(ComponentRegistry, 'unregister');
|
||||
deactivate();
|
||||
expect(ComponentRegistry.unregister).toHaveBeenCalledWith(MyComposerButton);
|
||||
expect(ComponentRegistry.unregister).toHaveBeenCalledWith(MyMessageSidebar);
|
||||
});
|
||||
});
|
|
@ -1,25 +0,0 @@
|
|||
{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 draftClientId="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()
|
27
static/package-template/spec/my-composer-button-spec.jsx
Normal file
27
static/package-template/spec/my-composer-button-spec.jsx
Normal file
|
@ -0,0 +1,27 @@
|
|||
import {React} from 'nylas-exports';
|
||||
const ReactTestUtils = React.addons.TestUtils
|
||||
|
||||
import MyComposerButton from '../lib/my-composer-button';
|
||||
|
||||
describe("MyComposerButton", () => {
|
||||
beforeEach(() => {
|
||||
this.component = ReactTestUtils.renderIntoDocument(
|
||||
<MyComposerButton draftClientId="test" />
|
||||
);
|
||||
});
|
||||
|
||||
it("should render into the page", () => {
|
||||
expect(this.component).toBeDefined();
|
||||
});
|
||||
|
||||
it("should have a displayName", () => {
|
||||
expect(MyComposerButton.displayName).toBe('MyComposerButton');
|
||||
});
|
||||
|
||||
it("should show a dialog box when clicked", () => {
|
||||
spyOn(this.component, '_onClick');
|
||||
const buttonNode = React.findDOMNode(this.component.refs.button);
|
||||
ReactTestUtils.Simulate.click(buttonNode);
|
||||
expect(this.component._onClick).toHaveBeenCalled();
|
||||
});
|
||||
});
|
Loading…
Add table
Reference in a new issue