You've already forked mattermost-webapp
mirror of
https://github.com/zerotier/mattermost-webapp.git
synced 2026-05-22 16:23:25 -07:00
170 lines
5.8 KiB
JavaScript
170 lines
5.8 KiB
JavaScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
import {Client4} from 'mattermost-redux/client';
|
|
|
|
import store from 'stores/redux_store.jsx';
|
|
import {ActionTypes} from 'utils/constants.jsx';
|
|
import {getSiteURL} from 'utils/url.jsx';
|
|
import PluginRegistry from 'plugins/registry';
|
|
import {unregisterAllPluginWebSocketEvents, unregisterPluginReconnectHandler} from 'actions/websocket_actions.jsx';
|
|
|
|
// plugins records all active web app plugins by id.
|
|
window.plugins = {};
|
|
|
|
// registerPlugin, on the global window object, should be invoked by a plugin's web app bundle as
|
|
// it is loaded.
|
|
//
|
|
// During the beta, plugins manipulated the global window.plugins data structure directly. This
|
|
// remains possible, but is officially deprecated and may be removed in a future release.
|
|
function registerPlugin(id, plugin) {
|
|
window.plugins[id] = plugin;
|
|
}
|
|
window.registerPlugin = registerPlugin;
|
|
|
|
// initializePlugins queries the server for all enabled plugins and loads each in turn.
|
|
export async function initializePlugins() {
|
|
if (store.getState().entities.general.config.PluginsEnabled !== 'true') {
|
|
return;
|
|
}
|
|
|
|
const {data, error} = await getPlugins()(store.dispatch);
|
|
if (error) {
|
|
console.error(error); //eslint-disable-line no-console
|
|
return;
|
|
}
|
|
|
|
if (data == null || data.length === 0) {
|
|
return;
|
|
}
|
|
|
|
await Promise.all(data.map((m) => {
|
|
return loadPlugin(m);
|
|
}));
|
|
}
|
|
|
|
// getPlugins queries the server for all enabled plugins
|
|
export function getPlugins() {
|
|
return async (dispatch) => {
|
|
let plugins;
|
|
try {
|
|
plugins = await Client4.getWebappPlugins();
|
|
} catch (error) {
|
|
return {error};
|
|
}
|
|
|
|
dispatch({type: ActionTypes.RECEIVED_WEBAPP_PLUGINS, data: plugins});
|
|
|
|
return {data: plugins};
|
|
};
|
|
}
|
|
|
|
// loadedPlugins tracks which plugins have been added as script tags to the page
|
|
const loadedPlugins = {};
|
|
|
|
// loadPlugin fetches the web app bundle described by the given manifest, waits for the bundle to
|
|
// load, and then ensures the plugin has been initialized.
|
|
export function loadPlugin(manifest) {
|
|
return new Promise((resolve) => {
|
|
// Don't load it again if previously loaded
|
|
if (loadedPlugins[manifest.id]) {
|
|
resolve();
|
|
return;
|
|
}
|
|
|
|
function onLoad() {
|
|
initializePlugin(manifest);
|
|
console.log('Loaded ' + manifest.id + ' plugin'); //eslint-disable-line no-console
|
|
resolve();
|
|
}
|
|
|
|
// Backwards compatibility for old plugins
|
|
let bundlePath = manifest.webapp.bundle_path;
|
|
if (bundlePath.includes('/static/') && !bundlePath.includes('/static/plugins/')) {
|
|
bundlePath = bundlePath.replace('/static/', '/static/plugins/');
|
|
}
|
|
|
|
const script = document.createElement('script');
|
|
script.id = 'plugin_' + manifest.id;
|
|
script.type = 'text/javascript';
|
|
script.src = getSiteURL() + bundlePath;
|
|
script.onload = onLoad;
|
|
console.log('Loading ' + manifest.id + ' plugin'); //eslint-disable-line no-console
|
|
document.getElementsByTagName('head')[0].appendChild(script);
|
|
|
|
loadedPlugins[manifest.id] = true;
|
|
});
|
|
}
|
|
|
|
// initializePlugin creates a registry specific to the plugin and invokes any initialize function
|
|
// on the registered plugin class.
|
|
function initializePlugin(manifest) {
|
|
// Initialize the plugin
|
|
const plugin = window.plugins[manifest.id];
|
|
const registry = new PluginRegistry(manifest.id);
|
|
if (plugin && plugin.initialize) {
|
|
plugin.initialize(registry, store);
|
|
}
|
|
}
|
|
|
|
// removePlugin triggers any uninitialize callback on the registered plugin, unregisters any
|
|
// event handlers, and removes the plugin script from the DOM entirely. The plugin is responsible
|
|
// for removing any of its registered components.
|
|
export function removePlugin(manifest) {
|
|
console.log('Removing ' + manifest.id + ' plugin'); //eslint-disable-line no-console
|
|
|
|
loadedPlugins[manifest.id] = false;
|
|
|
|
const plugin = window.plugins[manifest.id];
|
|
if (plugin && plugin.uninitialize) {
|
|
plugin.uninitialize();
|
|
|
|
// Support the deprecated deinitialize callback from the plugins beta.
|
|
} else if (plugin && plugin.deinitialize) {
|
|
plugin.deinitialize();
|
|
}
|
|
unregisterAllPluginWebSocketEvents(manifest.id);
|
|
unregisterPluginReconnectHandler(manifest.id);
|
|
const script = document.getElementById('plugin_' + manifest.id);
|
|
if (!script) {
|
|
return;
|
|
}
|
|
script.parentNode.removeChild(script);
|
|
console.log('Removed ' + manifest.id + ' plugin'); //eslint-disable-line no-console
|
|
}
|
|
|
|
// loadPluginsIfNecessary synchronizes the current state of loaded plugins with that of the server,
|
|
// loading any newly added plugins and unloading any removed ones.
|
|
export async function loadPluginsIfNecessary() {
|
|
if (store.getState().entities.general.config.PluginsEnabled !== 'true') {
|
|
return;
|
|
}
|
|
|
|
const oldManifests = store.getState().plugins.plugins;
|
|
|
|
const {error} = await getPlugins()(store.dispatch);
|
|
if (error) {
|
|
console.error(error); //eslint-disable-line no-console
|
|
return;
|
|
}
|
|
|
|
const newManifests = store.getState().plugins.plugins;
|
|
|
|
// Get new plugins and update existing plugins if version changed
|
|
Object.values(newManifests).forEach((newManifest) => {
|
|
const oldManifest = oldManifests[newManifest.id];
|
|
if (!oldManifest || oldManifest.version !== newManifest.version) {
|
|
loadPlugin(newManifest);
|
|
}
|
|
});
|
|
|
|
// Remove old plugins
|
|
Object.keys(oldManifests).forEach((id) => {
|
|
if (!newManifests.hasOwnProperty(id)) {
|
|
const oldManifest = oldManifests[id];
|
|
store.dispatch({type: ActionTypes.REMOVED_WEBAPP_PLUGIN, data: oldManifest});
|
|
removePlugin(oldManifest);
|
|
}
|
|
});
|
|
}
|