fix(examples): examples => packages, move away from installing them
|
@ -169,7 +169,6 @@ module.exports = (grunt) ->
|
|||
cp directory, path.join(appDir, directory), filter: filterPackage
|
||||
|
||||
cp 'spec', path.join(appDir, 'spec')
|
||||
cp 'examples', path.join(appDir, 'examples')
|
||||
cp 'src', path.join(appDir, 'src'), filter: /.+\.(cson|coffee|cjsx|jsx)$/
|
||||
cp 'static', path.join(appDir, 'static')
|
||||
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
|
||||
## Translate
|
||||
|
||||
A package for N1 that translates draft text into other languages using the Yandex Translation API.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/nylas/N1/master/examples/N1-Composer-Translate/examples-screencap-translate.png"/>
|
||||
|
||||
#### Install this plugin
|
||||
|
||||
1. Download and run N1
|
||||
|
||||
2. From the menu, select `Developer > Install a Plugin Manually...`
|
||||
The dialog will default to this examples directory. Just choose the
|
||||
`N1-Composer-Translate` folder to install it!
|
||||
|
||||
> When you install packages, they're moved to `~/.nylas/packages`,
|
||||
> and N1 runs `apm install` on the command line to fetch dependencies
|
||||
> listed in the package's `package.json`
|
||||
|
||||
#### Build documentation
|
||||
|
||||
```
|
||||
cjsx-transform lib/main.cjsx > docs/main.coffee
|
||||
docco docs/main.coffee
|
||||
rm docs/main.coffee
|
||||
```
|
Before Width: | Height: | Size: 3.7 KiB |
|
@ -1,21 +0,0 @@
|
|||
# Personal Level Icon
|
||||
|
||||
An icon to indicate whether an email was sent to either just you, or you and other recipients, or a mailing list that you were on.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/nylas/N1/master/examples/N1-Personal-Level-Indicators/examples-screencap-personal-level-icon.png"/>
|
||||
|
||||
#### Install this plugin
|
||||
|
||||
1. Download and run N1
|
||||
|
||||
2. From the menu, select `Developer > Install a Plugin Manually...`
|
||||
The dialog will default to this examples directory. Just choose the
|
||||
`N1-Personal-Level-Indicators` folder to install it!
|
||||
|
||||
> When you install packages, they're moved to `~/.nylas/packages`,
|
||||
> and N1 runs `apm install` on the command line to fetch dependencies
|
||||
> listed in the package's `package.json`
|
||||
|
||||
#### Who?
|
||||
|
||||
This package is annotated for developers who have no experience with React, Flux, Electron, or N1.
|
1
examples/composer-templates
Symbolic link
|
@ -0,0 +1 @@
|
|||
../internal_packages/composer-templates
|
1
examples/composer-translate
Symbolic link
|
@ -0,0 +1 @@
|
|||
../internal_packages/composer-translate
|
1
examples/github-contact-card
Symbolic link
|
@ -0,0 +1 @@
|
|||
../internal_packages/github-contact-card
|
1
examples/message-view-on-github
Symbolic link
|
@ -0,0 +1 @@
|
|||
../internal_packages/message-view-on-github
|
1
examples/personal-level-indicators
Symbolic link
|
@ -0,0 +1 @@
|
|||
../internal_packages/personal-level-indicators
|
|
@ -1,7 +1,10 @@
|
|||
{
|
||||
"name": "PersonalLevelIndicators",
|
||||
"name": "personal-level-indicators",
|
||||
"main": "./lib/main",
|
||||
"version": "0.1.0",
|
||||
"isOptional": true,
|
||||
"title": "Personal Level Indicators",
|
||||
"description": "Display chevrons beside threads that indicate whether you're a direct recipient or the only recipient on a thread.",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": ""
|
1
examples/phishing-detection
Symbolic link
|
@ -0,0 +1 @@
|
|||
../internal_packages/phishing-detection
|
1
examples/quick-schedule
Symbolic link
|
@ -0,0 +1 @@
|
|||
../internal_packages/quick-schedule
|
|
@ -14,7 +14,7 @@ tags are always stripped so the recipient never sees any highlighting.
|
|||
This example is a good starting point for plugins that want to extend the composer
|
||||
experience.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/nylas/N1/master/examples/N1-Composer-Templates/screenshot.png">
|
||||
<img src="https://raw.githubusercontent.com/nylas/N1/master/internal_packages/composer-templates/screenshot.png">
|
||||
|
||||
#### Install this plugin
|
||||
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
@ -58,10 +58,11 @@ class TemplatesComposerExtension extends ComposerExtension {
|
|||
const treeWalker = document.createTreeWalker(editableNode, NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT);
|
||||
let curIndex = 0;
|
||||
let nextIndex = null;
|
||||
let node;
|
||||
while (node = treeWalker.nextNode()) {
|
||||
let node = treeWalker.nextNode();
|
||||
while (node) {
|
||||
if (sel.anchorNode === node || sel.focusNode === node) break;
|
||||
if (node.nodeName === 'CODE' && node.classList.contains('var')) curIndex++;
|
||||
node = treeWalker.nextNode();
|
||||
}
|
||||
nextIndex = event.shiftKey ? curIndex - 1 : curIndex;
|
||||
nextIndex = (nextIndex + nodes.length) % nodes.length; // allow wraparound in both directions
|
|
@ -67,7 +67,7 @@ class TemplatePicker extends React.Component {
|
|||
render() {
|
||||
const button = (
|
||||
<button className="btn btn-toolbar narrow">
|
||||
<RetinaImg url="nylas://N1-Composer-Templates/assets/icon-composer-templates@2x.png" mode={RetinaImg.Mode.ContentIsMask}/>
|
||||
<RetinaImg url="nylas://composer-templates/assets/icon-composer-templates@2x.png" mode={RetinaImg.Mode.ContentIsMask}/>
|
||||
|
||||
<RetinaImg name="icon-composer-dropdown.png" mode={RetinaImg.Mode.ContentIsMask}/>
|
||||
</button>
|
|
@ -1,6 +1,5 @@
|
|||
import {DraftStore, Actions, QuotedHTMLTransformer} from 'nylas-exports';
|
||||
import NylasStore from 'nylas-store';
|
||||
import shell from 'shell';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
|
||||
|
@ -42,12 +41,12 @@ class TemplateStore extends NylasStore {
|
|||
fs.exists(this._templatesDir, (exists) => {
|
||||
if (exists) {
|
||||
this._populate();
|
||||
this.watch()
|
||||
this.watch();
|
||||
} else {
|
||||
fs.mkdir(this._templatesDir, () => {
|
||||
fs.readFile(this._welcomePath, (err, welcome) => {
|
||||
fs.writeFile(path.join(this._templatesDir, this._welcomeName), welcome, () => {
|
||||
this.watch()
|
||||
this.watch();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -56,8 +55,9 @@ class TemplateStore extends NylasStore {
|
|||
}
|
||||
|
||||
watch() {
|
||||
if(!this._watcher)
|
||||
if (!this._watcher) {
|
||||
this._watcher = fs.watch(this._templatesDir, () => this._populate());
|
||||
}
|
||||
}
|
||||
unwatch() {
|
||||
this._watcher.close();
|
||||
|
@ -103,7 +103,7 @@ class TemplateStore extends NylasStore {
|
|||
if (draftClientId) {
|
||||
DraftStore.sessionForClientId(draftClientId).then((session) => {
|
||||
const draft = session.draft();
|
||||
const draftName = name ? name : draft.subject.replace(TemplateStore.INVALID_TEMPLATE_NAME_REGEX,"");
|
||||
const draftName = name ? name : draft.subject.replace(TemplateStore.INVALID_TEMPLATE_NAME_REGEX, '');
|
||||
const draftContents = contents ? contents : QuotedHTMLTransformer.removeQuotedHTML(draft.body);
|
||||
if (!draftName || draftName.length === 0) {
|
||||
this._displayError('Give your draft a subject to name your template.');
|
||||
|
@ -115,44 +115,44 @@ class TemplateStore extends NylasStore {
|
|||
});
|
||||
return;
|
||||
}
|
||||
if (!name || name.length === 0)
|
||||
if (!name || name.length === 0) {
|
||||
this._displayError('You must provide a name for your template.');
|
||||
|
||||
if (!contents || contents.length === 0)
|
||||
}
|
||||
if (!contents || contents.length === 0) {
|
||||
this._displayError('You must provide contents for your template.');
|
||||
|
||||
}
|
||||
this.saveNewTemplate(name, contents, this._onShowTemplates);
|
||||
}
|
||||
|
||||
_onShowTemplates() {
|
||||
Actions.switchPreferencesTab('Quick Replies');
|
||||
Actions.openPreferences()
|
||||
Actions.openPreferences();
|
||||
}
|
||||
|
||||
_displayError(message) {
|
||||
const dialog = require('remote').require('dialog');
|
||||
dialog.showErrorBox('Template Creation Error', message);
|
||||
}
|
||||
_displayDialog(title,message,buttons) {
|
||||
_displayDialog(title, message, buttons) {
|
||||
const dialog = require('remote').require('dialog');
|
||||
return 0==dialog.showMessageBox({
|
||||
title: title,
|
||||
message: title,
|
||||
detail: message,
|
||||
buttons: buttons,
|
||||
type: 'info'
|
||||
});
|
||||
return (dialog.showMessageBox({
|
||||
title: title,
|
||||
message: title,
|
||||
detail: message,
|
||||
buttons: buttons,
|
||||
type: 'info',
|
||||
}) === 0);
|
||||
}
|
||||
|
||||
saveNewTemplate(name, contents, callback) {
|
||||
if(name.match(TemplateStore.INVALID_TEMPLATE_NAME_REGEX)) {
|
||||
this._displayError("Invalid template name! Names can only contain letters, numbers, spaces, dashes, and underscores.");
|
||||
if (name.match(TemplateStore.INVALID_TEMPLATE_NAME_REGEX)) {
|
||||
this._displayError('Invalid template name! Names can only contain letters, numbers, spaces, dashes, and underscores.');
|
||||
return;
|
||||
}
|
||||
|
||||
var template = this._getTemplate(name);
|
||||
if(template) {
|
||||
this._displayError("A template with that name already exists!");
|
||||
const template = this._getTemplate(name);
|
||||
if (template) {
|
||||
this._displayError('A template with that name already exists!');
|
||||
return;
|
||||
}
|
||||
this.saveTemplate(name, contents, callback);
|
||||
|
@ -160,9 +160,10 @@ class TemplateStore extends NylasStore {
|
|||
}
|
||||
|
||||
_getTemplate(name, id) {
|
||||
for(let template of this._items) {
|
||||
if((template.name === name || name == null) && (template.id === id || id == null))
|
||||
for (const template of this._items) {
|
||||
if ((template.name === name || name === null) && (template.id === id || id === null)) {
|
||||
return template;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
@ -171,7 +172,7 @@ class TemplateStore extends NylasStore {
|
|||
const filename = `${name}.html`;
|
||||
const templatePath = path.join(this._templatesDir, filename);
|
||||
|
||||
var template = this._getTemplate(name);
|
||||
let template = this._getTemplate(name);
|
||||
this.unwatch();
|
||||
fs.writeFile(templatePath, contents, (err) => {
|
||||
this.watch();
|
||||
|
@ -180,38 +181,42 @@ class TemplateStore extends NylasStore {
|
|||
template = {
|
||||
id: filename,
|
||||
name: name,
|
||||
path: templatePath
|
||||
path: templatePath,
|
||||
};
|
||||
this._items.push(template);
|
||||
}
|
||||
if(callback)
|
||||
if (callback) {
|
||||
callback(template);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
deleteTemplate(name, callback) {
|
||||
var template = this._getTemplate(name);
|
||||
if (!template) { return undefined }
|
||||
const template = this._getTemplate(name);
|
||||
if (!template) { return undefined; }
|
||||
|
||||
if(this._displayDialog(
|
||||
if (this._displayDialog(
|
||||
'Delete this template?',
|
||||
'The template and its file will be permanently deleted.',
|
||||
['Delete','Cancel']
|
||||
))
|
||||
['Delete', 'Cancel']
|
||||
)) {
|
||||
fs.unlink(template.path, () => {
|
||||
this._populate();
|
||||
if(callback)
|
||||
callback()
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
renameTemplate(oldName, newName, callback) {
|
||||
if(newName.match(TemplateStore.INVALID_TEMPLATE_NAME_REGEX)) {
|
||||
this._displayError("Invalid template name! Names can only contain letters, numbers, spaces, dashes, and underscores.");
|
||||
const template = this._getTemplate(oldName);
|
||||
if (!template) { return; }
|
||||
|
||||
if (newName.match(TemplateStore.INVALID_TEMPLATE_NAME_REGEX)) {
|
||||
this._displayError('Invalid template name! Names can only contain letters, numbers, spaces, dashes, and underscores.');
|
||||
return;
|
||||
}
|
||||
var template = this._getTemplate(oldName);
|
||||
if (!template) { return undefined }
|
||||
|
||||
const newFilename = `${newName}.html`;
|
||||
const oldPath = path.join(this._templatesDir, `${oldName}.html`);
|
||||
|
@ -221,25 +226,25 @@ class TemplateStore extends NylasStore {
|
|||
template.id = newFilename;
|
||||
template.path = newPath;
|
||||
this.trigger(this);
|
||||
callback(template)
|
||||
callback(template);
|
||||
});
|
||||
}
|
||||
|
||||
_onInsertTemplateId({templateId, draftClientId} = {}) {
|
||||
this.getTemplateContents(templateId, (body) => {
|
||||
DraftStore.sessionForClientId(draftClientId).then((session)=> {
|
||||
var proceed = true;
|
||||
let proceed = true;
|
||||
if (!session.draft().pristine) {
|
||||
proceed = this._displayDialog(
|
||||
'Replace draft contents?',
|
||||
'It looks like your draft already has some content. Loading this template will ' +
|
||||
'overwrite all draft contents.',
|
||||
['Replace contents','Cancel']
|
||||
)
|
||||
['Replace contents', 'Cancel']
|
||||
);
|
||||
}
|
||||
|
||||
if(proceed) {
|
||||
draftHtml = QuotedHTMLTransformer.appendQuotedHTML(body, session.draft().body);
|
||||
if (proceed) {
|
||||
const draftHtml = QuotedHTMLTransformer.appendQuotedHTML(body, session.draft().body);
|
||||
session.changes.add({body: draftHtml});
|
||||
}
|
||||
});
|
||||
|
@ -247,8 +252,8 @@ class TemplateStore extends NylasStore {
|
|||
}
|
||||
|
||||
getTemplateContents(templateId, callback) {
|
||||
var template = this._getTemplate(null,templateId);
|
||||
if (!template) { return undefined }
|
||||
const template = this._getTemplate(null, templateId);
|
||||
if (!template) { return; }
|
||||
|
||||
fs.readFile(template.path, (err, data)=> {
|
||||
const body = data.toString();
|
|
@ -1,9 +1,11 @@
|
|||
{
|
||||
"name": "N1-Composer-Templates",
|
||||
"name": "composer-templates",
|
||||
"version": "0.1.0",
|
||||
"main": "./lib/main",
|
||||
|
||||
"isOptional": true,
|
||||
"isStarterPackage": true,
|
||||
|
||||
"title": "Templates",
|
||||
"description": "Create templates you can use to pre-fill the composer - never type the same email again!",
|
||||
"icon": "./icon.png",
|
Before Width: | Height: | Size: 234 KiB After Width: | Height: | Size: 234 KiB |
20
internal_packages/composer-translate/README.md
Normal file
|
@ -0,0 +1,20 @@
|
|||
|
||||
## Translate
|
||||
|
||||
A package for N1 that translates draft text into other languages using the Yandex Translation API.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/nylas/N1/master/internal_packages/composer-translate/examples-screencap-translate.png"/>
|
||||
|
||||
#### Enable this plugin
|
||||
|
||||
1. Download and run N1
|
||||
|
||||
2. Navigate to Preferences > Plugins and click "Enable" beside the plugin.
|
||||
|
||||
#### Build documentation
|
||||
|
||||
```
|
||||
cjsx-transform lib/main.cjsx > docs/main.coffee
|
||||
docco docs/main.coffee
|
||||
rm docs/main.coffee
|
||||
```
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 50 KiB |
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
@ -71,7 +71,7 @@ class TranslateButton extends React.Component
|
|||
#
|
||||
_renderButton: =>
|
||||
<button className="btn btn-toolbar" title="Translate">
|
||||
<RetinaImg mode={RetinaImg.Mode.ContentIsMask} url="nylas://N1-Composer-Translate/assets/translate-icon@2x.png" />
|
||||
<RetinaImg mode={RetinaImg.Mode.ContentIsMask} url="nylas://composer-translate/assets/translate-icon@2x.png" />
|
||||
<span style={fontSize: "9px", verticalAlign: "top"}>▼</span>
|
||||
</button>
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
{
|
||||
"name": "N1-Composer-Translate",
|
||||
"name": "composer-translate",
|
||||
"version": "0.2.0",
|
||||
"main": "./lib/main",
|
||||
|
||||
"isOptional": true,
|
||||
"isStarterPackage": true,
|
||||
|
||||
"title": "Translation",
|
||||
"description": "Translate your drafts in the composer into other languages using the Yandex Translation API.",
|
||||
"icon": "./icon.png",
|
|
@ -7,7 +7,7 @@ and then displays public repos and their stars.
|
|||
This example is a good starting point for plugins that want to display data from
|
||||
external sources in the sidebar.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/nylas/N1/master/examples/N1-Github-Contact-Card-Section/screenshot.png">
|
||||
<img src="https://raw.githubusercontent.com/nylas/N1/master/internal_packages/github-contact-card/screenshot.png">
|
||||
|
||||
#### Install this plugin
|
||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
BIN
internal_packages/github-contact-card/icon.png
Normal file
After Width: | Height: | Size: 62 KiB |
|
@ -1,4 +1,4 @@
|
|||
_ = require 'underscore-plus'
|
||||
_ = require 'underscore'
|
||||
GithubUserStore = require "./github-user-store"
|
||||
{React} = require 'nylas-exports'
|
||||
|
||||
|
@ -33,7 +33,7 @@ class GithubProfile extends React.Component
|
|||
# Coffeescript at transpile-time. We're actually creating a nested tree of Javascript
|
||||
# objects here that *represent* the DOM we want.
|
||||
<div className="profile">
|
||||
<img className="logo" src="nylas://N1-Github-Contact-Card-Section/assets/github.png"/>
|
||||
<img className="logo" src="nylas://github-contact-card/assets/github.png"/>
|
||||
<a href={@props.profile.html_url}>{@props.profile.login}</a>
|
||||
<div>{repoElements}</div>
|
||||
</div>
|
|
@ -1,4 +1,4 @@
|
|||
_ = require 'underscore-plus'
|
||||
_ = require 'underscore'
|
||||
Reflux = require 'reflux'
|
||||
request = require 'request'
|
||||
{FocusedContactsStore} = require 'nylas-exports'
|
||||
|
@ -77,8 +77,8 @@ GithubUserStore = Reflux.createStore
|
|||
@_profile = @_cache[email] = profile
|
||||
@trigger(@)
|
||||
|
||||
# Wrap the Node `request` library and pass the User-Agent header, which is required
|
||||
# by Github's API. Also pass `json:true`, which causes responses to be automatically
|
||||
# parsed.
|
||||
_githubRequest: (url, callback) ->
|
||||
request({url: url, headers: {'User-Agent': 'request'}, json: true}, callback)
|
||||
# Wrap the Node `request` library and pass the User-Agent header, which is required
|
||||
# by Github's API. Also pass `json:true`, which causes responses to be automatically
|
||||
# parsed.
|
||||
_githubRequest: (url, callback) ->
|
||||
request({url: url, headers: {'User-Agent': 'request'}, json: true}, callback)
|
|
@ -1,4 +1,4 @@
|
|||
_ = require 'underscore-plus'
|
||||
_ = require 'underscore'
|
||||
GithubContactCardSection = require "./github-contact-card-section"
|
||||
{ComponentRegistry,
|
||||
WorkspaceStore} = require "nylas-exports"
|
|
@ -1,10 +1,12 @@
|
|||
{
|
||||
"name": "N1-Github-Contact-Card-Section",
|
||||
"name": "github-contact-card",
|
||||
"version": "0.1.0",
|
||||
"main": "./lib/main",
|
||||
|
||||
"isOptional": true,
|
||||
"isStarterPackage": true,
|
||||
"title": "Github",
|
||||
|
||||
"title": "GitHub Sidebar Info",
|
||||
"description": "Extends the contact card in the sidebar to show public repos of the people you email.",
|
||||
"icon": "./icon.png",
|
||||
|
||||
|
@ -19,6 +21,6 @@
|
|||
"dependencies": {
|
||||
"reflux": "0.1.13",
|
||||
"request": "^2.53",
|
||||
"underscore-plus": "^1.6"
|
||||
"underscore": "^1.8"
|
||||
}
|
||||
}
|
Before Width: | Height: | Size: 224 KiB After Width: | Height: | Size: 224 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 5.7 KiB After Width: | Height: | Size: 5.7 KiB |
|
@ -83,7 +83,7 @@ class ViewOnGithubButton extends React.Component
|
|||
title={"Visit Thread on GitHub"}>
|
||||
<RetinaImg
|
||||
mode={RetinaImg.Mode.ContentIsMask}
|
||||
url="nylas://N1-Message-View-on-Github/assets/github@2x.png" />
|
||||
url="nylas://message-view-on-github/assets/github@2x.png" />
|
||||
</button>
|
||||
</KeyCommandsRegion>
|
||||
|
|
@ -1,10 +1,15 @@
|
|||
{
|
||||
"name": "N1-Message-View-on-Github",
|
||||
"name": "message-view-on-github",
|
||||
"version": "0.1.0",
|
||||
"main": "./lib/main",
|
||||
"description": "View on Github button",
|
||||
"license": "GPL-3.0",
|
||||
"private": true,
|
||||
|
||||
"title":"View on GitHub",
|
||||
"description": "Adds a 'View On GitHub' button that appears when viewing GitHub emails.",
|
||||
"icon": "./icon.png",
|
||||
"isOptional": true,
|
||||
|
||||
"engines": {
|
||||
"nylas": ">=0.3.0 <0.5.0"
|
||||
},
|
|
@ -3,52 +3,28 @@ path = require 'path'
|
|||
{RetinaImg, ConfigPropContainer} = require 'nylas-component-kit'
|
||||
{EdgehillAPI} = require 'nylas-exports'
|
||||
OnboardingActions = require './onboarding-actions'
|
||||
InitialPackagesStore = require './initial-packages-store'
|
||||
|
||||
RunningPackageInstalls = 0
|
||||
|
||||
class InstallButton extends React.Component
|
||||
constructor: (@props) ->
|
||||
@state =
|
||||
installed: NylasEnv.packages.resolvePackagePath(@props.package.name)?
|
||||
installing: false
|
||||
installed: !NylasEnv.packages.isPackageDisabled(@props.package.name)
|
||||
|
||||
render: =>
|
||||
classname = "btn btn-install"
|
||||
classname += " installing" if @state.installing
|
||||
classname += " installed" if @state.installed
|
||||
|
||||
<div className={classname} onClick={@_onInstall}></div>
|
||||
|
||||
_onInstall: =>
|
||||
return if @state.installing or @state.installed
|
||||
return unless @props.package.path
|
||||
RunningPackageInstalls += 1
|
||||
@setState(installing: true)
|
||||
NylasEnv.packages.installPackageFromPath @props.package.path, (err) =>
|
||||
RunningPackageInstalls -= 1
|
||||
@props.onPackageInstaled()
|
||||
@setState({
|
||||
installing: false
|
||||
installed: NylasEnv.packages.resolvePackagePath(@props.package.name)?
|
||||
})
|
||||
NylasEnv.packages.enablePackage(@props.package.name)
|
||||
@setState(installed: true)
|
||||
|
||||
class InitialPackagesPage extends React.Component
|
||||
@displayName: "InitialPackagesPage"
|
||||
|
||||
constructor: (@props) ->
|
||||
@state = @getStateFromStores()
|
||||
|
||||
componentDidMount: =>
|
||||
@unlisten = InitialPackagesStore.listen =>
|
||||
@setState(@getStateFromStores())
|
||||
|
||||
componentWillUnmount: =>
|
||||
@unlisten?()
|
||||
|
||||
getStateFromStores: =>
|
||||
packages: InitialPackagesStore.starterPackages
|
||||
error: InitialPackagesStore.lastError
|
||||
@state =
|
||||
packages: NylasEnv.packages.getAvailablePackageMetadata().filter ({isStarterPackage}) => isStarterPackage
|
||||
|
||||
render: =>
|
||||
<div className="page opaque" style={width:900, height:650}>
|
||||
|
@ -63,12 +39,11 @@ class InitialPackagesPage extends React.Component
|
|||
</p>
|
||||
|
||||
<div>
|
||||
{@_renderError()}
|
||||
{@state.packages.map (item) =>
|
||||
<div className="initial-package" key={item.name}>
|
||||
<img src={item.iconPath} style={width:50} />
|
||||
<img src="nylas://#{item.name}/#{item.icon}" style={width:50} />
|
||||
<div className="install-container">
|
||||
<InstallButton package={item} onPackageInstaled={@_onPackageInstaled} />
|
||||
<InstallButton package={item} />
|
||||
</div>
|
||||
<div className="name">{item.title}</div>
|
||||
<div className="description">{item.description}</div>
|
||||
|
@ -78,30 +53,14 @@ class InitialPackagesPage extends React.Component
|
|||
<button className="btn btn-large btn-get-started btn-emphasis"
|
||||
style={marginTop: 15}
|
||||
onClick={@_onGetStarted}>
|
||||
{@_renderStartSpinner()}
|
||||
Start Using N1
|
||||
</button>
|
||||
</div>
|
||||
|
||||
_renderError: =>
|
||||
return false unless @state.error
|
||||
<div className="error">{@state.error.toString()}</div>
|
||||
|
||||
_renderStartSpinner: =>
|
||||
return false unless @state.waitingToGetStarted
|
||||
<div className="spinner"></div>
|
||||
|
||||
_onPrevPage: =>
|
||||
OnboardingActions.moveToPage('initial-preferences')
|
||||
|
||||
_onPackageInstaled: =>
|
||||
if RunningPackageInstalls is 0 and @state.waitingToGetStarted
|
||||
@_onGetStarted()
|
||||
|
||||
_onGetStarted: =>
|
||||
if RunningPackageInstalls > 0
|
||||
@setState(waitingToGetStarted: true)
|
||||
else
|
||||
require('electron').ipcRenderer.send('account-setup-successful')
|
||||
require('electron').ipcRenderer.send('account-setup-successful')
|
||||
|
||||
module.exports = InitialPackagesPage
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
path = require 'path'
|
||||
fs = require 'fs'
|
||||
async = require 'async'
|
||||
NylasStore = require 'nylas-store'
|
||||
|
||||
class InitialPackagesStore extends NylasStore
|
||||
constructor: ->
|
||||
@starterPackages = []
|
||||
{resourcePath} = NylasEnv.getLoadSettings()
|
||||
|
||||
if resourcePath.indexOf('app.asar') != -1
|
||||
@starterPackagesPath = path.join(resourcePath,'..', 'app.asar.unpacked', 'examples')
|
||||
else
|
||||
@starterPackagesPath = path.join(resourcePath, "examples")
|
||||
|
||||
@lastError = null
|
||||
@loadStarterPackages()
|
||||
|
||||
loadStarterPackages: =>
|
||||
fs.readdir @starterPackagesPath, (err, filenames) =>
|
||||
return @encounteredError(err) if err
|
||||
packageJSONPaths = filenames.map (name) =>
|
||||
path.join(@starterPackagesPath, name, 'package.json')
|
||||
|
||||
async.filter packageJSONPaths, fs.exists, (packageJSONPaths) =>
|
||||
return @encounteredError(err) if err
|
||||
|
||||
async.map packageJSONPaths, fs.readFile, (err, packageJSONStrings) =>
|
||||
return @encounteredError(err) if err
|
||||
|
||||
@starterPackages = packageJSONStrings.map(@parseStarterPackage)
|
||||
# Remove falsy values / packages that were not starter packages
|
||||
@starterPackages = @starterPackages.filter(Boolean)
|
||||
|
||||
@trigger()
|
||||
|
||||
parseStarterPackage: (jsonString) =>
|
||||
try
|
||||
json = JSON.parse(jsonString)
|
||||
|
||||
unless json?.isStarterPackage?
|
||||
return false
|
||||
unless json.icon? and json.title? and json.description?
|
||||
console.log("Starter package `#{json.name}` is missing icon, title or description")
|
||||
return false
|
||||
|
||||
json.path = path.join(@starterPackagesPath, json.name)
|
||||
json.iconPath = path.join(@starterPackagesPath, json.name, json.icon)
|
||||
json
|
||||
|
||||
encounteredError: (err) =>
|
||||
@lastError = err
|
||||
@trigger()
|
||||
|
||||
module.exports = new InitialPackagesStore()
|
15
internal_packages/personal-level-indicators/README.md
Normal file
|
@ -0,0 +1,15 @@
|
|||
# Personal Level Icon
|
||||
|
||||
An icon to indicate whether an email was sent to either just you, or you and other recipients, or a mailing list that you were on.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/nylas/N1/master/internal_packages/personal-level-indicators/examples-screencap-personal-level-icon.png"/>
|
||||
|
||||
#### Enable this plugin
|
||||
|
||||
1. Download and run N1
|
||||
|
||||
2. Navigate to Preferences > Plugins and click "Enable" beside the plugin.
|
||||
|
||||
#### Who?
|
||||
|
||||
This package is annotated for developers who have no experience with React, Flux, Electron, or N1.
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
BIN
internal_packages/personal-level-indicators/icon.png
Normal file
After Width: | Height: | Size: 59 KiB |