Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions assets/stylesheets/dashboard-theme.css
Original file line number Diff line number Diff line change
Expand Up @@ -77,3 +77,8 @@ body.ea-dark-scheme img.img-light {
body:not(.ea-dark-scheme) img.img-dark {
display: none;
}

.text-monospace {
font-family: var(--font-family-monospace);
font-size: 13px;
}
51 changes: 41 additions & 10 deletions src/Controller/Dashboard/DashboardPackagesInfoController.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

use CodedMonkey\Dirigent\Attribute\IsGrantedAccess;
use CodedMonkey\Dirigent\Attribute\MapPackage;
use CodedMonkey\Dirigent\Doctrine\Entity\Metadata;
use CodedMonkey\Dirigent\Doctrine\Entity\Package;
use CodedMonkey\Dirigent\Doctrine\Entity\PackageProvideLink;
use CodedMonkey\Dirigent\Doctrine\Entity\PackageRequireLink;
Expand All @@ -31,24 +30,37 @@ public function __construct(
*/
#[Route('/packages/{package}', name: 'dashboard_packages_info', requirements: ['package' => MapPackage::PACKAGE_REGEX])]
#[IsGrantedAccess]
public function info(#[MapPackage] Package $package): Response
public function info(Request $request, #[MapPackage] Package $package, MetadataRepository $metadataRepository): Response
{
$version = $package->getLatestVersion();

if (!$version) {
return $this->redirectToRoute('dashboard_packages_versions', ['package' => $package->getName()]);
}

return $this->versionInfo($package, $version);
return $this->versionInfo($request, $package, $version, $metadataRepository);
}

#[Route('/packages/{package}/versions/{version}', name: 'dashboard_packages_version_info', requirements: ['package' => MapPackage::PACKAGE_REGEX, 'version' => '.*'])]
#[IsGrantedAccess]
public function versionInfo(#[MapPackage] Package $package, #[MapPackage] Version $version): Response
{
/** @var MetadataRepository $metadataRepository */
$metadataRepository = $this->entityManager->getRepository(Metadata::class);
$metadataRepository->fetchMetadataCollections($version->getCurrentMetadata());
public function versionInfo(
Request $request,
#[MapPackage] Package $package,
#[MapPackage] Version $version,
MetadataRepository $metadataRepository,
): Response {
$metadata = $version->getCurrentMetadata();
$revision = $request->query->getInt('revision');
if (0 !== $revision) {
$metadata = $metadataRepository->findOneBy(['version' => $version, 'revision' => $revision]);
}
if (null === $metadata) {
throw $this->createNotFoundException('The revision does not exist.');
}

$metadataRepository->fetchMetadataCollections($metadata);

$metadataCount = $metadataRepository->getMetadataCountForVersion($version);

$dependentCount = $this->entityManager->getRepository(PackageRequireLink::class)->count(['linkedPackageName' => $package->getName()]);
$implementationCount = $this->entityManager->getRepository(PackageProvideLink::class)->count(['linkedPackageName' => $package->getName(), 'implementation' => true]);
Expand All @@ -58,21 +70,40 @@ public function versionInfo(#[MapPackage] Package $package, #[MapPackage] Versio
return $this->render('dashboard/packages/package_info.html.twig', [
'package' => $package,
'version' => $version,
'metadata' => $version->getCurrentMetadata(),
'metadata' => $metadata,

'dependentCount' => $dependentCount,
'implementationCount' => $implementationCount,
'metadataCount' => $metadataCount,
'providerCount' => $providerCount,
'suggesterCount' => $suggesterCount,
]);
}

#[Route('/packages/{package}/revisions/{version}', name: 'dashboard_packages_version_metadata_list', requirements: ['package' => MapPackage::PACKAGE_REGEX, 'version' => '.*'])]
#[IsGrantedAccess]
public function versionMetadataList(
#[MapPackage] Package $package,
#[MapPackage] Version $version,
MetadataRepository $metadataRepository,
): Response {
$metadataCollection = $metadataRepository->getMetadataCollectionForVersion($version);

return $this->render('dashboard/packages/package_version_revisions.html.twig', [
'package' => $package,
'version' => $version,

'metadataCollection' => $metadataCollection,
]);
}

#[Route('/packages/{package}/versions', name: 'dashboard_packages_versions', requirements: ['package' => MapPackage::PACKAGE_REGEX])]
#[IsGrantedAccess]
public function versions(#[MapPackage] Package $package): Response
public function versions(#[MapPackage] Package $package, MetadataRepository $metadataRepository): Response
{
return $this->render('dashboard/packages/package_versions.html.twig', [
'package' => $package,
'metadataCounts' => $metadataRepository->getMetadataCountsForPackage($package),
]);
}

Expand Down
40 changes: 40 additions & 0 deletions src/Doctrine/Repository/MetadataRepository.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,11 @@
namespace CodedMonkey\Dirigent\Doctrine\Repository;

use CodedMonkey\Dirigent\Doctrine\Entity\Metadata;
use CodedMonkey\Dirigent\Doctrine\Entity\Package;
use CodedMonkey\Dirigent\Doctrine\Entity\Version;
use CodedMonkey\Dirigent\Entity\MetadataLinkType;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Common\Collections\Order;
use Doctrine\Persistence\ManagerRegistry;

/**
Expand Down Expand Up @@ -40,6 +43,43 @@ public function remove(Metadata $entity, bool $flush = false): void
}
}

public function getMetadataCountForVersion(Version $version): int
{
return $this->count(['version' => $version]);
}

public function getMetadataCollectionForVersion(Version $version): array
{
return $this->findBy(
['version' => $version],
['revision' => Order::Descending->value],
);
}

/**
* Returns a map of version ID => metadata count for all versions of the given package.
*
* @return array<int, int>
*/
public function getMetadataCountsForPackage(Package $package): array
{
$rows = $this->createQueryBuilder('metadata')
->select('IDENTITY(metadata.version) as version_id, COUNT(metadata.id) as revision_count')
->join('metadata.version', 'version')
->where('version.package = :package')
->groupBy('metadata.version')
->setParameter('package', $package)
->getQuery()
->getResult();

$counts = [];
foreach ($rows as $row) {
$counts[(int) $row['version_id']] = (int) $row['revision_count'];
}

return $counts;
}

/**
* Initializes all link and keyword collections for the given metadata.
*/
Expand Down
8 changes: 6 additions & 2 deletions templates/dashboard/packages/_package_header.html.twig
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
{% set currentPage = currentPage|default(null) %}
{% set currentVersion = currentVersion|default(null) %}
{% set attrActive = 'class="nav-link active" aria-current="page"' %}
{% set attr = 'class="nav-link text-primary"' %}

<ul class="nav nav-pills nav-justified d-grid d-md-flex gap-1 pb-3 mb-3 border-bottom">
<ul class="nav nav-pills nav-justified d-grid d-md-flex gap-1 pb-2 mb-3 border-bottom">
<li class="nav-item">
{% if package.versions|length > 0 %}
{% set packageInfoUrl = path('dashboard_packages_info', {package: package.name}) %}
{% set packageInfoUrl = version is defined
? path('dashboard_packages_version_info', {package: package.name, version: version.name})
: path('dashboard_packages_info', {package: package.name})
%}
<a {{ (currentPage == 'info' ? attrActive : attr)|raw }} href="{{ packageInfoUrl }}">{{ 'Info'|trans }}</a>
{% else %}
<span class="nav-link disabled">{{ 'Info'|trans }}</span>
Expand Down
138 changes: 86 additions & 52 deletions templates/dashboard/packages/package_info.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -100,66 +100,100 @@
{% endif %}
</div>

<div class="row border-bottom pb-3 mb-3">
{{ _self.linkBlock('Requires', metadata.requireLinks) }}
{{ _self.linkBlock('Requires (dev)', metadata.devRequireLinks) }}
{{ _self.provideBlock(metadata.provideLinks) }}
{{ _self.linkBlock('Suggests', metadata.suggestLinks) }}
{{ _self.linkBlock('Conflicts', metadata.conflictLinks) }}
{{ _self.linkBlock('Replaces', metadata.replaceLinks) }}
<div class="border-bottom mb-3">
<div class="row g-0">
{{ _self.linkBlock('Requires', metadata.requireLinks) }}
{{ _self.linkBlock('Requires (dev)', metadata.devRequireLinks) }}
{{ _self.provideBlock(metadata.provideLinks) }}
{{ _self.linkBlock('Suggests', metadata.suggestLinks) }}
{{ _self.linkBlock('Conflicts', metadata.conflictLinks) }}
{{ _self.linkBlock('Replaces', metadata.replaceLinks) }}
</div>
</div>

<div class="row border-bottom pb-3 mb-3">
<div class="col-md-6">
{% if metadata.hasSource() %}
<div class="h5">
{{ 'Source'|trans }}
<span class="badge text-bg-secondary">{{ metadata.sourceType }}</span>
<div class="border-bottom pb-3 mb-3">
{% if metadataCount > 1 %}
{% set isCurrent = metadata == version.currentMetadata %}
<div class="bg-body-tertiary border border-warning-subtle px-3 py-2 mb-3 rounded">
<p>
{{ 'Multiple revisions found for version %version% of package %package%'|trans({
'%package%': "<strong>#{package.name}</strong>",
'%version%': "<strong>#{version.name}</strong>",
})|raw }}
</p>
{% if not isCurrent %}
<p class="text-warning">
<strong>
{{ "You're viewing an inactive revision of this package"|trans }}
</strong>
</p>
{% endif %}
<div class="btn-toolbar gap-1">
<a class="btn btn-sm btn-secondary" href="{{ path('dashboard_packages_version_metadata_list', {package: package.name, version: version.name}) }}">
<span class="fa-solid fa-list me-1" aria-hidden="true"></span>
<span class="btn-label">{{ 'Revisions'|trans }}</span>
</a>
{% if not isCurrent %}
<a class="btn btn-sm btn-secondary" href="{{ path('dashboard_packages_version_info', {package: package.name, version: version.name}) }}">
<span class="fa-solid fa-code-commit me-1" aria-hidden="true"></span>
<span class="btn-label">{{ 'Current revision'|trans }}</span>
</a>
{% endif %}
</div>
</div>
{% endif %}
<div class="row g-0">
<div class="col-md-6">
{% if metadata.hasSource() %}
<div class="h5">
{{ 'Source'|trans }}
<span class="badge text-bg-secondary">{{ metadata.sourceType }}</span>
</div>

<div class="mb-2">
<code>{{ metadata.sourceUrl }}</code>
</div>
<div class="mb-2">
<code>{{ metadata.sourceUrl }}</code>
</div>

<div class="mb-2">
{{ 'Reference'|trans }}: <code>{{ metadata.sourceReference }}</code>
</div>
<div class="mb-2">
{{ 'Reference'|trans }}: <code>{{ metadata.sourceReference }}</code>
</div>

<div class="mb-2">
{% set browseUrl = metadata.browsableRepositoryUrl %}
{% if browseUrl %}
<a class="btn btn-sm btn-secondary" href="{{ browseUrl }}">
<span class="fa-solid fa-code me-1" aria-hidden="true"></span>
{{ 'Browse code'|trans }}
</a>
{% endif %}
</div>
{% else %}
<div class="h5">{{ 'Source'|trans }}</div>
-
{% endif %}
</div>
<div class="col-md-6">
{% if metadata.hasDist() %}
<div class="h5">
{{ 'Distribution'|trans }}
<span class="badge text-bg-secondary">{{ metadata.distType }}</span>
</div>
<div>
{% set browseUrl = metadata.browsableRepositoryUrl %}
{% if browseUrl %}
<a class="btn btn-sm btn-secondary" href="{{ browseUrl }}">
<span class="fa-solid fa-code me-1" aria-hidden="true"></span>
<span class="btn-label">{{ 'Browse code'|trans }}</span>
</a>
{% endif %}
</div>
{% else %}
<div class="h5">{{ 'Source'|trans }}</div>
-
{% endif %}
</div>
<div class="col-md-6">
{% if metadata.hasDist() %}
<div class="h5">
{{ 'Distribution'|trans }}
<span class="badge text-bg-secondary">{{ metadata.distType }}</span>
</div>

<div class="mb-2">
{{ 'Reference'|trans }}: <code>{{ metadata.distReference }}</code>
</div>
<div class="mb-2">
{{ 'Reference'|trans }}: <code>{{ metadata.distReference }}</code>
</div>

<div class="mb-2">
<a class="btn btn-sm btn-secondary" href="{{ metadata.distUrl }}" download>
<span class="fa-solid fa-download me-1" aria-hidden="true"></span>
{{ 'Download' }}
</a>
</div>
{% else %}
<div class="h5">{{ 'Distribution'|trans }}</div>
-
{% endif %}
<div>
<a class="btn btn-sm btn-secondary" href="{{ metadata.distUrl }}" download>
<span class="fa-solid fa-download me-1" aria-hidden="true"></span>
<span class="btn-label">{{ 'Download' }}</span>
</a>
</div>
{% else %}
<div class="h5">{{ 'Distribution'|trans }}</div>
-
{% endif %}
</div>
</div>
</div>

Expand Down
38 changes: 38 additions & 0 deletions templates/dashboard/packages/package_version_revisions.html.twig
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{% extends 'dashboard/packages/package_base.html.twig' %}

{% block page_title %}
{%- apply spaceless -%}
{{ package.name }}
<small>{{ version.extendedName }}</small>
{%- endapply -%}
{% endblock %}

{% block page_content %}
{{ include('dashboard/packages/_package_header.html.twig') }}

<h2 class="h4">{{ 'Revisions'|trans }}</h2>

<div class="list-group list-group-flush border-bottom mb-3">
{% for metadata in metadataCollection %}
{% set isCurrent = metadata == version.currentMetadata %}
{% set infoUrl = isCurrent
? path('dashboard_packages_version_info', {package: package.name, version: version.name})
: path('dashboard_packages_version_info', {package: package.name, version: version.name, revision: metadata.revision})
%}
<a href="{{ infoUrl }}" class="list-group-item">
<div class="d-flex justify-content-between">
<div>
<span>{{ 'Revision'|trans }} {{ metadata.revision }}: <span class="text-monospace">{{ metadata.sourceReference }}</span></span>
</div>
<span class="text-muted">{{ metadata.releasedAt ? metadata.releasedAt.format('Y-m-d') }}</span>
</div>
<div>
<span>{{ 'Indexed on %date%'|trans({'%date%': metadata.createdAt.format('Y-m-d')}) }}</span>
{% if isCurrent %}
<span class="badge text-bg-secondary ms-1">{{ 'Current revision'|trans }}</span>
{% endif %}
</div>
</a>
{% endfor %}
</div>
{% endblock %}
Loading
Loading