Skip to content

Commit

Permalink
UI: Settings main page with overview and plugin information (#366)
Browse files Browse the repository at this point in the history
  • Loading branch information
psrok1 committed May 13, 2021
1 parent a964e03 commit a50087c
Show file tree
Hide file tree
Showing 8 changed files with 208 additions and 86 deletions.
4 changes: 2 additions & 2 deletions mwdb/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@
from mwdb.resources.search import SearchResource
from mwdb.resources.server import (
PingResource,
ServerAdminInfoResource,
ServerDocsResource,
ServerInfoResource,
ServerPluginInfoResource,
)
from mwdb.resources.share import ShareGroupListResource, ShareResource
from mwdb.resources.tag import TagListResource, TagResource
Expand Down Expand Up @@ -201,7 +201,7 @@ def require_auth():
# Server health endpoints
api.add_resource(PingResource, "/ping")
api.add_resource(ServerInfoResource, "/server")
api.add_resource(ServerPluginInfoResource, "/server/plugins")
api.add_resource(ServerAdminInfoResource, "/server/admin")
api.add_resource(ServerDocsResource, "/docs")

# Authentication endpoints
Expand Down
34 changes: 26 additions & 8 deletions mwdb/resources/server.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
from flask import g
from flask_restful import Resource
from werkzeug.exceptions import Forbidden

from mwdb.core.app import api
from mwdb.core.capabilities import Capabilities
from mwdb.core.config import app_config
from mwdb.core.plugins import get_plugin_info
from mwdb.schema.server import (
ServerAdminInfoResponseSchema,
ServerInfoResponseSchema,
ServerPingResponseSchema,
ServerPluginInfoResponseSchema,
)
from mwdb.version import app_build_version

Expand Down Expand Up @@ -63,26 +65,42 @@ def get(self):
)


class ServerPluginInfoResource(Resource):
class ServerAdminInfoResource(Resource):
@requires_authorization
def get(self):
"""
---
summary: Get plugin information
description: Returns information about installed plugins
summary: Get extended server information
description: |
Returns information about extra flags and installed plugins
Requires any administration capability (manage_users, manage_attributes)
security:
- bearerAuth: []
tags:
- server
responses:
200:
description: Server plugin info with public configuration
description: Server extended information
content:
application/json:
schema: ServerInfoResponseSchema
schema: ServerAdminInfoResponseSchema
403:
description: When user doesn't have any of required capabilities
"""
schema = ServerPluginInfoResponseSchema()
return schema.dump({"active_plugins": get_plugin_info()})
if not g.auth_user.has_rights(
Capabilities.manage_users
) and not g.auth_user.has_rights(Capabilities.managing_attributes):
raise Forbidden("You don't have required capability to perform this action")

schema = ServerAdminInfoResponseSchema()
return schema.dump(
{
"rate_limit_enabled": app_config.mwdb.enable_rate_limit,
"plugins_enabled": app_config.mwdb.enable_plugins,
"active_plugins": get_plugin_info(),
}
)


class ServerDocsResource(Resource):
Expand Down
4 changes: 3 additions & 1 deletion mwdb/schema/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@ class ServerInfoResponseSchema(Schema):
recaptcha_site_key = fields.Str(required=True, allow_none=True)


class ServerPluginInfoResponseSchema(Schema):
class ServerAdminInfoResponseSchema(Schema):
rate_limit_enabled = fields.Boolean(required=True, allow_none=False)
plugins_enabled = fields.Boolean(required=True, allow_none=False)
active_plugins = fields.Dict(required=True, allow_none=False)
19 changes: 16 additions & 3 deletions mwdb/web/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,21 @@ function DefaultRoute() {
);
}

function SettingsRoute(args) {
const auth = useContext(AuthContext);
return (
<ProtectedRoute
condition={
auth.hasCapability(Capability.managingAttributes) ||
auth.hasCapability(Capability.manageUsers)
}
{...args}
>
<SettingsView />
</ProtectedRoute>
);
}

export default function App() {
const auth = useContext(AuthContext);
const config = useContext(ConfigContext);
Expand Down Expand Up @@ -222,9 +237,7 @@ export default function App() {
<ProtectedRoute path="/remote/:remote">
<RemoteViews />
</ProtectedRoute>
<ProtectedRoute path="/admin">
<SettingsView />
</ProtectedRoute>
<SettingsRoute path="/admin" />
<ProtectedRoute path={["/profile/user/:user", "/profile"]}>
<ProfileView />
</ProtectedRoute>
Expand Down
6 changes: 3 additions & 3 deletions mwdb/web/src/commons/api/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ function getServerInfo() {
return axios.get("/server");
}

function getServerPluginInfo() {
return axios.get("/server/plugins");
function getServerAdminInfo() {
return axios.get("/server/admin");
}

function authLogin(login, password) {
Expand Down Expand Up @@ -466,7 +466,7 @@ export default {
getApiForEnvironment,
getServerDocs,
getServerInfo,
getServerPluginInfo,
getServerAdminInfo,
authLogin,
authGroups,
authRefresh,
Expand Down
66 changes: 1 addition & 65 deletions mwdb/web/src/components/About.js
Original file line number Diff line number Diff line change
@@ -1,55 +1,12 @@
import React, { useCallback, useContext, useEffect, useState } from "react";
import React, { useContext } from "react";

import api from "@mwdb-web/commons/api";
import { ConfigContext } from "@mwdb-web/commons/config";
import { View } from "@mwdb-web/commons/ui";

import logo from "../assets/logo.png";

function PluginItems(props) {
const { name, info } = props;
const { active, version, description } = info;

return (
<tr>
<td>
{name}{" "}
{active ? (
<span className="badge badge-success">Active</span>
) : (
<span className="badge badge-danger">Inactive</span>
)}
</td>
<td>{description}</td>
<td>{version}</td>
</tr>
);
}

export default function About() {
const config = useContext(ConfigContext);
const [pluginsList, setPluginsList] = useState([]);

async function updatePlugins() {
try {
const response = await api.getServerPluginInfo();
setPluginsList(
Object.entries(response.data["active_plugins"]).sort()
);
} catch (e) {
console.error(e);
}
}

const getPlugins = useCallback(updatePlugins, []);

useEffect(() => {
getPlugins();
}, [getPlugins]);

const plugins = pluginsList.map(([key, value]) => (
<PluginItems name={key} info={value} />
));

return (
<div className="align-items-center">
Expand Down Expand Up @@ -82,27 +39,6 @@ export default function About() {
</div>
</View>
</div>
{plugins.length ? (
<div className="container">
<table className="table table-striped table-bordered wrap-table">
<thead>
<tr>
<th>Plugin name</th>
<th>Description</th>
<th>Version</th>
</tr>
</thead>
<tbody>{plugins}</tbody>
</table>
</div>
) : (
<p style={{ textAlign: "center" }}>
No plugins are installed. Visit our{" "}
<a href="https://mwdb.readthedocs.io/">documentation</a> to
learn about MWDB plugins and how they can be used and
installed.
</p>
)}
</div>
);
}
17 changes: 13 additions & 4 deletions mwdb/web/src/components/Settings/SettingsView.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useState, useEffect, useContext } from "react";
import { NavLink, Redirect, Switch } from "react-router-dom";
import { NavLink, Route, Switch } from "react-router-dom";

import { faUsersCog } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
Expand All @@ -23,6 +23,7 @@ import AttributeDefine from "./Views/AttributeDefine";
import UserView from "./Views/UserView";
import AccessControl from "./Views/AccessControl";
import GroupView from "./Views/GroupView";
import SettingsOverview from "./Views/SettingsOverview";

function SettingsNav() {
const auth = useContext(AuthContext);
Expand Down Expand Up @@ -50,6 +51,14 @@ function SettingsNav() {
}, [isAdmin]);

const adminLinks = [
...(auth.hasCapability(Capability.managingAttributes) ||
auth.hasCapability(Capability.manageUsers)
? [
<NavLink to="/admin" className="nav-link">
Overview
</NavLink>,
]
: []),
...(auth.hasCapability(Capability.manageUsers)
? [
...(config.config["is_registration_enabled"]
Expand Down Expand Up @@ -124,9 +133,9 @@ export default function SettingsView(props) {
<div className="col-8">
<div className="tab-content">
<Switch>
<AdministrativeRoute exact path="/admin">
<Redirect to="/admin/pending" />
</AdministrativeRoute>
<Route exact path="/admin">
<SettingsOverview />
</Route>
<AdministrativeRoute path="/admin/pending">
<ShowPendingUsers />
</AdministrativeRoute>
Expand Down

0 comments on commit a50087c

Please sign in to comment.