Experimental implementation for webapp plugins (#7185)

* Start of experimental implementation for webapp plugins

* Updates to webapp plugin architecture

* Update pluggable test

* Remove debug code
Этот коммит содержится в:
Joram Wilander
2017-08-29 09:54:02 -04:00
коммит произвёл GitHub
родитель 82a8bd99cc
Коммит 257edc9ea3
15 изменённых файлов: 354 добавлений и 32 удалений

51
webapp/plugins/index.js Обычный файл
Просмотреть файл

@@ -0,0 +1,51 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
// EXPERIMENTAL - SUBJECT TO CHANGE
import store from 'stores/redux_store.jsx';
import {ActionTypes} from 'utils/constants.jsx';
import {getSiteURL} from 'utils/url.jsx';
window.plugins = {};
export function registerComponents(components) {
store.dispatch({
type: ActionTypes.RECEIVED_PLUGIN_COMPONENTS,
data: components || {}
});
}
export function initializePlugins() {
const pluginJson = window.mm_config.Plugins || '[]';
let pluginManifests;
try {
pluginManifests = JSON.parse(pluginJson);
} catch (error) {
console.error('Invalid plugins JSON: ' + error); //eslint-disable-line no-console
return;
}
pluginManifests.forEach((m) => {
function onLoad() {
// Add the plugin's js to the page
const script = document.createElement('script');
script.type = 'text/javascript';
script.text = this.responseText;
document.getElementsByTagName('head')[0].appendChild(script);
// Initialize the plugin
console.log('Registering ' + m.id + ' plugin...'); //eslint-disable-line no-console
const plugin = window.plugins[m.id];
plugin.initialize(registerComponents, store);
console.log('...done'); //eslint-disable-line no-console
}
// Fetch the plugin's bundled js
const xhrObj = new XMLHttpRequest();
xhrObj.open('GET', getSiteURL() + m.bundle_path, true);
xhrObj.addEventListener('load', onLoad);
xhrObj.send('');
});
}

17
webapp/plugins/pluggable/index.js Обычный файл
Просмотреть файл

@@ -0,0 +1,17 @@
// Copyright (c) 2017 Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
import {connect} from 'react-redux';
import {getTheme} from 'mattermost-redux/selectors/entities/preferences';
import Pluggable from './pluggable.jsx';
function mapStateToProps(state, ownProps) {
return {
...ownProps,
components: state.plugins.components,
theme: getTheme(state)
};
}
export default connect(mapStateToProps)(Pluggable);

55
webapp/plugins/pluggable/pluggable.jsx Обычный файл
Просмотреть файл

@@ -0,0 +1,55 @@
// Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved.
// See License.txt for license information.
// EXPERIMENTAL - SUBJECT TO CHANGE
import React from 'react';
import PropTypes from 'prop-types';
export default class Pluggable extends React.PureComponent {
static propTypes = {
/*
* Should be a single overridable React component
*/
children: PropTypes.element.isRequired,
/*
* Components for overriding provided by plugins
*/
components: PropTypes.object.isRequired,
/*
* Logged in user's theme
*/
theme: PropTypes.object.isRequired
}
render() {
const child = React.Children.only(this.props.children).type;
const components = this.props.components;
if (child == null) {
return null;
}
// Include any props passed to this component or to the child component
let props = {...this.props};
Reflect.deleteProperty(props, 'children');
Reflect.deleteProperty(props, 'components');
props = {...props, ...this.props.children.props};
// Override the default component with any registered plugin's component
if (components.hasOwnProperty(child.name)) {
const PluginComponent = components[child.name];
return (
<PluginComponent
{...props}
theme={this.props.theme}
/>
);
}
return React.cloneElement(this.props.children, {...props});
}
}