graph changes

This commit is contained in:
Barış Soner Uşaklı
2026-02-27 14:14:02 -05:00
parent 415602d89e
commit ecc740aa25
8 changed files with 79 additions and 67 deletions

View File

@@ -11,6 +11,8 @@ get:
allOf:
- type: object
properties:
graphTitle:
type: string
version:
type: string
lookupFailed:

View File

@@ -11,6 +11,8 @@ get:
allOf:
- type: object
properties:
graphTitle:
type: string
set:
type: string
description: The analytics set that is being queried

View File

@@ -11,6 +11,8 @@ get:
allOf:
- type: object
properties:
graphTitle:
type: string
set:
type: string
description: The analytics set that is being queried

View File

@@ -11,6 +11,8 @@ get:
allOf:
- type: object
properties:
graphTitle:
type: string
set:
type: string
description: The analytics set that is being queried

View File

@@ -349,25 +349,26 @@ function setupGraphs(callback) {
updateTrafficGraph();
$('[data-action="updateGraph"]:not([data-units="custom"])').on('click', function () {
$('[data-action="updateGraph"]').on('change', function () {
let amount = $(this).val();
if (amount === 'custom') {
throwCustomRangeSelector($(this));
return;
}
const units = amount === '1' ? 'hours' : 'days';
let until = new Date();
const amount = $(this).attr('data-amount');
if ($(this).attr('data-units') === 'days') {
if (amount !== '1') {
until.setHours(0, 0, 0, 0);
}
if (amount === '1') { // change 1 day to 24 hours
amount = '24';
}
until = until.getTime();
updateTrafficGraph($(this).attr('data-units'), until, amount);
require(['translator'], function (translator) {
translator.translate('[[admin/dashboard:page-views-custom]]', function (translated) {
$('[data-action="updateGraph"][data-units="custom"]').text(translated);
});
});
updateTrafficGraph(units, until, amount);
$('[data-action="updateGraph"] option[value="range"]').addClass('hidden');
});
$('[data-action="updateGraph"][data-units="custom"]').on('click', function () {
const targetEl = $(this);
function throwCustomRangeSelector(targetEl) {
Benchpress.render('admin/partials/pageviews-range-select', {}).then(function (html) {
const modal = bootbox.dialog({
title: '[[admin/dashboard:page-views-custom]]',
@@ -415,10 +416,11 @@ function setupGraphs(callback) {
// Update "custom range" label
targetEl.attr('data-startRange', formData.startRange);
targetEl.attr('data-endRange', formData.endRange);
targetEl.html(formData.startRange + ' – ' + formData.endRange);
targetEl.find('option[value="range"]').text(formData.startRange + ' - ' + formData.endRange);
targetEl.val('range');
}
});
});
}
callback();
});

View File

@@ -83,6 +83,12 @@ export function init({ set, dataset }) {
},
},
},
plugins: {
legend: {
display: false,
position: 'bottom',
},
},
interaction: {
intersect: false,
mode: 'index',
@@ -100,25 +106,26 @@ export function init({ set, dataset }) {
}
function handleUpdateControls({ set }) {
$('[data-action="updateGraph"]:not([data-units="custom"])').on('click', function () {
$('[data-action="updateGraph"]').on('change', function () {
let amount = $(this).val();
if (amount === 'custom') {
throwCustomRangeSelector($(this));
return;
}
const units = amount === '1' ? 'hours' : 'days';
let until = new Date();
const amount = $(this).attr('data-amount');
if ($(this).attr('data-units') === 'days') {
if (amount !== '1') {
until.setHours(0, 0, 0, 0);
}
if (amount === '1') { // change 1 day to 24 hours
amount = '24';
}
until = until.getTime();
update(set, $(this).attr('data-units'), until, amount);
require(['translator'], function (translator) {
translator.translate('[[admin/dashboard:page-views-custom]]', function (translated) {
$('[data-action="updateGraph"][data-units="custom"]').text(translated);
});
});
update(set, units, until, amount);
$('[data-action="updateGraph"] option[value="range"]').addClass('hidden');
});
$('[data-action="updateGraph"][data-units="custom"]').on('click', function () {
const targetEl = $(this);
function throwCustomRangeSelector(targetEl) {
Benchpress.render('admin/partials/pageviews-range-select', {}).then(function (html) {
const modal = bootbox.dialog({
title: '[[admin/dashboard:page-views-custom]]',
@@ -166,10 +173,11 @@ function handleUpdateControls({ set }) {
// Update "custom range" label
targetEl.attr('data-startRange', formData.startRange);
targetEl.attr('data-endRange', formData.endRange);
targetEl.html(formData.startRange + ' – ' + formData.endRange);
targetEl.find('option[value="range"]').text(formData.startRange + ' - ' + formData.endRange);
targetEl.val('range');
}
});
});
}
}
function update(

View File

@@ -32,6 +32,7 @@ dashboardController.get = async function (req, res) {
const latestValidVersion = semver.valid(latestVersion);
res.render('admin/dashboard', {
graphTitle: '[[admin/dashboard:forum-traffic]]',
version: version,
lookupFailed: latestValidVersion === null,
latestVersion: latestValidVersion,
@@ -131,6 +132,7 @@ async function getStats() {
}
let results = (await Promise.all([
getStatsFromAnalytics('pageviews', ''),
getStatsFromAnalytics('uniquevisitors', ''),
getStatsFromAnalytics('logins', 'loginCount'),
getStatsForSet('users:joindate', 'userCount'),
@@ -140,24 +142,25 @@ async function getStats() {
meta.config.activitypubEnabled ? getStatsForSet('topicsRemote:tid', '') : null,
])).filter(Boolean);
results[0].name = '[[admin/dashboard:unique-visitors]]';
results[0].name = '[[admin/dashboard:graphs.page-views]]';
results[1].name = '[[admin/dashboard:unique-visitors]]';
results[1].name = '[[admin/dashboard:logins]]';
results[1].href = `${nconf.get('relative_path')}/admin/dashboard/logins`;
results[2].name = '[[admin/dashboard:logins]]';
results[2].href = `${nconf.get('relative_path')}/admin/dashboard/logins`;
results[2].name = '[[admin/dashboard:new-users]]';
results[2].href = `${nconf.get('relative_path')}/admin/dashboard/users`;
results[3].name = '[[admin/dashboard:new-users]]';
results[3].href = `${nconf.get('relative_path')}/admin/dashboard/users`;
results[3].name = '[[admin/dashboard:posts]]';
results[4].name = '[[admin/dashboard:posts]]';
results[4].name = '[[admin/dashboard:topics]]';
results[4].href = `${nconf.get('relative_path')}/admin/dashboard/topics`;
results[5].name = '[[admin/dashboard:topics]]';
results[5].href = `${nconf.get('relative_path')}/admin/dashboard/topics`;
if (results[5]) {
results[5].name = '[[admin/dashboard:remote-posts]]';
}
if (results[6]) {
results[6].name = '[[admin/dashboard:remote-topics]]';
results[6].name = '[[admin/dashboard:remote-posts]]';
}
if (results[7]) {
results[7].name = '[[admin/dashboard:remote-topics]]';
}
({ results } = await plugins.hooks.fire('filter:admin.getStats', {
@@ -287,6 +290,7 @@ dashboardController.getLogins = async (req, res) => {
sessions = _.flatten(sessions).sort((a, b) => b.datetime - a.datetime);
res.render('admin/dashboard/logins', {
graphTitle: '[[admin/dashboard:logins]]',
set: 'logins',
query: _.pick(req.query, ['units', 'until', 'count']),
stats,
@@ -315,6 +319,7 @@ dashboardController.getUsers = async (req, res) => {
const users = await user.getUsersData(uids);
res.render('admin/dashboard/users', {
graphTitle: '[[admin/dashboard:new-users]]',
set: 'registrations',
query: _.pick(req.query, ['units', 'until', 'count']),
stats,
@@ -342,6 +347,7 @@ dashboardController.getTopics = async (req, res) => {
const topicData = await topics.getTopicsByTids(tids);
res.render('admin/dashboard/topics', {
graphTitle: '[[admin/dashboard:topics]]',
set: 'topics',
query: _.pick(req.query, ['units', 'until', 'count']),
stats,

View File

@@ -1,36 +1,24 @@
<div class="card mb-3" id="analytics-panel">
<div class="card shadow-none mb-3" id="analytics-panel">
<div class="card-header">
<div class="d-flex justify-content-between">
[[admin/dashboard:forum-traffic]]
<div class="d-flex justify-content-between align-items-center">
{graphTitle}
<div class="d-flex gap-1">
<select data-action="updateGraph" class="form-select form-select-sm">
<option value="1">[[admin/dashboard:page-views-last-day]]</option>
<option value="7">[[admin/dashboard:page-views-seven]]</option>
<option value="30">[[admin/dashboard:page-views-thirty]]</option>
<option value="custom">[[admin/dashboard:page-views-custom]]</option>
<option value="range" class="hidden">[[admin/dashboard:page-views-custom]]</option>
</select>
<a class="btn btn-sm btn-light lh-sm" target="_blank" id="view-as-json" href="{config.relative_path}/api/v3/admin/analytics/{set}?type=hourly" data-bs-toggle="tooltip" data-bs-placement="bottom" title="[[admin/dashboard:view-as-json]]"><i class="fa fa-fw fa-xs fa-terminal text-primary"></i></a>
<a class="btn btn-sm btn-light lh-sm" id="expand-analytics" href="#" data-bs-toggle="tooltip" data-bs-placement="bottom" title="[[admin/dashboard:expand-analytics]]"><i class="fa fa-fw fa-xs fa-expand text-primary"></i></a>
</div>
</div>
</div>
<div class="card-body">
<div class="graph-container position-relative" id="analytics-traffic-container" style="height: 40vh; min-height: 300px; ">
<canvas id="analytics-traffic" ></canvas>
</div>
<hr/>
<div class="row">
<div class="col-sm-3 hidden-xs text-center pageview-stats">
<div><strong id="pageViewsThirty">{{{ if summary.month }}}{./summary.month}{{{ else }}}0{{{ end }}}</strong></div>
<div><a href="#" class="updatePageviewsGraph text-sm" data-action="updateGraph" data-units="days" data-amount="30">[[admin/dashboard:page-views-thirty]]</a></div>
</div>
<div class="col-sm-3 text-center pageview-stats">
<div><strong id="pageViewsSeven">{{{ if summary.week }}}{./summary.week}{{{ else }}}0{{{ end }}}</strong></div>
<div><a href="#" class="updatePageviewsGraph text-sm" data-action="updateGraph" data-units="days" data-amount="7">[[admin/dashboard:page-views-seven]]</a></div>
</div>
<div class="col-sm-3 hidden-xs text-center pageview-stats">
<div><strong id="pageViewsPastDay">{{{ if summary.day }}}{./summary.day}{{{ else }}}0{{{ end }}}</strong></div>
<div><a href="#" class="updatePageviewsGraph text-sm" data-action="updateGraph" data-units="hours" data-amount="24">[[admin/dashboard:page-views-last-day]]</a></div>
</div>
<div class="col-sm-3 text-center pageview-stats">
<div><strong><i class="fa fa-clock-o"></i></strong></div>
<div><a href="#" class="updatePageviewsGraph text-sm" data-action="updateGraph" data-units="custom">[[admin/dashboard:page-views-custom]]</a></div>
</div>
<div class="card-body p-0">
<div class="graph-container position-relative" id="analytics-traffic-container" style="width: 100%; {{{ if template.admin/dashboard }}}min-height: 300px;{{{ end }}}">
<canvas id="analytics-traffic"></canvas>
</div>
</div>
</div>