mirror of
https://github.com/flarum/core.git
synced 2025-07-17 23:01:17 +02:00
Basic implementation of dashboard widgets, statistics
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.
This commit is contained in:
412
framework/core/js/admin/dist/app.js
vendored
412
framework/core/js/admin/dist/app.js
vendored
@@ -18358,15 +18358,19 @@ System.register('flarum/components/Checkbox', ['flarum/Component', 'flarum/compo
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
});;
|
});;
|
||||||
"use strict";
|
'use strict';
|
||||||
|
|
||||||
System.register("flarum/components/DashboardPage", ["flarum/components/Page"], function (_export, _context) {
|
System.register('flarum/components/DashboardPage', ['flarum/components/Page', 'flarum/components/StatusWidget', 'flarum/components/StatisticsWidget'], function (_export, _context) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
var Page, DashboardPage;
|
var Page, StatusWidget, StatisticsWidget, DashboardPage;
|
||||||
return {
|
return {
|
||||||
setters: [function (_flarumComponentsPage) {
|
setters: [function (_flarumComponentsPage) {
|
||||||
Page = _flarumComponentsPage.default;
|
Page = _flarumComponentsPage.default;
|
||||||
|
}, function (_flarumComponentsStatusWidget) {
|
||||||
|
StatusWidget = _flarumComponentsStatusWidget.default;
|
||||||
|
}, function (_flarumComponentsStatisticsWidget) {
|
||||||
|
StatisticsWidget = _flarumComponentsStatisticsWidget.default;
|
||||||
}],
|
}],
|
||||||
execute: function () {
|
execute: function () {
|
||||||
DashboardPage = function (_Page) {
|
DashboardPage = function (_Page) {
|
||||||
@@ -18378,62 +18382,16 @@ System.register("flarum/components/DashboardPage", ["flarum/components/Page"], f
|
|||||||
}
|
}
|
||||||
|
|
||||||
babelHelpers.createClass(DashboardPage, [{
|
babelHelpers.createClass(DashboardPage, [{
|
||||||
key: "view",
|
key: 'view',
|
||||||
value: function view() {
|
value: function view() {
|
||||||
return m(
|
return m(
|
||||||
"div",
|
'div',
|
||||||
{ className: "DashboardPage" },
|
{ className: 'DashboardPage' },
|
||||||
m(
|
m(
|
||||||
"div",
|
'div',
|
||||||
{ className: "container" },
|
{ className: 'container' },
|
||||||
m(
|
m(StatusWidget, null),
|
||||||
"h2",
|
m(StatisticsWidget, null)
|
||||||
null,
|
|
||||||
app.translator.trans('core.admin.dashboard.welcome_text')
|
|
||||||
),
|
|
||||||
m(
|
|
||||||
"p",
|
|
||||||
null,
|
|
||||||
app.translator.trans('core.admin.dashboard.version_text', { version: m(
|
|
||||||
"strong",
|
|
||||||
null,
|
|
||||||
app.forum.attribute('version')
|
|
||||||
) })
|
|
||||||
),
|
|
||||||
m(
|
|
||||||
"p",
|
|
||||||
null,
|
|
||||||
app.translator.trans('core.admin.dashboard.beta_warning_text', { strong: m("strong", null) })
|
|
||||||
),
|
|
||||||
m(
|
|
||||||
"ul",
|
|
||||||
null,
|
|
||||||
m(
|
|
||||||
"li",
|
|
||||||
null,
|
|
||||||
app.translator.trans('core.admin.dashboard.contributing_text', { a: m("a", { href: "http://flarum.org/docs/contributing", target: "_blank" }) })
|
|
||||||
),
|
|
||||||
m(
|
|
||||||
"li",
|
|
||||||
null,
|
|
||||||
app.translator.trans('core.admin.dashboard.troubleshooting_text', { a: m("a", { href: "http://flarum.org/docs/troubleshooting", target: "_blank" }) })
|
|
||||||
),
|
|
||||||
m(
|
|
||||||
"li",
|
|
||||||
null,
|
|
||||||
app.translator.trans('core.admin.dashboard.support_text', { a: m("a", { href: "http://discuss.flarum.org/t/support", target: "_blank" }) })
|
|
||||||
),
|
|
||||||
m(
|
|
||||||
"li",
|
|
||||||
null,
|
|
||||||
app.translator.trans('core.admin.dashboard.features_text', { a: m("a", { href: "http://discuss.flarum.org/t/features", target: "_blank" }) })
|
|
||||||
),
|
|
||||||
m(
|
|
||||||
"li",
|
|
||||||
null,
|
|
||||||
app.translator.trans('core.admin.dashboard.extension_text', { a: m("a", { href: "http://flarum.org/docs/extend", target: "_blank" }) })
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -18441,7 +18399,53 @@ System.register("flarum/components/DashboardPage", ["flarum/components/Page"], f
|
|||||||
return DashboardPage;
|
return DashboardPage;
|
||||||
}(Page);
|
}(Page);
|
||||||
|
|
||||||
_export("default", DashboardPage);
|
_export('default', DashboardPage);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});;
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register('flarum/components/DashboardWidget', ['flarum/Component'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var Component, Widget;
|
||||||
|
return {
|
||||||
|
setters: [function (_flarumComponent) {
|
||||||
|
Component = _flarumComponent.default;
|
||||||
|
}],
|
||||||
|
execute: function () {
|
||||||
|
Widget = function (_Component) {
|
||||||
|
babelHelpers.inherits(Widget, _Component);
|
||||||
|
|
||||||
|
function Widget() {
|
||||||
|
babelHelpers.classCallCheck(this, Widget);
|
||||||
|
return babelHelpers.possibleConstructorReturn(this, (Widget.__proto__ || Object.getPrototypeOf(Widget)).apply(this, arguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
babelHelpers.createClass(Widget, [{
|
||||||
|
key: 'view',
|
||||||
|
value: function view() {
|
||||||
|
return m(
|
||||||
|
'div',
|
||||||
|
{ className: "Widget " + this.className() },
|
||||||
|
this.content()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'className',
|
||||||
|
value: function className() {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'content',
|
||||||
|
value: function content() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
return Widget;
|
||||||
|
}(Component);
|
||||||
|
|
||||||
|
_export('default', Widget);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
});;
|
});;
|
||||||
@@ -21108,6 +21112,254 @@ System.register('flarum/components/SplitDropdown', ['flarum/components/Dropdown'
|
|||||||
});;
|
});;
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
System.register('flarum/components/StatisticsWidget', ['flarum/components/DashboardWidget', 'flarum/helpers/icon', 'flarum/helpers/listItems', 'flarum/utils/ItemList'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var DashboardWidget, icon, listItems, ItemList, StatisticsWidget;
|
||||||
|
return {
|
||||||
|
setters: [function (_flarumComponentsDashboardWidget) {
|
||||||
|
DashboardWidget = _flarumComponentsDashboardWidget.default;
|
||||||
|
}, function (_flarumHelpersIcon) {
|
||||||
|
icon = _flarumHelpersIcon.default;
|
||||||
|
}, function (_flarumHelpersListItems) {
|
||||||
|
listItems = _flarumHelpersListItems.default;
|
||||||
|
}, function (_flarumUtilsItemList) {
|
||||||
|
ItemList = _flarumUtilsItemList.default;
|
||||||
|
}],
|
||||||
|
execute: function () {
|
||||||
|
StatisticsWidget = function (_DashboardWidget) {
|
||||||
|
babelHelpers.inherits(StatisticsWidget, _DashboardWidget);
|
||||||
|
|
||||||
|
function StatisticsWidget() {
|
||||||
|
babelHelpers.classCallCheck(this, StatisticsWidget);
|
||||||
|
return babelHelpers.possibleConstructorReturn(this, (StatisticsWidget.__proto__ || Object.getPrototypeOf(StatisticsWidget)).apply(this, arguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
babelHelpers.createClass(StatisticsWidget, [{
|
||||||
|
key: 'className',
|
||||||
|
value: function className() {
|
||||||
|
return 'StatisticsWidget';
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'content',
|
||||||
|
value: function content() {
|
||||||
|
return m(
|
||||||
|
'table',
|
||||||
|
null,
|
||||||
|
m(
|
||||||
|
'thead',
|
||||||
|
null,
|
||||||
|
m(
|
||||||
|
'tr',
|
||||||
|
null,
|
||||||
|
m('th', null),
|
||||||
|
m(
|
||||||
|
'th',
|
||||||
|
null,
|
||||||
|
app.translator.trans('core.admin.statistics.users_heading')
|
||||||
|
),
|
||||||
|
m(
|
||||||
|
'th',
|
||||||
|
null,
|
||||||
|
app.translator.trans('core.admin.statistics.discussions_heading')
|
||||||
|
),
|
||||||
|
m(
|
||||||
|
'th',
|
||||||
|
null,
|
||||||
|
app.translator.trans('core.admin.statistics.posts_heading')
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
m(
|
||||||
|
'tbody',
|
||||||
|
null,
|
||||||
|
m(
|
||||||
|
'tr',
|
||||||
|
{ className: 'StatisticsWidget-total' },
|
||||||
|
m(
|
||||||
|
'th',
|
||||||
|
null,
|
||||||
|
app.translator.trans('core.admin.statistics.total_label')
|
||||||
|
),
|
||||||
|
m(
|
||||||
|
'td',
|
||||||
|
null,
|
||||||
|
app.data.statistics.total.users
|
||||||
|
),
|
||||||
|
m(
|
||||||
|
'td',
|
||||||
|
null,
|
||||||
|
app.data.statistics.total.discussions
|
||||||
|
),
|
||||||
|
m(
|
||||||
|
'td',
|
||||||
|
null,
|
||||||
|
app.data.statistics.total.posts
|
||||||
|
)
|
||||||
|
),
|
||||||
|
m(
|
||||||
|
'tr',
|
||||||
|
null,
|
||||||
|
m(
|
||||||
|
'th',
|
||||||
|
null,
|
||||||
|
app.translator.trans('core.admin.statistics.last_28_days_label')
|
||||||
|
),
|
||||||
|
m(
|
||||||
|
'td',
|
||||||
|
null,
|
||||||
|
app.data.statistics.month.users
|
||||||
|
),
|
||||||
|
m(
|
||||||
|
'td',
|
||||||
|
null,
|
||||||
|
app.data.statistics.month.discussions
|
||||||
|
),
|
||||||
|
m(
|
||||||
|
'td',
|
||||||
|
null,
|
||||||
|
app.data.statistics.month.posts
|
||||||
|
)
|
||||||
|
),
|
||||||
|
m(
|
||||||
|
'tr',
|
||||||
|
null,
|
||||||
|
m(
|
||||||
|
'th',
|
||||||
|
null,
|
||||||
|
app.translator.trans('core.admin.statistics.last_7_days_label')
|
||||||
|
),
|
||||||
|
m(
|
||||||
|
'td',
|
||||||
|
null,
|
||||||
|
app.data.statistics.week.users
|
||||||
|
),
|
||||||
|
m(
|
||||||
|
'td',
|
||||||
|
null,
|
||||||
|
app.data.statistics.week.discussions
|
||||||
|
),
|
||||||
|
m(
|
||||||
|
'td',
|
||||||
|
null,
|
||||||
|
app.data.statistics.week.posts
|
||||||
|
)
|
||||||
|
),
|
||||||
|
m(
|
||||||
|
'tr',
|
||||||
|
null,
|
||||||
|
m(
|
||||||
|
'th',
|
||||||
|
null,
|
||||||
|
app.translator.trans('core.admin.statistics.today_label')
|
||||||
|
),
|
||||||
|
m(
|
||||||
|
'td',
|
||||||
|
null,
|
||||||
|
app.data.statistics.today.users
|
||||||
|
),
|
||||||
|
m(
|
||||||
|
'td',
|
||||||
|
null,
|
||||||
|
app.data.statistics.today.discussions
|
||||||
|
),
|
||||||
|
m(
|
||||||
|
'td',
|
||||||
|
null,
|
||||||
|
app.data.statistics.today.posts
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
return StatisticsWidget;
|
||||||
|
}(DashboardWidget);
|
||||||
|
|
||||||
|
_export('default', StatisticsWidget);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});;
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register('flarum/components/StatusWidget', ['flarum/components/DashboardWidget', 'flarum/helpers/icon', 'flarum/helpers/listItems', 'flarum/utils/ItemList'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var DashboardWidget, icon, listItems, ItemList, StatusWidget;
|
||||||
|
return {
|
||||||
|
setters: [function (_flarumComponentsDashboardWidget) {
|
||||||
|
DashboardWidget = _flarumComponentsDashboardWidget.default;
|
||||||
|
}, function (_flarumHelpersIcon) {
|
||||||
|
icon = _flarumHelpersIcon.default;
|
||||||
|
}, function (_flarumHelpersListItems) {
|
||||||
|
listItems = _flarumHelpersListItems.default;
|
||||||
|
}, function (_flarumUtilsItemList) {
|
||||||
|
ItemList = _flarumUtilsItemList.default;
|
||||||
|
}],
|
||||||
|
execute: function () {
|
||||||
|
StatusWidget = function (_DashboardWidget) {
|
||||||
|
babelHelpers.inherits(StatusWidget, _DashboardWidget);
|
||||||
|
|
||||||
|
function StatusWidget() {
|
||||||
|
babelHelpers.classCallCheck(this, StatusWidget);
|
||||||
|
return babelHelpers.possibleConstructorReturn(this, (StatusWidget.__proto__ || Object.getPrototypeOf(StatusWidget)).apply(this, arguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
babelHelpers.createClass(StatusWidget, [{
|
||||||
|
key: 'className',
|
||||||
|
value: function className() {
|
||||||
|
return 'StatusWidget';
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'content',
|
||||||
|
value: function content() {
|
||||||
|
return m(
|
||||||
|
'ul',
|
||||||
|
null,
|
||||||
|
listItems(this.items().toArray())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'items',
|
||||||
|
value: function items() {
|
||||||
|
var items = new ItemList();
|
||||||
|
|
||||||
|
items.add('help', m(
|
||||||
|
'a',
|
||||||
|
{ href: 'http://flarum.org/docs/troubleshooting', target: '_blank' },
|
||||||
|
icon('question-circle'),
|
||||||
|
' ',
|
||||||
|
app.translator.trans('core.admin.dashboard.help_link')
|
||||||
|
));
|
||||||
|
|
||||||
|
items.add('version-flarum', [m(
|
||||||
|
'strong',
|
||||||
|
null,
|
||||||
|
'Flarum'
|
||||||
|
), m('br', null), app.forum.attribute('version')]);
|
||||||
|
items.add('version-php', [m(
|
||||||
|
'strong',
|
||||||
|
null,
|
||||||
|
'PHP'
|
||||||
|
), m('br', null), app.data.phpVersion]);
|
||||||
|
items.add('version-mysql', [m(
|
||||||
|
'strong',
|
||||||
|
null,
|
||||||
|
'MySQL'
|
||||||
|
), m('br', null), app.data.mysqlVersion]);
|
||||||
|
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
return StatusWidget;
|
||||||
|
}(DashboardWidget);
|
||||||
|
|
||||||
|
_export('default', StatusWidget);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});;
|
||||||
|
'use strict';
|
||||||
|
|
||||||
System.register('flarum/components/Switch', ['flarum/components/Checkbox'], function (_export, _context) {
|
System.register('flarum/components/Switch', ['flarum/components/Checkbox'], function (_export, _context) {
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
@@ -21261,6 +21513,52 @@ System.register('flarum/components/UploadImageButton', ['flarum/components/Butto
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
});;
|
});;
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
System.register('flarum/components/Widget', ['flarum/Component'], function (_export, _context) {
|
||||||
|
"use strict";
|
||||||
|
|
||||||
|
var Component, DashboardWidget;
|
||||||
|
return {
|
||||||
|
setters: [function (_flarumComponent) {
|
||||||
|
Component = _flarumComponent.default;
|
||||||
|
}],
|
||||||
|
execute: function () {
|
||||||
|
DashboardWidget = function (_Component) {
|
||||||
|
babelHelpers.inherits(DashboardWidget, _Component);
|
||||||
|
|
||||||
|
function DashboardWidget() {
|
||||||
|
babelHelpers.classCallCheck(this, DashboardWidget);
|
||||||
|
return babelHelpers.possibleConstructorReturn(this, (DashboardWidget.__proto__ || Object.getPrototypeOf(DashboardWidget)).apply(this, arguments));
|
||||||
|
}
|
||||||
|
|
||||||
|
babelHelpers.createClass(DashboardWidget, [{
|
||||||
|
key: 'view',
|
||||||
|
value: function view() {
|
||||||
|
return m(
|
||||||
|
'div',
|
||||||
|
{ className: "DashboardWidget " + this.className() },
|
||||||
|
this.content()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'className',
|
||||||
|
value: function className() {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
key: 'content',
|
||||||
|
value: function content() {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}]);
|
||||||
|
return DashboardWidget;
|
||||||
|
}(Component);
|
||||||
|
|
||||||
|
_export('default', DashboardWidget);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
});;
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
System.register("flarum/extend", [], function (_export, _context) {
|
System.register("flarum/extend", [], function (_export, _context) {
|
||||||
|
@@ -1,20 +1,14 @@
|
|||||||
import Page from 'flarum/components/Page';
|
import Page from 'flarum/components/Page';
|
||||||
|
import StatusWidget from 'flarum/components/StatusWidget';
|
||||||
|
import StatisticsWidget from 'flarum/components/StatisticsWidget';
|
||||||
|
|
||||||
export default class DashboardPage extends Page {
|
export default class DashboardPage extends Page {
|
||||||
view() {
|
view() {
|
||||||
return (
|
return (
|
||||||
<div className="DashboardPage">
|
<div className="DashboardPage">
|
||||||
<div className="container">
|
<div className="container">
|
||||||
<h2>{app.translator.trans('core.admin.dashboard.welcome_text')}</h2>
|
<StatusWidget/>
|
||||||
<p>{app.translator.trans('core.admin.dashboard.version_text', {version: <strong>{app.forum.attribute('version')}</strong>})}</p>
|
<StatisticsWidget/>
|
||||||
<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>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
38
framework/core/js/admin/src/components/DashboardWidget.js
Normal file
38
framework/core/js/admin/src/components/DashboardWidget.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Flarum.
|
||||||
|
*
|
||||||
|
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||||
|
*
|
||||||
|
* 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
framework/core/js/admin/src/components/StatisticsWidget.js
Normal file
60
framework/core/js/admin/src/components/StatisticsWidget.js
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Flarum.
|
||||||
|
*
|
||||||
|
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||||
|
*
|
||||||
|
* 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
framework/core/js/admin/src/components/StatusWidget.js
Normal file
41
framework/core/js/admin/src/components/StatusWidget.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Flarum.
|
||||||
|
*
|
||||||
|
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||||
|
*
|
||||||
|
* 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
framework/core/js/admin/src/components/Widget.js
Normal file
38
framework/core/js/admin/src/components/Widget.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of Flarum.
|
||||||
|
*
|
||||||
|
* (c) Toby Zerner <toby.zerner@gmail.com>
|
||||||
|
*
|
||||||
|
* 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 [];
|
||||||
|
}
|
||||||
|
}
|
@@ -2,20 +2,81 @@
|
|||||||
background: @control-bg;
|
background: @control-bg;
|
||||||
color: @control-color;
|
color: @control-color;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
font-size: 14px;
|
|
||||||
line-height: 1.7;
|
|
||||||
|
|
||||||
@media @desktop-up {
|
@media @desktop-up {
|
||||||
.container {
|
.container {
|
||||||
max-width: 600px;
|
|
||||||
padding: 30px;
|
padding: 30px;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
h2 {
|
.Widget {
|
||||||
font-size: 26px;
|
background: @body-bg;
|
||||||
font-weight: 300;
|
color: @text-color;
|
||||||
margin-top: 0;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -11,13 +11,18 @@
|
|||||||
|
|
||||||
namespace Flarum\Admin\Controller;
|
namespace Flarum\Admin\Controller;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
use Flarum\Admin\WebApp;
|
use Flarum\Admin\WebApp;
|
||||||
|
use Flarum\Core\Discussion;
|
||||||
use Flarum\Core\Permission;
|
use Flarum\Core\Permission;
|
||||||
|
use Flarum\Core\Post;
|
||||||
|
use Flarum\Core\User;
|
||||||
use Flarum\Event\PrepareUnserializedSettings;
|
use Flarum\Event\PrepareUnserializedSettings;
|
||||||
use Flarum\Extension\ExtensionManager;
|
use Flarum\Extension\ExtensionManager;
|
||||||
use Flarum\Http\Controller\AbstractWebAppController;
|
use Flarum\Http\Controller\AbstractWebAppController;
|
||||||
use Flarum\Settings\SettingsRepositoryInterface;
|
use Flarum\Settings\SettingsRepositoryInterface;
|
||||||
use Illuminate\Contracts\Events\Dispatcher;
|
use Illuminate\Contracts\Events\Dispatcher;
|
||||||
|
use Illuminate\Database\ConnectionInterface;
|
||||||
use Psr\Http\Message\ServerRequestInterface;
|
use Psr\Http\Message\ServerRequestInterface;
|
||||||
|
|
||||||
class WebAppController extends AbstractWebAppController
|
class WebAppController extends AbstractWebAppController
|
||||||
@@ -37,13 +42,15 @@ class WebAppController extends AbstractWebAppController
|
|||||||
* @param Dispatcher $events
|
* @param Dispatcher $events
|
||||||
* @param SettingsRepositoryInterface $settings
|
* @param SettingsRepositoryInterface $settings
|
||||||
* @param ExtensionManager $extensions
|
* @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->webApp = $webApp;
|
||||||
$this->events = $events;
|
$this->events = $events;
|
||||||
$this->settings = $settings;
|
$this->settings = $settings;
|
||||||
$this->extensions = $extensions;
|
$this->extensions = $extensions;
|
||||||
|
$this->db = $db;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -63,6 +70,40 @@ class WebAppController extends AbstractWebAppController
|
|||||||
$view->setVariable('permissions', Permission::map());
|
$view->setVariable('permissions', Permission::map());
|
||||||
$view->setVariable('extensions', $this->extensions->getExtensions()->toArray());
|
$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;
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user