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
}
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.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
+ }
+}
+
+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