Remove the (broken) plugin template and link to the starter github repo instead #1645

This commit is contained in:
Ben Gotow 2019-10-08 21:26:03 -05:00
parent 2165c54be2
commit e319e9d447
10 changed files with 8 additions and 332 deletions

View file

@ -26,9 +26,13 @@ Mailspring's UI is entirely open-source and pull requests and contributions are
### Building A Plugin
Plugins lie at the heart of Mailspring and give it its powerful features. Building your own plugins allows you to integrate the app with other tools, experiment with new workflows, and more. Follow the [Getting Started guide](https://Foundry376.github.io/Mailspring/) to write your first plugin in five minutes. To create your own theme, go to our [Theme Starter guide](https://github.com/Foundry376/Mailspring-Theme-Starter).
Plugins lie at the heart of Mailspring and give it its powerful features. Building your own plugins allows you to integrate the app with other tools, experiment with new workflows, and more. Follow the [Getting Started guide](https://Foundry376.github.io/Mailspring/) to write your first plugin in five minutes.
A plugin "store" like the Chrome Web Store is coming soon, and will make it easy for other users to discover plugins you create.
- To create your own theme, check out the [Mailspring-Theme-Starter](https://github.com/Foundry376/Mailspring-Theme-Starter).
- To create your own plugin, check out the [Mailspring-Plugin-Starter](https://github.com/Foundry376/Mailspring-Plugin-Starter).
A plugin "store" like the Chrome Web Store is coming soon, and will make it easy for other users to discover plugins you create. (Right now, users need to "sideload" the plugins into the app by downloading them and copying them into place.)
### Building a Theme

View file

@ -1,6 +1,6 @@
import path from 'path';
import fs from 'fs-plus';
import { shell, remote, ipcRenderer } from 'electron';
import { shell } from 'electron';
import { localized } from './intl';
import Package from './package';
@ -197,86 +197,6 @@ export default class PackageManager {
}
createPackageManually() {
if (!AppEnv.inDevMode()) {
const btn = remote.dialog.showMessageBox({
type: 'warning',
message: localized('Run with debug flags?'),
detail: localized(
`To develop plugins, you should run Mailspring with debug flags. This gives you better error messages, the debug version of React, and more. You can disable it at any time from the Developer menu.`
),
buttons: [localized('OK'), localized('Cancel')],
});
if (btn === 0) {
ipcRenderer.send('command', 'application:toggle-dev');
}
return;
}
const devPackagesDir = path.join(this.configDirPath, 'dev', 'packages');
fs.makeTreeSync(devPackagesDir);
AppEnv.showSaveDialog(
{
title: localized('Save New Package'),
defaultPath: devPackagesDir,
properties: ['createDirectory'],
},
newPackagePath => {
if (!newPackagePath) return;
const newName = path.basename(newPackagePath);
if (!newPackagePath.startsWith(devPackagesDir)) {
return AppEnv.showErrorDialog({
title: localized('Invalid plugin location'),
message: localized('Sorry, you must create plugins in the dev/packages folder.'),
});
}
if (this.available[newName]) {
return AppEnv.showErrorDialog({
title: localized('Invalid plugin name'),
message: localized('Sorry, you must give your plugin a unique name.'),
});
}
if (newName.indexOf(' ') !== -1) {
return AppEnv.showErrorDialog({
title: localized('Invalid plugin name'),
message: localized('Sorry, plugin names cannot contain spaces.'),
});
}
fs.mkdir(newPackagePath, err => {
if (err) {
return AppEnv.showErrorDialog({
title: localized('Could not create plugin'),
message: err.toString(),
});
}
const templatePath = path.join(this.resourcePath, 'static', 'package-template');
fs.copySync(templatePath, newPackagePath);
const packageJSON = require(path.join(templatePath, 'package.json'));
packageJSON.name = newName;
packageJSON.engines.mailspring = `>=${AppEnv.getVersion().split('-')[0]}`;
fs.writeFileSync(
path.join(newPackagePath, 'package.json'),
JSON.stringify(packageJSON, null, 2)
);
setTimeout(() => {
// show the package in the finder
shell.showItemInFolder(newPackagePath);
// load the package into the app
const pkg = new Package(newPackagePath);
this.available[pkg.name] = pkg;
this.activatePackage(pkg);
}, 0);
});
}
);
shell.openExternal('https://github.com/Foundry376/Mailspring-Plugin-Starter');
}
}

View file

@ -1,4 +0,0 @@
## My Package
A sample package for N1. It demonstrates how to add components to the composer's action bar and the message sidebar. Enjoy!

View file

@ -1,32 +0,0 @@
import { ComponentRegistry } from 'mailspring-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);
}

View file

@ -1,55 +0,0 @@
import React from 'react';
import { PropTypes } from 'mailspring-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 = {
draft: PropTypes.object.isRequired,
session: PropTypes.object.isRequired,
};
shouldComponentUpdate(nextProps) {
// Our render method doesn't use the provided `draft`, and the draft changes
// constantly (on every keystroke!) `shouldComponentUpdate` helps keep Mailspring fast.
return nextProps.session !== this.props.session;
}
_onClick = () => {
const { session, draft } = this.props;
// 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.
const newSubject = `${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('electron').remote.dialog;
}
render() {
return (
<div className="my-package">
<button className="btn btn-toolbar" onClick={() => this._onClick()} ref="button">
Hello World
</button>
</div>
);
}
}

View file

@ -1,78 +0,0 @@
import {
React,
FocusedContactsStore,
} from 'mailspring-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 mailspring:// URL scheme:
//
// <RetinaImg
// url="mailspring://<<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,
};

View file

@ -1,19 +0,0 @@
{
"name": "replaced-at-runtime",
"main": "./lib/main",
"version": "0.1.0",
"repository": {
"type": "git",
"url": ""
},
"engines": {
"mailspring": ">=1.0.1"
},
"windowTypes": {
"default": true,
"composer": true
},
"description": "Enter a description of your package!",
"dependencies": {},
"license": "MIT"
}

View file

@ -1,27 +0,0 @@
import { ComponentRegistry } from 'mailspring-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);
});
});

View file

@ -1,27 +0,0 @@
import {React, ReactDOM} from 'mailspring-exports';
const ReactTestUtils = require('react-dom/test-utils')
import MyComposerButton from '../lib/my-composer-button';
describe("MyComposerButton", () => {
beforeEach(() => {
this.component = ReactTestUtils.renderIntoDocument(
<MyComposerButton headerMessageId="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 = ReactDOM.findDOMNode(this.component.refs.button);
ReactTestUtils.Simulate.click(buttonNode);
expect(this.component._onClick).toHaveBeenCalled();
});
});

View file

@ -1,6 +0,0 @@
@import "ui-variables";
@import "ui-mixins";
.my-package .btn {
}