diff --git a/maubot/management/frontend/src/Login.js b/maubot/management/frontend/src/Login.js index af95d07..e342abe 100644 --- a/maubot/management/frontend/src/Login.js +++ b/maubot/management/frontend/src/Login.js @@ -14,7 +14,7 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . import React, { Component } from "react" -import Spinner from "./Spinner" +import Spinner from "./components/Spinner" import api from "./api" class Login extends Component { diff --git a/maubot/management/frontend/src/MaubotRouter.js b/maubot/management/frontend/src/MaubotRouter.js index 891f613..b3c7561 100644 --- a/maubot/management/frontend/src/MaubotRouter.js +++ b/maubot/management/frontend/src/MaubotRouter.js @@ -14,11 +14,11 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . import React, { Component } from "react" -import { BrowserRouter as Router, Route, Redirect } from "react-router-dom" -import PrivateRoute from "./PrivateRoute" -import Home from "./Home" +import { BrowserRouter as Router, Switch } from "react-router-dom" +import PrivateRoute from "./components/PrivateRoute" +import Dashboard from "./dashboard" import Login from "./Login" -import Spinner from "./Spinner" +import Spinner from "./components/Spinner" import api from "./api" class MaubotRouter extends Component { @@ -43,6 +43,8 @@ class MaubotRouter extends Component { if (username) { localStorage.username = username this.setState({ authed: true }) + } else { + localStorage.accessToken = undefined } } catch (err) { console.error(err) @@ -60,10 +62,11 @@ class MaubotRouter extends Component { } return
- }/> - - } - authed={!this.state.authed} to="/dashboard"/> + + } + authed={!this.state.authed} to="/"/> + +
} diff --git a/maubot/management/frontend/src/PrivateRoute.js b/maubot/management/frontend/src/components/PrivateRoute.js similarity index 100% rename from maubot/management/frontend/src/PrivateRoute.js rename to maubot/management/frontend/src/components/PrivateRoute.js diff --git a/maubot/management/frontend/src/Spinner.js b/maubot/management/frontend/src/components/Spinner.js similarity index 100% rename from maubot/management/frontend/src/Spinner.js rename to maubot/management/frontend/src/components/Spinner.js diff --git a/maubot/management/frontend/src/dashboard/client/ListEntry.js b/maubot/management/frontend/src/dashboard/client/ListEntry.js new file mode 100644 index 0000000..e19055f --- /dev/null +++ b/maubot/management/frontend/src/dashboard/client/ListEntry.js @@ -0,0 +1,30 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2018 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import React from "react" +import { Link } from "react-router-dom" +import { ReactComponent as ChevronRight } from "../../res/chevron-right.svg" + +const ClientListEntry = ({ client }) => ( + + {client.id.substr(1, + {client.displayname || client.id} + + +) + +export default ClientListEntry diff --git a/maubot/management/frontend/src/Home.js b/maubot/management/frontend/src/dashboard/client/View.js similarity index 86% rename from maubot/management/frontend/src/Home.js rename to maubot/management/frontend/src/dashboard/client/View.js index 464294d..5256549 100644 --- a/maubot/management/frontend/src/Home.js +++ b/maubot/management/frontend/src/dashboard/client/View.js @@ -15,12 +15,10 @@ // along with this program. If not, see . import React, { Component } from "react" -class Home extends Component { +class ClientView extends Component { render() { - return
- Hello, {localStorage.username} -
+ return
{this.props.client.displayname}
} } -export default Home +export default ClientView diff --git a/maubot/management/frontend/src/dashboard/index.js b/maubot/management/frontend/src/dashboard/index.js new file mode 100644 index 0000000..6e40a8f --- /dev/null +++ b/maubot/management/frontend/src/dashboard/index.js @@ -0,0 +1,105 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2018 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import React, { Component } from "react" +import { Route, Redirect } from "react-router-dom" +import api from "../api" +import InstanceListEntry from "./instance/ListEntry" +import InstanceView from "./instance/View" +import ClientListEntry from "./client/ListEntry" +import ClientView from "./client/View" +import PluginListEntry from "./plugin/ListEntry" +import PluginView from "./plugin/View" + +class Dashboard extends Component { + constructor(props) { + super(props) + this.state = { + instances: {}, + clients: {}, + plugins: {}, + } + global.maubot = this + } + + async componentWillMount() { + const [instanceList, clientList, pluginList] = await Promise.all([ + api.getInstances(), api.getClients(), api.getPlugins()]) + const instances = {} + for (const instance of instanceList) { + instances[instance.id] = instance + } + const clients = {} + for (const client of clientList) { + clients[client.id] = client + } + const plugins = {} + for (const plugin of pluginList) { + plugins[plugin.id] = plugin + } + this.setState({ instances, clients, plugins }) + } + + renderList(field, type) { + return Object.values(this.state[field + "s"]).map(entry => + React.createElement(type, { key: entry.id, [field]: entry })) + } + + renderView(field, type, id) { + const entry = this.state[field + "s"][id] + if (!entry) { + return "Not found :(" + } + return React.createElement(type, { [field]: entry }) + } + + render() { + return
+
+ + Maubot Manager +
+
+ {localStorage.username} +
+ +
+ "Hello, World!"}/> + + this.renderView("instance", InstanceView, match.params.id)}/> + + this.renderView("client", ClientView, match.params.id)}/> + + this.renderView("plugin", PluginView, match.params.id)}/> + }/> +
+
+ } +} + +export default Dashboard diff --git a/maubot/management/frontend/src/dashboard/instance/ListEntry.js b/maubot/management/frontend/src/dashboard/instance/ListEntry.js new file mode 100644 index 0000000..0603e4d --- /dev/null +++ b/maubot/management/frontend/src/dashboard/instance/ListEntry.js @@ -0,0 +1,27 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2018 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import React from "react" +import { Link } from "react-router-dom" +import { ReactComponent as ChevronRight } from "../../res/chevron-right.svg" + +const InstanceListEntry = ({ instance }) => ( + + {instance.id} + + +) + +export default InstanceListEntry diff --git a/maubot/management/frontend/src/dashboard/instance/View.js b/maubot/management/frontend/src/dashboard/instance/View.js new file mode 100644 index 0000000..69bdf9f --- /dev/null +++ b/maubot/management/frontend/src/dashboard/instance/View.js @@ -0,0 +1,24 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2018 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import React, { Component } from "react" + +class InstanceView extends Component { + render() { + return
{this.props.instance.id}
+ } +} + +export default InstanceView diff --git a/maubot/management/frontend/src/dashboard/plugin/ListEntry.js b/maubot/management/frontend/src/dashboard/plugin/ListEntry.js new file mode 100644 index 0000000..6facdbf --- /dev/null +++ b/maubot/management/frontend/src/dashboard/plugin/ListEntry.js @@ -0,0 +1,27 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2018 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import React from "react" +import { Link } from "react-router-dom" +import { ReactComponent as ChevronRight } from "../../res/chevron-right.svg" + +const PluginListEntry = ({ plugin }) => ( + + {plugin.id} + + +) + +export default PluginListEntry diff --git a/maubot/management/frontend/src/dashboard/plugin/View.js b/maubot/management/frontend/src/dashboard/plugin/View.js new file mode 100644 index 0000000..5b8ccbc --- /dev/null +++ b/maubot/management/frontend/src/dashboard/plugin/View.js @@ -0,0 +1,24 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2018 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +import React, { Component } from "react" + +class PluginView extends Component { + render() { + return
{this.props.plugin.id}
+ } +} + +export default PluginView diff --git a/maubot/management/frontend/src/res/chevron-right.svg b/maubot/management/frontend/src/res/chevron-right.svg new file mode 100644 index 0000000..58ee688 --- /dev/null +++ b/maubot/management/frontend/src/res/chevron-right.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/maubot/management/frontend/src/style/base/elements.sass b/maubot/management/frontend/src/style/base/elements.sass index 48fb045..93d10f0 100644 --- a/maubot/management/frontend/src/style/base/elements.sass +++ b/maubot/management/frontend/src/style/base/elements.sass @@ -36,9 +36,9 @@ text-decoration: none =main-color-button() - background-color: $main-color + background-color: $primary &:hover - background-color: $dark-color + background-color: $primary-dark .button +button @@ -92,7 +92,7 @@ resize: vertical &:hover, &:focus - border-color: $main-color + border-color: $primary &:focus border-width: 2px @@ -101,8 +101,8 @@ .input, .textarea +input -=notification($color: $error-color) +=notification($border: $error-dark, $background: transparentize($error-light, 0.5)) padding: 1rem border-radius: .25rem - border: 2px solid $color - background-color: lighten($color, 25%) + border: 2px solid $border + background-color: $background diff --git a/maubot/management/frontend/src/style/base/vars.sass b/maubot/management/frontend/src/style/base/vars.sass index 9dc77dd..6e9a6c3 100644 --- a/maubot/management/frontend/src/style/base/vars.sass +++ b/maubot/management/frontend/src/style/base/vars.sass @@ -13,16 +13,18 @@ // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -$main-color: darken(#50D367, 10%) -$dark-color: darken($main-color, 10%) -$light-color: lighten($main-color, 10%) -$alt-color: darken(#47B9D7, 10%) -$dark-alt-color: darken($alt-color, 10%) -$border-color: #CCC -$error-color: #D35067 +$primary: #00C853 +$primary-dark: #009624 +$primary-light: #5EFC82 +$secondary: #00B8D4 +$secondary-dark: #0088A3 +$secondary-light: #62EBFF +$error: #B71C1C +$error-dark: #7F0000 +$error-light: #F05545 + +$border-color: #DDD $text-color: #212121 $background-color: #FAFAFA $inverted-text-color: $background-color $font-stack: sans-serif -$max-width: 42.5rem -$header-height: 3.5rem diff --git a/maubot/management/frontend/src/style/index.sass b/maubot/management/frontend/src/style/index.sass index 8486157..c2e9a16 100644 --- a/maubot/management/frontend/src/style/index.sass +++ b/maubot/management/frontend/src/style/index.sass @@ -20,3 +20,4 @@ @import base/elements @import pages/login +@import pages/dashboard diff --git a/maubot/management/frontend/src/style/pages/dashboard-grid.css b/maubot/management/frontend/src/style/pages/dashboard-grid.css new file mode 100644 index 0000000..26906db --- /dev/null +++ b/maubot/management/frontend/src/style/pages/dashboard-grid.css @@ -0,0 +1,6 @@ +.dashboard { + grid-template: + [row1-start] "title topbar" 3.5rem [row1-end] + [row2-start] "sidebar main" auto [row2-end] + / 15rem auto; +} diff --git a/maubot/management/frontend/src/style/pages/dashboard.sass b/maubot/management/frontend/src/style/pages/dashboard.sass new file mode 100644 index 0000000..4be4111 --- /dev/null +++ b/maubot/management/frontend/src/style/pages/dashboard.sass @@ -0,0 +1,57 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2018 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +@import "dashboard-grid" + +.dashboard + display: grid + height: 100% + + > .title + grid-area: title + display: flex + align-items: center + justify-content: center + + font-size: 1.35rem + font-weight: bold + + color: $text-color + + z-index: 1 + + background-color: $background-color + border-right: 1px solid $primary + border-bottom: 1px solid $border-color + + > img + max-width: 2rem + margin-right: .5rem + + > .topbar + grid-area: topbar + display: flex + align-items: center + justify-content: center + background-color: $primary + width: 110% + margin: 0 -5% + box-shadow: 0 .25rem .25rem rgba(0, 0, 0, .25) + + + @import "sidebar" + + > .dashboard + grid-area: main diff --git a/maubot/management/frontend/src/style/pages/login.sass b/maubot/management/frontend/src/style/pages/login.sass index 62b0891..6447f54 100644 --- a/maubot/management/frontend/src/style/pages/login.sass +++ b/maubot/management/frontend/src/style/pages/login.sass @@ -15,7 +15,7 @@ // along with this program. If not, see . .maubot-wrapper:not(.authenticated) - background-color: $main-color + background-color: $primary text-align: center @@ -29,7 +29,7 @@ margin-top: 3rem h1 - color: $main-color + color: $primary margin: 3rem 0 input, button @@ -53,5 +53,5 @@ height: 26.5rem .error - +notification($error-color) + +notification($error) margin: .5rem 2.5rem diff --git a/maubot/management/frontend/src/style/pages/sidebar.sass b/maubot/management/frontend/src/style/pages/sidebar.sass new file mode 100644 index 0000000..a96a2cd --- /dev/null +++ b/maubot/management/frontend/src/style/pages/sidebar.sass @@ -0,0 +1,53 @@ +// maubot - A plugin-based Matrix bot system. +// Copyright (C) 2018 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +> .sidebar + grid-area: sidebar + background-color: $background-color + + border-right: 1px solid $border-color + padding: .5rem + + div.list + margin-bottom: 1.5rem + + h3.title + margin: 0 + + a.entry + display: block + color: $text-color + text-decoration: none + + &:not(:hover) > svg + display: none + + > svg + float: right + + padding: .25rem + + &.client + padding: .25rem + + img.avatar + max-height: 1.5rem + border-radius: 100% + vertical-align: middle + + span.displayname + margin-left: .25rem + vertical-align: middle