Skip to content

Commit

Permalink
Basic implementation of dashboard widgets, statistics
Browse files Browse the repository at this point in the history
Currently not user-customizable. Just needed to display statistics for a
client, so figured I'd make a start at this. Nothing too fancy for now,
but I'm sure some people will be happy to have this information at their
fingertips.
  • Loading branch information
tobyzerner committed Nov 29, 2017
1 parent 79fee36 commit 1ef9217
Show file tree
Hide file tree
Showing 8 changed files with 646 additions and 75 deletions.
412 changes: 355 additions & 57 deletions js/admin/dist/app.js

Large diffs are not rendered by default.

14 changes: 4 additions & 10 deletions js/admin/src/components/DashboardPage.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
import Page from 'flarum/components/Page';
import StatusWidget from 'flarum/components/StatusWidget';
import StatisticsWidget from 'flarum/components/StatisticsWidget';

export default class DashboardPage extends Page {
view() {
return (
<div className="DashboardPage">
<div className="container">
<h2>{app.translator.trans('core.admin.dashboard.welcome_text')}</h2>
<p>{app.translator.trans('core.admin.dashboard.version_text', {version: <strong>{app.forum.attribute('version')}</strong>})}</p>
<p>{app.translator.trans('core.admin.dashboard.beta_warning_text', {strong: <strong/>})}</p>
<ul>
<li>{app.translator.trans('core.admin.dashboard.contributing_text', {a: <a href="http://flarum.org/docs/contributing" target="_blank"/>})}</li>
<li>{app.translator.trans('core.admin.dashboard.troubleshooting_text', {a: <a href="http://flarum.org/docs/troubleshooting" target="_blank"/>})}</li>
<li>{app.translator.trans('core.admin.dashboard.support_text', {a: <a href="http://discuss.flarum.org/t/support" target="_blank"/>})}</li>
<li>{app.translator.trans('core.admin.dashboard.features_text', {a: <a href="http://discuss.flarum.org/t/features" target="_blank"/>})}</li>
<li>{app.translator.trans('core.admin.dashboard.extension_text', {a: <a href="http://flarum.org/docs/extend" target="_blank"/>})}</li>
</ul>
<StatusWidget/>
<StatisticsWidget/>
</div>
</div>
);
Expand Down
38 changes: 38 additions & 0 deletions js/admin/src/components/DashboardWidget.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import Component from 'flarum/Component';

export default class Widget extends Component {
view() {
return (
<div className={"Widget "+this.className()}>
{this.content()}
</div>
);
}

/**
* Get the class name to apply to the widget.
*
* @return {String}
*/
className() {
return '';
}

/**
* Get the content of the widget.
*
* @return {VirtualElement}
*/
content() {
return [];
}
}
60 changes: 60 additions & 0 deletions js/admin/src/components/StatisticsWidget.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import DashboardWidget from 'flarum/components/DashboardWidget';
import icon from 'flarum/helpers/icon';
import listItems from 'flarum/helpers/listItems';
import ItemList from 'flarum/utils/ItemList';

export default class StatisticsWidget extends DashboardWidget {
className() {
return 'StatisticsWidget';
}

content() {
return (
<table>
<thead>
<tr>
<th></th>
<th>{app.translator.trans('core.admin.statistics.users_heading')}</th>
<th>{app.translator.trans('core.admin.statistics.discussions_heading')}</th>
<th>{app.translator.trans('core.admin.statistics.posts_heading')}</th>
</tr>
</thead>
<tbody>
<tr className="StatisticsWidget-total">
<th>{app.translator.trans('core.admin.statistics.total_label')}</th>
<td>{app.data.statistics.total.users}</td>
<td>{app.data.statistics.total.discussions}</td>
<td>{app.data.statistics.total.posts}</td>
</tr>
<tr>
<th>{app.translator.trans('core.admin.statistics.last_28_days_label')}</th>
<td>{app.data.statistics.month.users}</td>
<td>{app.data.statistics.month.discussions}</td>
<td>{app.data.statistics.month.posts}</td>
</tr>
<tr>
<th>{app.translator.trans('core.admin.statistics.last_7_days_label')}</th>
<td>{app.data.statistics.week.users}</td>
<td>{app.data.statistics.week.discussions}</td>
<td>{app.data.statistics.week.posts}</td>
</tr>
<tr>
<th>{app.translator.trans('core.admin.statistics.today_label')}</th>
<td>{app.data.statistics.today.users}</td>
<td>{app.data.statistics.today.discussions}</td>
<td>{app.data.statistics.today.posts}</td>
</tr>
</tbody>
</table>
);
}
}
41 changes: 41 additions & 0 deletions js/admin/src/components/StatusWidget.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import DashboardWidget from 'flarum/components/DashboardWidget';
import icon from 'flarum/helpers/icon';
import listItems from 'flarum/helpers/listItems';
import ItemList from 'flarum/utils/ItemList';

export default class StatusWidget extends DashboardWidget {
className() {
return 'StatusWidget';
}

content() {
return (
<ul>{listItems(this.items().toArray())}</ul>
);
}

items() {
const items = new ItemList();

items.add('help', (
<a href="http://flarum.org/docs/troubleshooting" target="_blank">
{icon('question-circle')} {app.translator.trans('core.admin.dashboard.help_link')}
</a>
));

items.add('version-flarum', [<strong>Flarum</strong>, <br/>, app.forum.attribute('version')]);
items.add('version-php', [<strong>PHP</strong>, <br/>, app.data.phpVersion]);
items.add('version-mysql', [<strong>MySQL</strong>, <br/>, app.data.mysqlVersion]);

return items;
}
}
38 changes: 38 additions & 0 deletions js/admin/src/components/Widget.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* This file is part of Flarum.
*
* (c) Toby Zerner <[email protected]>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import Component from 'flarum/Component';

export default class DashboardWidget extends Component {
view() {
return (
<div className={"DashboardWidget "+this.className()}>
{this.content()}
</div>
);
}

/**
* Get the class name to apply to the widget.
*
* @return {String}
*/
className() {
return '';
}

/**
* Get the content of the widget.
*
* @return {VirtualElement}
*/
content() {
return [];
}
}
75 changes: 68 additions & 7 deletions less/admin/DashboardPage.less
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,81 @@
background: @control-bg;
color: @control-color;
min-height: 100vh;
font-size: 14px;
line-height: 1.7;

@media @desktop-up {
.container {
max-width: 600px;
padding: 30px;
margin: 0;
}
}
}

.Widget {
background: @body-bg;
color: @text-color;
border-radius: @border-radius;
padding: 20px;
margin-bottom: 20px;
}

.StatusWidget {
color: @muted-color;

> ul {
margin: 0;
padding: 0;
list-style-type: none;

> li {
display: inline-block;
margin-right: 30px;
vertical-align: middle;

&[class^="item-version-"] {
max-width: 100px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
&.item-help {
float: right;
margin-right: 0;
}
}
}
}

h2 {
font-size: 26px;
font-weight: 300;
margin-top: 0;
.StatisticsWidget {
td {
font-size: 14px;
}
td, th {
padding: 5px 20px 5px 0;
text-align: left;
font-weight: normal;
border-bottom: 1px solid @control-bg;
}
tbody tr:last-child {
td, th {
border-bottom: 0;
}
}
th {
color: @muted-color;
}
thead th {
font-weight: bold;
}
}
.StatisticsWidget-total {
td, th {
font-weight: bold;
}
}
@media @tablet-up {
.StatisticsWidget {
td, th {
min-width: 120px;
}
}
}
43 changes: 42 additions & 1 deletion src/Admin/Controller/WebAppController.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,18 @@

namespace Flarum\Admin\Controller;

use DateTime;
use Flarum\Admin\WebApp;
use Flarum\Core\Discussion;
use Flarum\Core\Permission;
use Flarum\Core\Post;
use Flarum\Core\User;
use Flarum\Event\PrepareUnserializedSettings;
use Flarum\Extension\ExtensionManager;
use Flarum\Http\Controller\AbstractWebAppController;
use Flarum\Settings\SettingsRepositoryInterface;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Database\ConnectionInterface;
use Psr\Http\Message\ServerRequestInterface;

class WebAppController extends AbstractWebAppController
Expand All @@ -37,13 +42,15 @@ class WebAppController extends AbstractWebAppController
* @param Dispatcher $events
* @param SettingsRepositoryInterface $settings
* @param ExtensionManager $extensions
* @param ConnectionInterface $db
*/
public function __construct(WebApp $webApp, Dispatcher $events, SettingsRepositoryInterface $settings, ExtensionManager $extensions)
public function __construct(WebApp $webApp, Dispatcher $events, SettingsRepositoryInterface $settings, ExtensionManager $extensions, ConnectionInterface $db)
{
$this->webApp = $webApp;
$this->events = $events;
$this->settings = $settings;
$this->extensions = $extensions;
$this->db = $db;
}

/**
Expand All @@ -63,6 +70,40 @@ protected function getView(ServerRequestInterface $request)
$view->setVariable('permissions', Permission::map());
$view->setVariable('extensions', $this->extensions->getExtensions()->toArray());

$view->setVariable('phpVersion', PHP_VERSION);
$view->setVariable('mysqlVersion', $this->db->selectOne('select version() as version')->version);

$view->setVariable('statistics', $this->getStatistics());

return $view;
}

private function getStatistics()
{
return [
'total' => $this->getEntityCounts(),
'month' => $this->getEntityCounts(new DateTime('-28 days')),
'week' => $this->getEntityCounts(new DateTime('-7 days')),
'today' => $this->getEntityCounts(new DateTime('-1 day'))
];
}

private function getEntityCounts($since = null)
{
$queries = [
'users' => User::query(),
'discussions' => Discussion::query(),
'posts' => Post::where('type', 'comment')
];

if ($since) {
$queries['users']->where('join_time', '>', $since);
$queries['discussions']->where('start_time', '>', $since);
$queries['posts']->where('time', '>', $since);
}

return array_map(function ($query) {
return $query->count();
}, $queries);
}
}

0 comments on commit 1ef9217

Please sign in to comment.