Skip to content

Commit df6ede2

Browse files
committed
Improve details sidebar on package info page with browsable repository URLs
1 parent e44be6f commit df6ede2

7 files changed

Lines changed: 130 additions & 53 deletions

File tree

assets/stylesheets/dashboard-theme.css

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,8 @@
6464
.ea-dark-scheme .bg-body-secondary {
6565
--bs-secondary-bg-rgb: var(--dirigent-body-bg-subtle-rgb);
6666
}
67+
68+
.dirigent-package-sidebar div span {
69+
display: inline-block;
70+
width: 120px;
71+
}

src/Doctrine/Entity/Package.php

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,30 @@ public function setDumpedAt(?\DateTimeInterface $dumpedAt): void
343343
$this->dumpedAt = $dumpedAt;
344344
}
345345

346+
public function getBrowsableRepositoryUrl(): ?string
347+
{
348+
if (!$this->repositoryUrl) {
349+
return null;
350+
}
351+
352+
if (!Preg::isMatch('{^https?://}i', $this->repositoryUrl)) {
353+
return null;
354+
}
355+
356+
return $this->repositoryUrl;
357+
}
358+
359+
public function getPrettyBrowsableRepositoryUrl(): ?string
360+
{
361+
if (null === $url = $this->getBrowsableRepositoryUrl()) {
362+
return null;
363+
}
364+
365+
$url = preg_replace('#^https?://#', '', $url);
366+
367+
return $url;
368+
}
369+
346370
/**
347371
* Returns the default branch or latest version of the package.
348372
*/

src/Doctrine/Entity/Version.php

Lines changed: 5 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,11 @@ public function setReleasedAt(?\DateTimeInterface $releasedAt): void
512512
$this->releasedAt = $releasedAt;
513513
}
514514

515+
public function getSourceUrl(): ?string
516+
{
517+
return $this->source['url'] ?? null;
518+
}
519+
515520
public function getDistReference(): ?string
516521
{
517522
return $this->dist['reference'] ?? null;
@@ -568,28 +573,6 @@ public function getFundingSorted(): ?array
568573
return $funding;
569574
}
570575

571-
public function getPublicUrl(): ?string
572-
{
573-
$url = $this->getHomepage() ?? $this->getSource()['url'] ?? null;
574-
575-
if (!$url || (!str_starts_with($url, 'http://') && !str_starts_with($url, 'https://'))) {
576-
return null;
577-
}
578-
579-
return $url;
580-
}
581-
582-
public function getPrettyPublicUrl(): ?string
583-
{
584-
if (null === $url = $this->getPublicUrl()) {
585-
return null;
586-
}
587-
588-
$url = preg_replace('#^https?://#', '', $url);
589-
590-
return $url;
591-
}
592-
593576
public function getMajorVersion(): int
594577
{
595578
$split = explode('.', $this->version);

src/Package/PackageMetadataResolver.php

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,8 @@ private function resolveVcsRepository(Package $package): void
156156
foreach ($composerPackages as $composerPackage) {
157157
if ($composerPackage->isDefaultBranch()) {
158158
$package->setRepositoryUrl($composerPackage->getSourceUrl());
159+
160+
return;
159161
}
160162
}
161163
}
@@ -166,8 +168,8 @@ private function resolveVcsRepository(Package $package): void
166168
private function updatePackage(Package $package, array $composerPackages, ?VcsDriverInterface $driver = null): void
167169
{
168170
$existingVersions = $this->versionRepository->getVersionMetadataForUpdate($package);
169-
/** @var ?string $primaryVersionName Version name to use as the package link source */
170-
$primaryVersionName = null;
171+
/** @var ?CompletePackageInterface $primaryVersion Version to use as the package info source */
172+
$primaryVersion = null;
171173

172174
foreach ($composerPackages as $composerPackage) {
173175
if ($composerPackage instanceof AliasPackage) {
@@ -184,19 +186,22 @@ private function updatePackage(Package $package, array $composerPackages, ?VcsDr
184186
$versionName = $version->getNormalizedVersion();
185187

186188
// Use the first version which should be the highest stable version by default
187-
if (null === $primaryVersionName) {
188-
$primaryVersionName = $versionName;
189-
}
189+
$primaryVersion ??= $version;
190190
// If default branch is present however we prefer that as the canonical package link source
191191
if ($version->isDefaultBranch()) {
192-
$primaryVersionName = $versionName;
192+
$primaryVersion = $version;
193193
}
194194

195195
unset($existingVersions[$versionName]);
196196
}
197197

198-
if ($primaryVersionName) {
199-
$message = new Envelope(new UpdatePackageLinks($package->getId(), $primaryVersionName), [
198+
if ($primaryVersion) {
199+
// Only update the repository URL if the package is mirrored
200+
if ($package->getMirrorRegistry()) {
201+
$package->setRepositoryUrl($primaryVersion->getSourceUrl());
202+
}
203+
204+
$message = new Envelope(new UpdatePackageLinks($package->getId(), $primaryVersion->getNormalizedVersion()), [
200205
new DispatchAfterCurrentBusStamp(),
201206
new TransportNamesStamp('async'),
202207
]);

templates/dashboard/packages/package_info.html.twig

Lines changed: 34 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -23,42 +23,59 @@
2323

2424
<p class="lead">{{ version.description }}</p>
2525

26-
<p class="mb-0">Last updated at {{ package.updatedAt|date }}</p>
26+
{% if version.authors|length > 0 %}
27+
<div class="d-flex gap-3 mb-2">
28+
{% for author in version.authors %}
29+
{% set authorText %}<span class="fa-solid fa-user me-2" aria-hidden="true"></span>{{ author.name }}{% endset %}
30+
{% if author.homepage is defined %}<a href="{{ author.homepage }}">{{ authorText }}</a>{% else %}<span>{{ authorText }}</span>{% endif %}
31+
{% endfor %}
32+
</div>
33+
{% endif %}
2734
</div>
2835
<div class="col-md-4">
29-
<div class="bg-body-secondary px-3 py-2 rounded">
30-
{% if version.publicUrl %}
36+
<div class="dirigent-package-sidebar bg-body-secondary px-3 py-2 mb-2 rounded">
37+
{% if package.browsableRepositoryUrl %}
3138
<div>
32-
<a href="{{ version.publicUrl }}">{{ version.prettyPublicUrl }}</a>
39+
<a href="{{ package.browsableRepositoryUrl }}">{{ package.prettyBrowsableRepositoryUrl }}</a>
3340
</div>
3441
{% endif %}
3542
{% if package.mirrorRegistry %}
3643
<div>Mirrored from {{ package.mirrorRegistry.name }}</div>
3744
{% endif %}
38-
{% if version.publicUrl or package.mirrorRegistry %}
45+
{% if package.browsableRepositoryUrl or package.mirrorRegistry %}
3946
<hr class="my-1">
4047
{% endif %}
4148
{% if version.homepage %}
4249
<div><a href="{{ version.homepage }}">Homepage</a></div>
4350
{% endif %}
44-
{% if version.source %}
45-
<div><a href="{{ version.source.url }}">Source</a></div>
51+
{% if version.sourceUrl %}
52+
<div><a href="{{ version.sourceUrl }}">Source</a></div>
53+
{% endif %}
54+
{% set packageStatisticsUrl = path('dashboard_packages_statistics', {packageName: package.name}) %}
55+
<div><span><a href="{{ packageStatisticsUrl }}">{{ 'Installations'|trans }}</a></span> {{ package.installations.total }}</div>
56+
{% if dependentCount > 0 %}
57+
{% set packageDependentsUrl = path('dashboard_packages_dependents', {packageName: package.name}) %}
58+
<div><span><a href="{{ packageDependentsUrl }}">{{ 'Dependents'|trans }}</a></span> {{ dependentCount }}</div>
59+
{% endif %}
60+
{% if suggesterCount > 0 %}
61+
{% set packageSuggestersUrl = path('dashboard_packages_suggesters', {packageName: package.name}) %}
62+
<div><span><a href="{{ packageSuggestersUrl }}">{{ 'Suggesters'|trans }}</a></span> {{ suggesterCount }}</div>
63+
{% endif %}
64+
{% if implementationCount > 0 %}
65+
{% set packageImplementationsUrl = path('dashboard_packages_implementations', {packageName: package.name}) %}
66+
<div><span><a href="{{ packageImplementationsUrl }}">{{ 'Implementations'|trans }}</a></span> {{ implementationCount }}</div>
67+
{% endif %}
68+
{% if providerCount > 0 %}
69+
{% set packageProvidersUrl = path('dashboard_packages_providers', {packageName: package.name}) %}
70+
<div><span><a href="{{ packageProvidersUrl }}">{{ 'Providers'|trans }}</a></span> {{ providerCount }}</div>
4671
{% endif %}
47-
<div>Installs: {{ package.installations.total }}</div>
48-
{% set packageDependentsUrl = path('dashboard_packages_dependents', {packageName: package.name}) %}
49-
<div><a href="{{ packageDependentsUrl }}">{{ 'Dependents'|trans }}</a>: {{ dependentCount }}</div>
50-
{% set packageSuggestersUrl = path('dashboard_packages_suggesters', {packageName: package.name}) %}
51-
<div><a href="{{ packageSuggestersUrl }}">{{ 'Suggesters'|trans }}</a>: {{ suggesterCount }}</div>
52-
{% set packageImplementationsUrl = path('dashboard_packages_implementations', {packageName: package.name}) %}
53-
<div><a href="{{ packageImplementationsUrl }}">{{ 'Implementations'|trans }}</a>: {{ implementationCount }}</div>
54-
{% set packageProvidersUrl = path('dashboard_packages_providers', {packageName: package.name}) %}
55-
<div><a href="{{ packageProvidersUrl }}">{{ 'Providers'|trans }}</a>: {{ providerCount }}</div>
5672
{% if version.license %}
57-
<div>License: {{ version.license|join(', ') }}</div>
73+
<div><span>{{ 'License'|trans }}</span> {{ version.license|join(', ') }}</div>
5874
{% else %}
5975
<div>No license specified</div>
6076
{% endif %}
6177
</div>
78+
<p class="px-3 mb-0"><small>{{ 'Last updated at %date%'|trans({'%date%': package.updatedAt|date}) }}</small></p>
6279
</div>
6380
</div>
6481

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
<?php
2+
3+
namespace CodedMonkey\Dirigent\Tests\UnitTests\Doctrine\Entity;
4+
5+
use CodedMonkey\Dirigent\Doctrine\Entity\Package;
6+
use PHPUnit\Framework\Attributes\CoversClass;
7+
use PHPUnit\Framework\TestCase;
8+
9+
#[CoversClass(Package::class)]
10+
class PackageTest extends TestCase
11+
{
12+
public function testBrowsableRepositoryUrl(): void
13+
{
14+
$package = new Package();
15+
16+
$package->setRepositoryUrl('https://example.com/super/trouper');
17+
self::assertSame('https://example.com/super/trouper', $package->getBrowsableRepositoryUrl());
18+
19+
$package->setRepositoryUrl('git://example.com/super/trouper');
20+
self::assertNull($package->getBrowsableRepositoryUrl());
21+
22+
$package->setRepositoryUrl('git@example.com/super/trouper.git');
23+
self::assertNull($package->getBrowsableRepositoryUrl());
24+
}
25+
26+
public function testPrettyBrowsableRepositoryUrl(): void
27+
{
28+
$package = new Package();
29+
30+
$package->setRepositoryUrl('https://example.com/super/trouper');
31+
self::assertSame('example.com/super/trouper', $package->getPrettyBrowsableRepositoryUrl());
32+
33+
$package->setRepositoryUrl('git://example.com/super/trouper');
34+
self::assertNull($package->getPrettyBrowsableRepositoryUrl());
35+
36+
$package->setRepositoryUrl('git@example.com/super/trouper.git');
37+
self::assertNull($package->getPrettyBrowsableRepositoryUrl());
38+
}
39+
}

translations/messages.en.yaml

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,11 @@ Account: Account
33
Administration: Administration
44
Credits: Credits
55
Dashboard: Dashboard
6-
Dependents: Dependents
76
Documentation: Documentation
8-
Implementations: Implementations
97
Info: Info
108
Packages: Packages
119
Personal: Personal
12-
Providers: Providers
1310
Sign out: Sign out
14-
Statistics: Statistics
15-
Suggesters: Suggesters
1611
Usage: Usage
1712

1813
# Entity names
@@ -47,6 +42,16 @@ Username: Username
4742
No credentials: No credentials
4843
Search packages: Search packages
4944

45+
# Package labels
46+
Dependents: Dependents
47+
Implementations: Implementations
48+
Installations: Installations
49+
Last updated at %date%: Last updated at %date%
50+
License: License
51+
Providers: Providers
52+
Statistics: Statistics
53+
Suggesters: Suggesters
54+
5055
# Page actions
5156
Impersonate: Impersonate
5257
Move Down: Move down
@@ -55,7 +60,6 @@ Move Up: Move up
5560
# Statistics labels
5661
Daily installations: Daily installations
5762
Daily installations per version: Daily installations per version
58-
Installations: Installations
5963
Last 30 days: Last 30 days
6064
Today: Today
6165
Total: Total

0 commit comments

Comments
 (0)