Files
MokoSuiteOpenGraph/source/packages/com_mokoog/tmpl/dashboard/default.php
T
jmiller 696e369ec1
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: PR Check / Validate PR (pull_request) Failing after 7s
Universal: PR Check / Secret Scan (pull_request) Successful in 10s
Generic: Project CI / Lint & Validate (pull_request) Successful in 17s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Branch Cleanup / Delete merged branch (pull_request) Successful in 2s
Joomla: Metadata Validation / Validate Joomla Metadata (pull_request) Failing after 48s
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
feat: OG coverage dashboard as default admin view (#94)
- New DashboardModel (BaseDatabaseModel) with getStats(), getCoverageByType(),
  getMissingArticles() — coverage logic moved out of the list template
- New View/Dashboard/HtmlView + tmpl/dashboard/default.php: SVG donut coverage
  gauge, field-gap badges, per-content_type breakdown table, and a list of
  published articles missing OG tags (linking to the article editor) with a
  Batch Generate shortcut
- DisplayController default_view -> dashboard; Dashboard + Tags submenu entries
- Removed the inline coverage.php include from the tags list (it ran 6 uncached
  COUNT queries on every list load); that logic now lives in DashboardModel
- Declared tmpl/dashboard in the manifest; added language strings (en-GB, en-US)
2026-06-29 10:48:33 -05:00

143 lines
7.6 KiB
PHP

<?php
/**
* @package MokoSuiteOpenGraph
* @subpackage com_mokoog
* @author Moko Consulting <hello@mokoconsulting.tech>
* @copyright Copyright (C) 2026 Moko Consulting. All rights reserved.
* @license GNU General Public License version 3 or later; see LICENSE
*/
defined('_JEXEC') or die;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Router\Route;
use Joomla\CMS\Uri\Uri;
/** @var \Joomla\Component\MokoOG\Administrator\View\Dashboard\HtmlView $this */
$s = $this->stats;
$coverage = (int) ($s['coverage'] ?? 0);
$total = (int) ($s['total'] ?? 0);
$withOg = (int) ($s['with_og'] ?? 0);
$colorClass = $coverage >= 80 ? 'text-success' : ($coverage >= 50 ? 'text-warning' : 'text-danger');
$stroke = $coverage >= 80 ? '#198754' : ($coverage >= 50 ? '#ffc107' : '#dc3545');
$r = 54.0;
$circ = 2 * M_PI * $r;
$dash = round($circ * $coverage / 100, 2);
$gap = round($circ - $dash, 2);
?>
<div class="p-3">
<div class="row">
<!-- Coverage donut -->
<div class="col-lg-4 mb-3">
<div class="card h-100">
<div class="card-body text-center">
<h4 class="card-title"><?php echo Text::_('COM_MOKOOG_COVERAGE_PERCENT'); ?></h4>
<svg width="160" height="160" viewBox="0 0 140 140" role="img"
aria-label="<?php echo $coverage; ?>%" class="<?php echo $colorClass; ?>">
<circle cx="70" cy="70" r="54" fill="none" stroke="#e9ecef" stroke-width="14"></circle>
<circle cx="70" cy="70" r="54" fill="none" stroke="<?php echo $stroke; ?>" stroke-width="14"
stroke-dasharray="<?php echo $dash; ?> <?php echo $gap; ?>"
stroke-linecap="round" transform="rotate(-90 70 70)"></circle>
<text x="70" y="80" text-anchor="middle" font-size="30" font-weight="bold" fill="currentColor"><?php echo $coverage; ?>%</text>
</svg>
<p class="mt-2 mb-0"><?php echo Text::sprintf('COM_MOKOOG_COVERAGE_ARTICLES', $withOg, $total); ?></p>
</div>
</div>
</div>
<!-- Missing fields -->
<div class="col-lg-8 mb-3">
<div class="card h-100">
<div class="card-body">
<h4 class="card-title"><?php echo Text::_('COM_MOKOOG_DASHBOARD_FIELD_GAPS'); ?></h4>
<ul class="list-group list-group-flush">
<li class="list-group-item d-flex justify-content-between">
<span><?php echo Text::_('COM_MOKOOG_HEADING_OG_TITLE'); ?></span>
<span class="badge bg-<?php echo ($s['missing_title'] ?? 0) ? 'warning text-dark' : 'success'; ?>"><?php echo Text::sprintf('COM_MOKOOG_COVERAGE_MISSING_TITLE', (int) ($s['missing_title'] ?? 0)); ?></span>
</li>
<li class="list-group-item d-flex justify-content-between">
<span><?php echo Text::_('COM_MOKOOG_FIELD_OG_DESCRIPTION'); ?></span>
<span class="badge bg-<?php echo ($s['missing_description'] ?? 0) ? 'warning text-dark' : 'success'; ?>"><?php echo Text::sprintf('COM_MOKOOG_COVERAGE_MISSING_DESC', (int) ($s['missing_description'] ?? 0)); ?></span>
</li>
<li class="list-group-item d-flex justify-content-between">
<span><?php echo Text::_('COM_MOKOOG_HEADING_IMAGE'); ?></span>
<span class="badge bg-<?php echo ($s['missing_image'] ?? 0) ? 'warning text-dark' : 'success'; ?>"><?php echo Text::sprintf('COM_MOKOOG_COVERAGE_MISSING_IMAGE', (int) ($s['missing_image'] ?? 0)); ?></span>
</li>
</ul>
</div>
</div>
</div>
</div>
<div class="row">
<!-- Coverage by content type -->
<div class="col-lg-6 mb-3">
<div class="card h-100">
<div class="card-body">
<h4 class="card-title"><?php echo Text::_('COM_MOKOOG_DASHBOARD_BY_TYPE'); ?></h4>
<?php if (empty($this->byType)) : ?>
<p class="text-muted mb-0"><?php echo Text::_('COM_MOKOOG_NO_TAGS'); ?></p>
<?php else : ?>
<table class="table table-sm mb-0">
<thead>
<tr>
<th><?php echo Text::_('COM_MOKOOG_HEADING_CONTENT_TYPE'); ?></th>
<th class="text-end"><?php echo Text::_('JGRID_HEADING_ID'); ?></th>
<th class="text-end"><?php echo Text::_('COM_MOKOOG_HEADING_OG_TITLE'); ?></th>
<th class="text-end"><?php echo Text::_('COM_MOKOOG_HEADING_IMAGE'); ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($this->byType as $row) : ?>
<tr>
<td><?php echo $this->escape($row->content_type); ?></td>
<td class="text-end"><?php echo (int) $row->total; ?></td>
<td class="text-end"><?php echo (int) $row->with_title; ?></td>
<td class="text-end"><?php echo (int) $row->with_image; ?></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<?php endif; ?>
</div>
</div>
</div>
<!-- Articles missing OG tags -->
<div class="col-lg-6 mb-3">
<div class="card h-100">
<div class="card-body">
<div class="d-flex justify-content-between align-items-center mb-2">
<h4 class="card-title mb-0"><?php echo Text::_('COM_MOKOOG_DASHBOARD_MISSING'); ?></h4>
<a class="btn btn-sm btn-primary" href="<?php echo Route::_('index.php?option=com_mokoog&view=tags'); ?>">
<span class="icon-refresh" aria-hidden="true"></span>
<?php echo Text::_('COM_MOKOOG_TOOLBAR_BATCH_GENERATE'); ?>
</a>
</div>
<?php if (empty($this->missing)) : ?>
<p class="text-success mb-0">
<span class="icon-check" aria-hidden="true"></span>
<?php echo Text::_('COM_MOKOOG_DASHBOARD_ALL_COVERED'); ?>
</p>
<?php else : ?>
<ul class="list-group list-group-flush">
<?php foreach ($this->missing as $article) : ?>
<li class="list-group-item py-1">
<a href="<?php echo Route::_('index.php?option=com_content&task=article.edit&id=' . (int) $article->id); ?>">
<?php echo $this->escape($article->title); ?>
</a>
</li>
<?php endforeach; ?>
</ul>
<small class="text-muted d-block mt-2"><?php echo Text::_('COM_MOKOOG_DASHBOARD_MISSING_NOTE'); ?></small>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>