mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-09-22 08:16:09 +08:00
Merge branch 'master' of github.com:nylas/N1
This commit is contained in:
commit
66c3b0c4e6
|
@ -5,17 +5,15 @@ Section: Guides
|
||||||
Order: 7
|
Order: 7
|
||||||
---
|
---
|
||||||
|
|
||||||
# Writing specs
|
|
||||||
|
|
||||||
Nylas uses [Jasmine](http://jasmine.github.io/1.3/introduction.html) as its spec framework. As a package developer, you can write specs using Jasmine 1.3 and get some quick wins. Jasmine specs can be run in N1 directly from the Developer menu, and the test environment provides you with helpful stubs. You can also require your own test framework, or use Jasmine for integration tests and your own framework for your existing business logic.
|
Nylas uses [Jasmine](http://jasmine.github.io/1.3/introduction.html) as its spec framework. As a package developer, you can write specs using Jasmine 1.3 and get some quick wins. Jasmine specs can be run in N1 directly from the Developer menu, and the test environment provides you with helpful stubs. You can also require your own test framework, or use Jasmine for integration tests and your own framework for your existing business logic.
|
||||||
|
|
||||||
This documentation describes using [Jasmine 1.3](http://jasmine.github.io/1.3/introduction.html) to write specs for a Nylas package.
|
This documentation describes using [Jasmine 1.3](http://jasmine.github.io/1.3/introduction.html) to write specs for a Nylas package.
|
||||||
|
|
||||||
#### Running Specs
|
### Running Specs
|
||||||
|
|
||||||
You can run your package specs from `Developer > Run Package Specs...`. Once you've opened the spec window, you can see output and re-run your specs by clicking `Reload Specs`.
|
You can run your package specs from `Developer > Run Package Specs...`. Once you've opened the spec window, you can see output and re-run your specs by clicking `Reload Specs`.
|
||||||
|
|
||||||
#### Writing Specs
|
### Writing Specs
|
||||||
|
|
||||||
To create specs, place `js`, `coffee`, or `cjsx` files in the `spec` directory of your package. Spec files must end with the `-spec` suffix.
|
To create specs, place `js`, `coffee`, or `cjsx` files in the `spec` directory of your package. Spec files must end with the `-spec` suffix.
|
||||||
|
|
||||||
|
|
|
@ -322,7 +322,8 @@ class CategoryPicker extends React.Component
|
||||||
|
|
||||||
_isUserFacing: (allInInbox, category) =>
|
_isUserFacing: (allInInbox, category) =>
|
||||||
hiddenCategories = []
|
hiddenCategories = []
|
||||||
currentCategoryId = FocusedMailViewStore.mailView().categoryId()
|
currentCategoryId = FocusedMailViewStore.mailView()?.categoryId()
|
||||||
|
|
||||||
if @_account?.usesLabels()
|
if @_account?.usesLabels()
|
||||||
hiddenCategories = ["all", "spam", "trash", "drafts", "sent"]
|
hiddenCategories = ["all", "spam", "trash", "drafts", "sent"]
|
||||||
if allInInbox
|
if allInInbox
|
||||||
|
|
|
@ -90,7 +90,7 @@ class ActivitySidebar extends React.Component
|
||||||
<RetinaImg name="sending-spinner.gif" width={18} mode={RetinaImg.Mode.ContentPreserve} />
|
<RetinaImg name="sending-spinner.gif" width={18} mode={RetinaImg.Mode.ContentPreserve} />
|
||||||
</div>
|
</div>
|
||||||
<div className="inner">
|
<div className="inner">
|
||||||
Syncing mail data…
|
Syncing your mailbox…
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,7 @@ class InitialSyncActivity extends React.Component
|
||||||
else
|
else
|
||||||
<div className={classSet} key="initial-sync" onClick={=> @setState expandedSync: !@state.expandedSync}>
|
<div className={classSet} key="initial-sync" onClick={=> @setState expandedSync: !@state.expandedSync}>
|
||||||
{@_renderProgressBar(totalProgress)}
|
{@_renderProgressBar(totalProgress)}
|
||||||
<div className="inner">Syncing mail data…</div>
|
<div className="inner">Syncing your mailbox…</div>
|
||||||
{@_expandedSyncState()}
|
{@_expandedSyncState()}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
BIN
internal_packages/onboarding/assets/nylas-pictographB@2x.png
Normal file
BIN
internal_packages/onboarding/assets/nylas-pictographB@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 16 KiB |
|
@ -30,7 +30,7 @@ class AccountChoosePage extends React.Component
|
||||||
<RetinaImg name="onboarding-close.png" mode={RetinaImg.Mode.ContentPreserve}/>
|
<RetinaImg name="onboarding-close.png" mode={RetinaImg.Mode.ContentPreserve}/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<RetinaImg url="nylas://onboarding/assets/nylas-pictograph@2x.png" mode={RetinaImg.Mode.ContentIsMask} style={zoom: 0.29} className="logo"/>
|
<RetinaImg url="nylas://onboarding/assets/nylas-pictographB@2x.png" mode={RetinaImg.Mode.ContentPreserve} style={zoom: 0.29, opacity: 0.55} className="logo"/>
|
||||||
|
|
||||||
<div className="caption" style={marginTop: 15, marginBottom:20}>Select your email provider</div>
|
<div className="caption" style={marginTop: 15, marginBottom:20}>Select your email provider</div>
|
||||||
|
|
||||||
|
|
|
@ -79,11 +79,16 @@ class AccountSettingsPage extends React.Component
|
||||||
|
|
||||||
_onSettingsChanged: (event) =>
|
_onSettingsChanged: (event) =>
|
||||||
field = event.target.dataset.field
|
field = event.target.dataset.field
|
||||||
|
format = event.target.dataset.format
|
||||||
|
int_formatter = (a) ->
|
||||||
|
i = parseInt(a)
|
||||||
|
if isNaN(i) then "" else i
|
||||||
|
formatter = if format is 'integer' then int_formatter else (a) -> a
|
||||||
settings = @state.settings
|
settings = @state.settings
|
||||||
if event.target.type is 'checkbox'
|
if event.target.type is 'checkbox'
|
||||||
settings[field] = event.target.checked
|
settings[field] = event.target.checked
|
||||||
else
|
else
|
||||||
settings[field] = event.target.value
|
settings[field] = formatter(event.target.value)
|
||||||
@setState({settings})
|
@setState({settings})
|
||||||
|
|
||||||
_onValueChanged: (event) =>
|
_onValueChanged: (event) =>
|
||||||
|
@ -94,7 +99,11 @@ class AccountSettingsPage extends React.Component
|
||||||
|
|
||||||
_onFieldKeyPress: (event) =>
|
_onFieldKeyPress: (event) =>
|
||||||
if event.key in ['Enter', 'Return']
|
if event.key in ['Enter', 'Return']
|
||||||
@_onSubmit()
|
pages = @state.provider.pages || []
|
||||||
|
if pages.length > @state.pageNumber+1
|
||||||
|
@_onNextButton()
|
||||||
|
else
|
||||||
|
@_onSubmit()
|
||||||
|
|
||||||
_renderTitle: =>
|
_renderTitle: =>
|
||||||
if @state.provider.name is 'gmail'
|
if @state.provider.name is 'gmail'
|
||||||
|
@ -129,6 +138,7 @@ class AccountSettingsPage extends React.Component
|
||||||
onChange={@_onValueChanged}
|
onChange={@_onValueChanged}
|
||||||
onKeyPress={@_onFieldKeyPress}
|
onKeyPress={@_onFieldKeyPress}
|
||||||
data-field={field.name}
|
data-field={field.name}
|
||||||
|
data-format={field.format} ? ""
|
||||||
className={errclass}
|
className={errclass}
|
||||||
placeholder={field.placeholder} />
|
placeholder={field.placeholder} />
|
||||||
</label>
|
</label>
|
||||||
|
@ -144,6 +154,7 @@ class AccountSettingsPage extends React.Component
|
||||||
onChange={@_onSettingsChanged}
|
onChange={@_onSettingsChanged}
|
||||||
onKeyPress={@_onFieldKeyPress}
|
onKeyPress={@_onFieldKeyPress}
|
||||||
data-field={field.name}
|
data-field={field.name}
|
||||||
|
data-format={field.format} ? ""
|
||||||
className={field.className ? ""} />
|
className={field.className ? ""} />
|
||||||
{field.label}
|
{field.label}
|
||||||
</label>
|
</label>
|
||||||
|
@ -159,6 +170,7 @@ class AccountSettingsPage extends React.Component
|
||||||
onChange={@_onSettingsChanged}
|
onChange={@_onSettingsChanged}
|
||||||
onKeyPress={@_onFieldKeyPress}
|
onKeyPress={@_onFieldKeyPress}
|
||||||
data-field={field.name}
|
data-field={field.name}
|
||||||
|
data-format={field.format} ? ""
|
||||||
className={errclass+(field.className ? "")}
|
className={errclass+(field.className ? "")}
|
||||||
placeholder={field.placeholder} />
|
placeholder={field.placeholder} />
|
||||||
</label>
|
</label>
|
||||||
|
|
|
@ -125,6 +125,7 @@ Providers = [
|
||||||
label: 'Port (optional)'
|
label: 'Port (optional)'
|
||||||
className: 'half'
|
className: 'half'
|
||||||
default: 993
|
default: 993
|
||||||
|
format: 'integer'
|
||||||
page: 1
|
page: 1
|
||||||
}, {
|
}, {
|
||||||
name: 'imap_ssl_enabled'
|
name: 'imap_ssl_enabled'
|
||||||
|
@ -157,6 +158,7 @@ Providers = [
|
||||||
placeholder: '587'
|
placeholder: '587'
|
||||||
label: 'Port (optional)'
|
label: 'Port (optional)'
|
||||||
className: 'half'
|
className: 'half'
|
||||||
|
format: 'integer'
|
||||||
default: 587
|
default: 587
|
||||||
page: 2
|
page: 2
|
||||||
}, {
|
}, {
|
||||||
|
|
|
@ -4,11 +4,10 @@ NylasStore = require 'nylas-store'
|
||||||
class NylasApiEnvironmentStore extends NylasStore
|
class NylasApiEnvironmentStore extends NylasStore
|
||||||
constructor: ->
|
constructor: ->
|
||||||
@listenTo Actions.changeAPIEnvironment, @_setEnvironment
|
@listenTo Actions.changeAPIEnvironment, @_setEnvironment
|
||||||
|
@_setEnvironment('production') unless atom.config.get('env')
|
||||||
|
|
||||||
defaultEnv = if atom.inDevMode() then 'staging' else 'staging'
|
getEnvironment: ->
|
||||||
@_setEnvironment(defaultEnv) unless atom.config.get('env')
|
atom.config.get('env')
|
||||||
|
|
||||||
getEnvironment: -> atom.config.get('env')
|
|
||||||
|
|
||||||
_setEnvironment: (env) ->
|
_setEnvironment: (env) ->
|
||||||
throw new Error("Environment #{env} is not allowed") unless env in ['development', 'experimental', 'staging', 'production']
|
throw new Error("Environment #{env} is not allowed") unless env in ['development', 'experimental', 'staging', 'production']
|
||||||
|
|
|
@ -45,7 +45,7 @@ class WelcomePage extends React.Component
|
||||||
|
|
||||||
_renderStep0: ->
|
_renderStep0: ->
|
||||||
<div className={@_stepClass(0)} key="step-0">
|
<div className={@_stepClass(0)} key="step-0">
|
||||||
<RetinaImg className="logo" style={zoom: 0.20, marginTop: 60} url="nylas://onboarding/assets/nylas-pictograph@2x.png" mode={RetinaImg.Mode.ContentIsMask} />
|
<RetinaImg className="logo" style={zoom: 0.20, marginTop: 60, opacity: 0.7} url="nylas://onboarding/assets/nylas-pictographB@2x.png" mode={RetinaImg.Mode.ContentPreserve}/>
|
||||||
<p className="hero-text" style={marginTop: 30, fontSize: 44}>Say hello to N1.</p>
|
<p className="hero-text" style={marginTop: 30, fontSize: 44}>Say hello to N1.</p>
|
||||||
<p className="sub-text" style={marginTop: 0, fontSize: 24}>The next-generation email platform.</p>
|
<p className="sub-text" style={marginTop: 0, fontSize: 24}>The next-generation email platform.</p>
|
||||||
<div style={fontSize:17, marginTop: 45}>Built with ❤︎ by Nylas</div>
|
<div style={fontSize:17, marginTop: 45}>Built with ❤︎ by Nylas</div>
|
||||||
|
@ -65,7 +65,7 @@ class WelcomePage extends React.Component
|
||||||
<RetinaImg className="wrench" mode={RetinaImg.Mode.ContentPreserve}
|
<RetinaImg className="wrench" mode={RetinaImg.Mode.ContentPreserve}
|
||||||
url="nylas://onboarding/assets/wrench@2x.png" />
|
url="nylas://onboarding/assets/wrench@2x.png" />
|
||||||
|
|
||||||
<p className="sub-text">N1 is built with modern web technologies and easy to extend with JavaScript.</p>
|
<p className="sub-text">N1 is built with modern web technologies and is easy to extend with JavaScript.</p>
|
||||||
{@_renderNavBubble(1)}
|
{@_renderNavBubble(1)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -15,18 +15,18 @@ describe "NylasApiEnvironmentStore", ->
|
||||||
spyOn(atom, "inDevMode").andReturn true
|
spyOn(atom, "inDevMode").andReturn true
|
||||||
spyOn(atom.config, "get").andReturn undefined
|
spyOn(atom.config, "get").andReturn undefined
|
||||||
store = new storeConstructor()
|
store = new storeConstructor()
|
||||||
expect(atom.config.set).toHaveBeenCalledWith("env", "staging")
|
expect(atom.config.set).toHaveBeenCalledWith("env", "production")
|
||||||
|
|
||||||
it "initializes with the correct default in production", ->
|
it "initializes with the correct default in production", ->
|
||||||
spyOn(atom, "inDevMode").andReturn false
|
spyOn(atom, "inDevMode").andReturn false
|
||||||
spyOn(atom.config, "get").andReturn undefined
|
spyOn(atom.config, "get").andReturn undefined
|
||||||
store = new storeConstructor()
|
store = new storeConstructor()
|
||||||
expect(atom.config.set).toHaveBeenCalledWith("env", "staging")
|
expect(atom.config.set).toHaveBeenCalledWith("env", "production")
|
||||||
|
|
||||||
describe "when setting the environment", ->
|
describe "when setting the environment", ->
|
||||||
it "sets from the desired action", ->
|
it "sets from the desired action", ->
|
||||||
Actions.changeAPIEnvironment("production")
|
Actions.changeAPIEnvironment("staging")
|
||||||
expect(atom.config.set).toHaveBeenCalledWith("env", "production")
|
expect(atom.config.set).toHaveBeenCalledWith("env", "staging")
|
||||||
|
|
||||||
it "throws if the env is invalid", ->
|
it "throws if the env is invalid", ->
|
||||||
expect( -> Actions.changeAPIEnvironment("bad")).toThrow()
|
expect( -> Actions.changeAPIEnvironment("bad")).toThrow()
|
||||||
|
|
|
@ -312,9 +312,6 @@
|
||||||
.page.account-choose {
|
.page.account-choose {
|
||||||
width: 388px;
|
width: 388px;
|
||||||
height: 615px;
|
height: 615px;
|
||||||
img.logo.content-mask {
|
|
||||||
background-color: rgba(255,255,255,0.4);
|
|
||||||
}
|
|
||||||
|
|
||||||
.caption {
|
.caption {
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
|
@ -539,9 +536,6 @@
|
||||||
line-height: 41px;
|
line-height: 41px;
|
||||||
}
|
}
|
||||||
|
|
||||||
img.logo.content-mask {
|
|
||||||
background-color: rgba(255,255,255,0.4);
|
|
||||||
}
|
|
||||||
img.icons.content-mask {
|
img.icons.content-mask {
|
||||||
background-color: rgba(255,255,255,0.7);
|
background-color: rgba(255,255,255,0.7);
|
||||||
}
|
}
|
||||||
|
@ -647,7 +641,7 @@
|
||||||
|
|
||||||
p {
|
p {
|
||||||
margin-top: 1em;
|
margin-top: 1em;
|
||||||
color: rgba(255,255,255,0.7);
|
color: rgba(255,255,255,0.9);
|
||||||
font-size: 17px;
|
font-size: 17px;
|
||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,6 @@ class EdgehillAPI
|
||||||
_onConfigChanged: =>
|
_onConfigChanged: =>
|
||||||
env = atom.config.get('env')
|
env = atom.config.get('env')
|
||||||
if env is 'development'
|
if env is 'development'
|
||||||
# @APIRoot = "http://localhost:5009"
|
|
||||||
@APIRoot = "https://edgehill-dev.nylas.com"
|
@APIRoot = "https://edgehill-dev.nylas.com"
|
||||||
else if env is 'experimental'
|
else if env is 'experimental'
|
||||||
@APIRoot = "https://edgehill-experimental.nylas.com"
|
@APIRoot = "https://edgehill-experimental.nylas.com"
|
||||||
|
|
Loading…
Reference in a new issue