diff --git a/CHANGELOG.md b/CHANGELOG.md index af6f237e..e05e4b71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -55,6 +55,7 @@ Version 2.0.0 them to be displayed by name in queries that join with the mapping. - Added option to configure timeout for exported Prometheus metrics. - Added option to set address to bind HTTP(S) port to. +- Added an overview of the installed plugins to the web interface. ### Changes diff --git a/packages/master/master.js b/packages/master/master.js index 2474c0d6..bb5a7da9 100755 --- a/packages/master/master.js +++ b/packages/master/master.js @@ -279,7 +279,7 @@ app.get("/api/plugins", (req, res) => { for (let pluginInfo of pluginInfos) { let name = pluginInfo.name; let enabled = masterPlugins.has(name) && masterConfig.group(name).get("enabled"); - plugins.push({ name, enabled }); + plugins.push({ name, version: pluginInfo.version, enabled }); } res.send(plugins); }); diff --git a/packages/master/src/routes.js b/packages/master/src/routes.js index bcfde4ee..c72ab970 100644 --- a/packages/master/src/routes.js +++ b/packages/master/src/routes.js @@ -11,5 +11,6 @@ module.exports = [ "/users/:id/view", "/roles", "/roles/:id/view", - "/settings", + "/plugins", + "/plugins/:name/view", ]; diff --git a/packages/web_ui/src/bootstrap.jsx b/packages/web_ui/src/bootstrap.jsx index 4b245cd7..627f446b 100644 --- a/packages/web_ui/src/bootstrap.jsx +++ b/packages/web_ui/src/bootstrap.jsx @@ -44,9 +44,11 @@ async function loadPlugins() { let container = window[`plugin_${meta.name}`]; await container.init(__webpack_share_scopes__.default); let pluginInfo = (await container.get("./info"))(); + let pluginPackage = (await container.get("./package.json"))(); plugins.push({ meta, info: pluginInfo, + package: pluginPackage, container, }); diff --git a/packages/web_ui/src/components/PluginViewPage.jsx b/packages/web_ui/src/components/PluginViewPage.jsx new file mode 100644 index 00000000..1445f232 --- /dev/null +++ b/packages/web_ui/src/components/PluginViewPage.jsx @@ -0,0 +1,84 @@ +import React, { useEffect, useContext, useState } from "react"; +import { useHistory, useParams } from "react-router-dom"; +import { Alert, Descriptions } from "antd"; + +import PluginsContext from "./PluginsContext"; +import PageLayout from "./PageLayout"; +import { notifyErrorHandler } from "../util/notify"; + + +export default function PluginViewPage() { + let params = useParams(); + let plugins = useContext(PluginsContext); + let pluginName = params.name; + + let plugin = plugins.find(plugin => plugin.meta.name === pluginName); + let pluginTitle = plugin.info ? plugin.info.title : plugin.meta.name; + let nav = [{ name: "Plugins", path: "/plugins" }, { name: pluginTitle }]; + if (!plugin) { + return + Plugin not found + Plugin with name {pluginName} was not found on the master server. + ; + } + + if (!plugin.info) { + return + + {plugin.meta.version} + {plugin.meta.enabled ? "Yes" : "No"} + + + ; + } + + return + + {plugin.meta.version} + {plugin.meta.enabled ? "Yes" : "No"} + {plugin.info.description} + {plugin.package.homepage ? + {plugin.package.homepage} + : null} + {plugin.package.author ? + {plugin.package.author} + : null} + {plugin.package.license} + + {plugin.meta.version !== plugin.package.version ? : null} + ; +} diff --git a/packages/web_ui/src/components/PluginsPage.jsx b/packages/web_ui/src/components/PluginsPage.jsx new file mode 100644 index 00000000..042b53f6 --- /dev/null +++ b/packages/web_ui/src/components/PluginsPage.jsx @@ -0,0 +1,52 @@ +import React, { useContext } from "react"; +import { useHistory } from "react-router-dom"; +import { Table } from "antd"; + +import PluginsContext from "./PluginsContext"; +import PageLayout from "./PageLayout"; + + +export default function PluginsPage() { + let plugins = useContext(PluginsContext); + let history = useHistory(); + + return + Plugins + plugin.info ? plugin.info.title : plugin.meta.name, + }, + { + title: "Version", + key: "version", + render: plugin => { + if (!plugin.package) { + return "Error loading module"; + } + if (plugin.package.version !== plugin.meta.version) { + return "Version missmatched"; + } + return plugin.package.version; + } + }, + { + title: "Enabled", + dataIndex: ["meta", "enabled"], + render: enabled => enabled ? "Yes" : null, + responsive: ["sm"], + }, + ]} + dataSource={plugins} + rowKey={plugin => plugin.meta.name} + pagination={false} + onRow={plugin => ({ + onClick: event => { + history.push(`/plugins/${plugin.meta.name}/view`); + } + })} + /> + ; +} diff --git a/packages/web_ui/src/components/SiteLayout.jsx b/packages/web_ui/src/components/SiteLayout.jsx index dc09a0a7..6553837b 100644 --- a/packages/web_ui/src/components/SiteLayout.jsx +++ b/packages/web_ui/src/components/SiteLayout.jsx @@ -17,11 +17,14 @@ import UsersPage from "./UsersPage"; import UserViewPage from "./UserViewPage"; import RolesPage from "./RolesPage"; import RoleViewPage from "./RoleViewPage"; +import PluginsPage from "./PluginsPage"; +import PluginViewPage from "./PluginViewPage"; const pages = [ { path: "/instances/:id/view", sidebarPath: "/instances", content: }, { path: "/users/:name/view", sidebarPath: "/users", content: }, { path: "/roles/:id/view", sidebarPath: "/roles", content: }, + { path: "/plugins/:name/view", sidebarPath: "/plugins", content: }, ]; const sidebar = [ @@ -30,6 +33,7 @@ const sidebar = [ { name: "Instances", path: "/instances", content: }, { name: "Users", path: "/users", content: }, { name: "Roles", path: "/roles", content: }, + { name: "Plugins", path: "/plugins", content: }, ]; diff --git a/plugins/global_chat/webpack.config.js b/plugins/global_chat/webpack.config.js index 60b98d7b..6f19d7f7 100644 --- a/plugins/global_chat/webpack.config.js +++ b/plugins/global_chat/webpack.config.js @@ -19,6 +19,7 @@ module.exports = (env = {}) => merge(common(env), { filename: "remoteEntry.js", exposes: { "./info": "./info.js", + "./package.json": "./package.json", }, shared: { "@clusterio/lib": { import: false }, diff --git a/plugins/research_sync/webpack.config.js b/plugins/research_sync/webpack.config.js index 484dfafe..80a7863e 100644 --- a/plugins/research_sync/webpack.config.js +++ b/plugins/research_sync/webpack.config.js @@ -19,6 +19,7 @@ module.exports = (env = {}) => merge(common(env), { filename: "remoteEntry.js", exposes: { "./info": "./info.js", + "./package.json": "./package.json", }, shared: { "@clusterio/lib": { import: false }, diff --git a/plugins/statistics_exporter/webpack.config.js b/plugins/statistics_exporter/webpack.config.js index 0da4c121..9a8259e7 100644 --- a/plugins/statistics_exporter/webpack.config.js +++ b/plugins/statistics_exporter/webpack.config.js @@ -19,6 +19,7 @@ module.exports = (env = {}) => merge(common(env), { filename: "remoteEntry.js", exposes: { "./info": "./info.js", + "./package.json": "./package.json", }, shared: { "@clusterio/lib": { import: false }, diff --git a/plugins/subspace_storage/webpack.config.js b/plugins/subspace_storage/webpack.config.js index cfd034a8..c53e2ca3 100644 --- a/plugins/subspace_storage/webpack.config.js +++ b/plugins/subspace_storage/webpack.config.js @@ -19,6 +19,7 @@ module.exports = (env = {}) => merge(common(env), { filename: "remoteEntry.js", exposes: { "./info": "./info.js", + "./package.json": "./package.json", }, shared: { "@clusterio/lib": { import: false },
Plugin with name {pluginName} was not found on the master server.