new: [instance:home] Added statistics and highlight panel - WiP
parent
6a68290561
commit
14e0fa90b3
|
@ -19,7 +19,9 @@ class InstanceController extends AppController
|
||||||
|
|
||||||
public function home()
|
public function home()
|
||||||
{
|
{
|
||||||
$this->set('md', file_get_contents(ROOT . '/README.md'));
|
// $this->set('md', file_get_contents(ROOT . '/README.md'));
|
||||||
|
$statistics = $this->Instance->getStatistics();
|
||||||
|
$this->set('statistics', $statistics);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function status()
|
public function status()
|
||||||
|
|
|
@ -4,6 +4,7 @@ namespace App\Model\Table;
|
||||||
|
|
||||||
use App\Model\Table\AppTable;
|
use App\Model\Table\AppTable;
|
||||||
use Cake\ORM\Table;
|
use Cake\ORM\Table;
|
||||||
|
use Cake\ORM\TableRegistry;
|
||||||
use Cake\Validation\Validator;
|
use Cake\Validation\Validator;
|
||||||
use Migrations\Migrations;
|
use Migrations\Migrations;
|
||||||
|
|
||||||
|
@ -21,6 +22,47 @@ class InstanceTable extends AppTable
|
||||||
return $validator;
|
return $validator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getStatistics($days=7): array
|
||||||
|
{
|
||||||
|
$models = ['Individuals', 'Organisations', 'Alignments', 'EncryptionKeys', 'SharingGroups', 'Users', 'Tags.Tags'];
|
||||||
|
foreach ($models as $model) {
|
||||||
|
$table = TableRegistry::getTableLocator()->get($model);
|
||||||
|
$statistics[$model]['amount'] = $table->find()->all()->count();
|
||||||
|
if ($table->behaviors()->has('Timestamp')) {
|
||||||
|
$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;
|
||||||
|
}
|
||||||
|
|
||||||
public function getMigrationStatus()
|
public function getMigrationStatus()
|
||||||
{
|
{
|
||||||
$migrations = new Migrations();
|
$migrations = new Migrations();
|
||||||
|
|
|
@ -979,6 +979,7 @@ class BoostrapCard extends BootstrapGeneric
|
||||||
'headerHTML' => '',
|
'headerHTML' => '',
|
||||||
'footerHTML' => '',
|
'footerHTML' => '',
|
||||||
'bodyHTML' => '',
|
'bodyHTML' => '',
|
||||||
|
'class' => '',
|
||||||
'headerClass' => '',
|
'headerClass' => '',
|
||||||
'bodyClass' => '',
|
'bodyClass' => '',
|
||||||
'footerClass' => '',
|
'footerClass' => '',
|
||||||
|
@ -1010,6 +1011,7 @@ class BoostrapCard extends BootstrapGeneric
|
||||||
'card',
|
'card',
|
||||||
!empty($this->options['variant']) ? "bg-{$this->options['variant']}" : '',
|
!empty($this->options['variant']) ? "bg-{$this->options['variant']}" : '',
|
||||||
!empty($this->options['variant']) ? $this->getTextClassForVariant($this->options['variant']) : '',
|
!empty($this->options['variant']) ? $this->getTextClassForVariant($this->options['variant']) : '',
|
||||||
|
h($this->options['class']),
|
||||||
],
|
],
|
||||||
], implode('', [$this->genHeader(), $this->genBody(), $this->genFooter()]));
|
], implode('', [$this->genHeader(), $this->genBody(), $this->genFooter()]));
|
||||||
return $card;
|
return $card;
|
||||||
|
|
|
@ -1,3 +1,22 @@
|
||||||
<?php
|
<?php
|
||||||
$Parsedown = new Parsedown();
|
// $Parsedown = new Parsedown();
|
||||||
echo $Parsedown->text($md);
|
// echo $Parsedown->text($md);
|
||||||
|
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<?php foreach ($statistics as $modelName => $statistics): ?>
|
||||||
|
<div class="col-sm-6 col-md-4 col-l-3 col-xl-2 mb-2">
|
||||||
|
<?php
|
||||||
|
$modelName = explode('.', $modelName);
|
||||||
|
$modelName = $modelName[count($modelName)-1];
|
||||||
|
echo $this->element('widgets/highlight-panel', [
|
||||||
|
'title' => $modelName,
|
||||||
|
'number' => $statistics['amount'],
|
||||||
|
'variation' => $statistics['variation'] ?? '',
|
||||||
|
'chartData' => $statistics['timeline'] ?? []
|
||||||
|
]);
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
<?php endforeach ?>
|
||||||
|
</div>
|
|
@ -0,0 +1,64 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$chartOptions = $chartOptions ?? [];
|
||||||
|
$chartData = $chartData ?? [];
|
||||||
|
$seed = mt_rand();
|
||||||
|
$chartId = "chart-{$seed}";
|
||||||
|
|
||||||
|
// Transform the chart data into the expected format
|
||||||
|
$data = [];
|
||||||
|
foreach ($chartData as $i => $entry) {
|
||||||
|
$data[] = $entry['count'];
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div id="<?= $chartId ?>"></div>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/apexcharts"></script>
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
const passedOptions = <?= json_encode($chartOptions) ?>;
|
||||||
|
const defaultOptions = {
|
||||||
|
chart: {
|
||||||
|
id: '<?= $chartId ?>',
|
||||||
|
type: 'bar',
|
||||||
|
sparkline: {
|
||||||
|
enabled: true
|
||||||
|
},
|
||||||
|
dropShadow: {
|
||||||
|
enabled: true,
|
||||||
|
top: 1,
|
||||||
|
left: 1,
|
||||||
|
blur: 2,
|
||||||
|
opacity: 0.2,
|
||||||
|
},
|
||||||
|
animations: {
|
||||||
|
enabled: false
|
||||||
|
},
|
||||||
|
},
|
||||||
|
series: [{
|
||||||
|
data: <?= json_encode($data) ?>,
|
||||||
|
}],
|
||||||
|
colors: ['var(--success)'],
|
||||||
|
tooltip: {
|
||||||
|
x: {
|
||||||
|
show: false
|
||||||
|
},
|
||||||
|
y: {
|
||||||
|
title: {
|
||||||
|
formatter: function formatter(val) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
theme: '<?= !empty($darkMode) ? 'dark' : 'light' ?>'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const chartOptions = Object.assign({}, defaultOptions, passedOptions)
|
||||||
|
new ApexCharts(document.querySelector('#<?= $chartId ?>'), chartOptions).render();
|
||||||
|
|
||||||
|
// const chart = new ApexCharts(document.querySelector("#<?= $chartId ?>"), options);
|
||||||
|
// chart.render();
|
||||||
|
})()
|
||||||
|
</script>
|
|
@ -0,0 +1,37 @@
|
||||||
|
<?php
|
||||||
|
$variationIcon = '';
|
||||||
|
$variationClass = '';
|
||||||
|
if ($variation == 0) {
|
||||||
|
$variationIcon = 'minus';
|
||||||
|
} elseif ($variation > 0) {
|
||||||
|
$variationIcon = 'arrow-up';
|
||||||
|
$variationClass = 'text-success';
|
||||||
|
} else {
|
||||||
|
$variationIcon = 'arrow-down';
|
||||||
|
$variationClass = 'text-danger';
|
||||||
|
}
|
||||||
|
|
||||||
|
$variationHtml = sprintf('<div class="%s"><span class="%s mr-2"></span>%s</div>',
|
||||||
|
$variationClass,
|
||||||
|
$this->FontAwesome->getClass($variationIcon),
|
||||||
|
!empty($variation) ? h($variation) : ''
|
||||||
|
);
|
||||||
|
|
||||||
|
$leftContent = sprintf('<div class="">%s</div><h2 class="my-2">%s</h2>%s',
|
||||||
|
h($title ?? ''),
|
||||||
|
h($number ?? ''),
|
||||||
|
$variationHtml
|
||||||
|
);
|
||||||
|
$rightContent = sprintf('<div class="">%s</div>', $this->element('charts/bar', [
|
||||||
|
'chartData' => $chartData
|
||||||
|
]));
|
||||||
|
|
||||||
|
$cardContent = sprintf('<div class="highlight-panel-container d-flex align-items-center justify-content-between"><div class="number-container">%s</div><div class="chart-container w-50">%s</div></div>', $leftContent, $rightContent);
|
||||||
|
|
||||||
|
echo $this->Bootstrap->card([
|
||||||
|
'variant' => 'secondary',
|
||||||
|
'bodyHTML' => $cardContent,
|
||||||
|
'bodyClass' => 'p-3'
|
||||||
|
]);
|
||||||
|
|
||||||
|
?>
|
Loading…
Reference in New Issue