Commit ef9dfe88 authored by Mark Harding's avatar Mark Harding

(feat): implements table visualisation and trending tab

1 merge request!343WIP: Analytics Dashboard
Pipeline #87896172 failed with stages
in 4 minutes and 47 seconds
......@@ -26,7 +26,7 @@ class dashboards implements Interfaces\Api, Interfaces\ApiIgnorePam
}
if (isset($_GET['filter'])) {
$filterIds = explode(',', $_GET['filters']);
$filterIds = explode(',', $_GET['filter']);
$dashboard->setFilterIds($filterIds);
}
......
......@@ -5,6 +5,7 @@ class Manager
{
const DASHBOARDS = [
'traffic' => TrafficDashboard::class,
'trending' => TrendingDashboard::class,
];
/**
......
<?php
namespace Minds\Core\Analytics\Dashboards\Metrics;
use Minds\Core\Di\Di;
use Minds\Core\Session;
use Minds\Core\Data\ElasticSearch;
class ViewsTableMetric extends AbstractMetric
{
/** @var Elasticsearch\Client */
private $es;
/** @var string */
protected $id = 'views_table';
/** @var string */
protected $label = 'Views breakdown';
/** @var string */
protected $description = 'Views by post';
/** @var array */
protected $permissions = [ 'admin' ];
public function __construct($es = null)
{
$this->es = $es ?? Di::_()->get('Database\ElasticSearch');
}
/**
* Build the metrics
* @return self
*/
public function buildSummary(): self
{
$this->summary = new MetricSummary();
$this->summary
->setValue(0)
->setComparisonValue(0)
->setComparisonInterval(null);
return $this;
}
/**
* Build a visualisation for the metric
* @return self
*/
public function buildVisualisation(): self
{
$timespan = $this->timespansCollection->getSelected();
$filters = $this->filtersCollection->getSelected();
// TODO: make this respect the filters
$field = "views::total";
if ($filters['view_type']) {
$field = "views::" . $filters['view_type']->getSelectedOption();
}
$must = [];
// Range must be from previous period
$must[]['range'] = [
'@timestamp' => [
'gte' => $timespan->getFromTsMs(),
],
];
// Specify the resolution to avoid duplicates
$must[] = [
'term' => [
'resolution' => $timespan->getInterval(),
],
];
if ($userGuid = $this->getUserGuid()) {
$must[] = [
'term' => [
'owner_guid' => $userGuid,
],
];
}
// Do the query
$query = [
'index' => 'minds-entitycentric-*',
'size' => 0,
'body' => [
'query' => [
'bool' => [
'must' => $must,
],
],
'aggs' => [
'1' => [
'terms' => [
'field' => 'entity_urn',
'min_doc_count' => 1,
'order' => [
$field => 'desc',
],
],
'aggs' => [
'views::total' => [
'sum' => [
'field' => 'views::total',
],
],
'views::organic' => [
'sum' => [
'field' => 'views::organic',
],
],
'views::single' => [
'sum' => [
'field' => 'views::single',
],
],
],
],
],
],
];
// Query elasticsearch
$prepared = new ElasticSearch\Prepared\Search();
$prepared->query($query);
$response = $this->es->request($prepared);
$buckets = [];
foreach ($response['aggregations']['1']['buckets'] as $bucket) {
$date = date(Visualisations\ChartVisualisation::DATE_FORMAT, $bucket['key'] / 1000);
$subBuckets = [];
$buckets[] = [
'key' => $bucket['key'],
'values' => [
'views::total' => $bucket['views::total']['value'],
'views::organic' => $bucket['views::organic']['value'],
'views::single' => $bucket['views::single']['value'],
],
];
}
$this->visualisation = (new Visualisations\TableVisualisation())
->setBuckets($buckets)
->setColumns([ 'views::total', 'views::organic', 'views::single']);
return $this;
}
private function getUserGuid(): ?string
{
$filters = $this->filtersCollection->getSelected();
$channelFilter = $filters['channel'];
if (!$channelFilter) {
return "";
}
if ($channelFilter->getSelectedOption() === 'self') {
return Session::getLoggedInUserGuid();
}
if ($channelFilter->getSelectedOption() === 'all') {
return "";
}
// TODO: check permissions first
return $channelFilter->getSelectedOption();
}
}
......@@ -13,7 +13,10 @@ class TableVisualisation extends AbstractVisualisation
private $type = 'table';
/** @var array */
private $rows;
private $buckets;
/** @var array */
private $columns;
/**
* Export
......@@ -24,7 +27,8 @@ class TableVisualisation extends AbstractVisualisation
{
return [
'type' => $this->type,
'rows' => (array) $this->rows,
'buckets' => (array) $this->buckets,
'columns' => (array) $this->columns,
];
}
}
<?php
/**
* Trending Dashboard
*/
namespace Minds\Core\Analytics\Dashboards;
use Minds\Traits\MagicAttributes;
/**
* @method TrafficDashboard setTimespanId(string $timespanId)
* @method TrafficDashboard setFilterIds(array $filtersIds)
*/
class TrendingDashboard implements DashboardInterface
{
use MagicAttributes;
/** @var string */
private $timespanId = '30d';
/** @var string[] */
private $filterIds = [ 'platform::browser' ];
/** @var string */
private $metricId = 'views_table';
/** @var Timespans\TimespansCollection */
private $timespansCollection;
/** @var Metrics\MetricsCollection */
private $metricsCollection;
/** @var Filters\FiltersCollection */
private $filtersCollection;
public function __construct(
$timespansCollection = null,
$metricsCollection = null,
$filtersCollection = null
) {
$this->timespansCollection = $timespansCollection ?? new Timespans\TimespansCollection();
$this->metricsCollection = $metricsCollection ?? new Metrics\MetricsCollection();
$this->filtersCollection = $filtersCollection ?? new Filters\FiltersCollection();
}
/**
* Build the dashboard
* @return self
*/
public function build(): self
{
$this->timespansCollection
->setSelectedId($this->timespanId)
->addTimespans(
new Timespans\TodayTimespan(),
new Timespans\_30dTimespan(),
new Timespans\_1yTimespan(),
new Timespans\MtdTimespan(),
new Timespans\YtdTimespan()
);
$this->filtersCollection
->setSelectedIds($this->filterIds)
->addFilters(
new Filters\PlatformFilter(),
new Filters\ViewTypeFilter(),
new Filters\ChannelFilter()
);
$this->metricsCollection
->setTimespansCollection($this->timespansCollection)
->setFiltersCollection($this->filtersCollection)
->setSelectedId($this->metricId)
->addMetrics(
new Metrics\ViewsTableMetric()
)
->build();
return $this;
}
/**
* Export
* @param array $extras
* @return array
*/
public function export(array $extras = []): array
{
$this->build();
return [
'category' => 'trending',
'timespan' => $this->timespansCollection->getSelected()->getId(),
'timespans' => $this->timespansCollection->export(),
'metric' => $this->metricsCollection->getSelected()->getId(),
'metrics' => $this->metricsCollection->export(),
'filter' => $this->filtersCollection->getSelectedIds(),
'filters' => $this->filtersCollection->export(),
];
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment