chg: [instance:home] Added support of both `modified` and `created` in stat panels

pull/93/head
Sami Mokaddem 2021-11-12 15:40:03 +01:00
parent 24e5a94662
commit 509b203591
No known key found for this signature in database
GPG Key ID: 164C473F627A06FA
5 changed files with 94 additions and 52 deletions

View File

@ -21,7 +21,6 @@ class InstanceController extends AppController
public function home() public function home()
{ {
// $this->set('md', file_get_contents(ROOT . '/README.md'));
$statistics = $this->Instance->getStatistics(); $statistics = $this->Instance->getStatistics();
$this->set('statistics', $statistics); $this->set('statistics', $statistics);
} }

View File

@ -25,47 +25,64 @@ class InstanceTable extends AppTable
return $validator; return $validator;
} }
public function getStatistics($days=30): array public function getStatistics(int $days=30): array
{ {
$models = ['Individuals', 'Organisations', 'Alignments', 'EncryptionKeys', 'SharingGroups', 'Users', 'Broods', 'Tags.Tags']; $models = ['Individuals', 'Organisations', 'Alignments', 'EncryptionKeys', 'SharingGroups', 'Users', 'Broods', 'Tags.Tags'];
foreach ($models as $model) { foreach ($models as $model) {
$table = TableRegistry::getTableLocator()->get($model); $table = TableRegistry::getTableLocator()->get($model);
$statistics[$model]['amount'] = $table->find()->all()->count(); $statistics[$model]['created'] = $this->getActivityStatistic($table, $days, 'created');
if ($table->behaviors()->has('Timestamp')) { $statistics[$model]['modified'] = $this->getActivityStatistic($table, $days, 'modified');
$query = $table->find();
$query->select([
'count' => $query->func()->count('id'),
'date' => 'DATE(modified)',
])
->where(['modified >' => new \DateTime("-{$days} days")])
->group(['date'])
->order(['date']);
$data = $query->toArray();
$interval = new \DateInterval('P1D');
$period = new \DatePeriod(new \DateTime("-{$days} days"), $interval, new \DateTime());
$timeline = [];
foreach ($period as $date) {
$timeline[$date->format("Y-m-d")] = [
'time' => $date->format("Y-m-d"),
'count' => 0
];
}
foreach ($data as $entry) {
$timeline[$entry->date]['count'] = $entry->count;
}
$statistics[$model]['timeline'] = array_values($timeline);
$startCount = $table->find()->where(['modified <' => new \DateTime("-{$days} days")])->all()->count();
$endCount = $statistics[$model]['amount'];
$statistics[$model]['variation'] = $endCount - $startCount;
} else {
$statistics[$model]['timeline'] = [];
$statistics[$model]['variation'] = 0;
}
} }
return $statistics; return $statistics;
} }
public function getActivityStatistic(Object $table, int $days=30, string $field='modified', bool $includeTimeline=true): array
{
$statistics = [];
$statistics['amount'] = $table->find()->all()->count();
if ($table->behaviors()->has('Timestamp') && $includeTimeline) {
$statistics['timeline'] = $this->buildTimeline($table, $days, $field);
$statistics['variation'] = $table->find()->where(["{$field} >" => new \DateTime("-{$days} days")])->all()->count(); - $statistics['amount'];
} else {
$statistics['timeline'] = [];
$statistics['variation'] = 0;
}
return $statistics;
}
public function buildTimeline(Object $table, int $days=30, string $field='modified'): array
{
$timeline = [];
$authorizedFields = ['modified', 'created'];
if ($table->behaviors()->has('Timestamp')) {
if (!in_array($field, $authorizedFields)) {
throw new MethodNotAllowedException(__('Cannot construct timeline for field `{0}`', $field));
}
$query = $table->find();
$query->select([
'count' => $query->func()->count('id'),
'date' => "DATE({$field})",
])
->where(["{$field} >" => new \DateTime("-{$days} days")])
->group(['date'])
->order(['date']);
$data = $query->toArray();
$interval = new \DateInterval('P1D');
$period = new \DatePeriod(new \DateTime("-{$days} days"), $interval, new \DateTime());
foreach ($period as $date) {
$timeline[$date->format("Y-m-d")] = [
'time' => $date->format("Y-m-d"),
'count' => 0
];
}
foreach ($data as $entry) {
$timeline[$entry->date]['count'] = $entry->count;
}
$timeline = array_values($timeline);
}
return $timeline;
}
public function searchAll($value, $limit=5, $model=null) public function searchAll($value, $limit=5, $model=null)
{ {
$results = []; $results = [];

View File

@ -32,7 +32,7 @@ $bookmarks = !empty($loggedUser->user_settings_by_name['ui.bookmarks']['value'])
<?= __('Activity') ?> <?= __('Activity') ?>
</h3> </h3>
<div class="row"> <div class="row">
<?php foreach ($statistics as $modelName => $statistics) : ?> <?php foreach ($statistics as $modelName => $statisticForModel) : ?>
<div class="col-sm-6 col-md-5 col-l-4 col-xl-3 mb-3"> <div class="col-sm-6 col-md-5 col-l-4 col-xl-3 mb-3">
<?php <?php
$exploded = explode('.', $modelName); $exploded = explode('.', $modelName);
@ -47,9 +47,9 @@ $bookmarks = !empty($loggedUser->user_settings_by_name['ui.bookmarks']['value'])
); );
echo $this->element('widgets/highlight-panel', [ echo $this->element('widgets/highlight-panel', [
'titleHtml' => $panelTitle, 'titleHtml' => $panelTitle,
'number' => $statistics['amount'], 'number' => $statisticForModel['created']['amount'],
'variation' => $statistics['variation'] ?? '', 'variation' => $statisticForModel['created']['variation'] ?? '',
'chartData' => $statistics['timeline'] ?? [] 'timeline' => $statisticForModel ?? []
]); ]);
?> ?>
</div> </div>

View File

@ -1,14 +1,22 @@
<?php <?php
$chartOptions = $chartOptions ?? []; $chartOptions = $chartOptions ?? [];
$chartData = $chartData ?? [];
$seed = mt_rand(); $seed = mt_rand();
$chartId = "chart-{$seed}"; $chartId = "chart-{$seed}";
// Transform the chart data into the expected format $chartData = $chartData ?? [];
$data = []; $chartSeries = [];
foreach ($chartData as $i => $entry) { if (!empty($series)) {
$data[] = $entry['count']; $chartSeries = $series;
} else {
// Transform the chart data into the expected format
$data = [];
foreach ($chartData as $i => $entry) {
$data[] = $entry['count'];
}
$chartSeries = [
['data' => $data]
];
} }
?> ?>
@ -20,7 +28,7 @@ foreach ($chartData as $i => $entry) {
const defaultOptions = { const defaultOptions = {
chart: { chart: {
id: '<?= $chartId ?>', id: '<?= $chartId ?>',
type: 'bar', type: 'line',
sparkline: { sparkline: {
enabled: true enabled: true
}, },
@ -35,10 +43,7 @@ foreach ($chartData as $i => $entry) {
enabled: false enabled: false
}, },
}, },
series: [{ series: <?= json_encode($chartSeries) ?>,
data: <?= json_encode($data) ?>,
}],
colors: ['var(--bs-light)'],
tooltip: { tooltip: {
x: { x: {
show: false show: false
@ -46,11 +51,11 @@ foreach ($chartData as $i => $entry) {
y: { y: {
title: { title: {
formatter: function formatter(val) { formatter: function formatter(val) {
return ''; return '';
} }
} }
}, },
theme: '<?= !empty($darkMode) ? 'dark' : 'light' ?>' theme: 'dark'
}, },
} }
const chartOptions = Object.assign({}, defaultOptions, passedOptions) const chartOptions = Object.assign({}, defaultOptions, passedOptions)

View File

@ -1,4 +1,6 @@
<?php <?php
// debug($timeline);
// $chartData = $timeline['modified']['timeline'];
$variationIcon = ''; $variationIcon = '';
$variationClass = ''; $variationClass = '';
if ($variation == 0) { if ($variation == 0) {
@ -11,6 +13,22 @@ if ($variation == 0) {
$variationClass = 'bg-danger'; $variationClass = 'bg-danger';
} }
$series = [];
if (!empty($timeline['created']['timeline'])) {
$series[0]['name'] = __('Created');
$series[0]['type'] = 'column';
foreach ($timeline['created']['timeline'] as $entry) {
$series[0]['data'][] = $entry['count'];
}
}
if (!empty($timeline['modified']['timeline'])) {
$series[1]['name'] = __('Modified');
$series[1]['type'] = 'line';
foreach ($timeline['modified']['timeline'] as $entry) {
$series[1]['data'][] = $entry['count'];
}
}
$variationHtml = sprintf( $variationHtml = sprintf(
'<div class="badge %s fw-bold"><span class="%s me-2 align-middle"></span>%s</div>', '<div class="badge %s fw-bold"><span class="%s me-2 align-middle"></span>%s</div>',
$variationClass, $variationClass,
@ -25,9 +43,12 @@ $leftContent = sprintf('<div class="">%s</div><h2 class="my-2">%s</h2>%s',
$variationHtml $variationHtml
); );
$rightContent = sprintf('<div class="">%s</div>', $this->element('charts/bar', [ $rightContent = sprintf('<div class="">%s</div>', $this->element('charts/bar', [
'chartData' => $chartData, 'series' => $series,
'chartOptions' => [ 'chartOptions' => [
// 'colors' => ['var(--bs-light)', 'var(--bs-primary)'],
'stroke' => [
'width' => [0, 2]
],
] ]
])); ]));