Skip to content

Commit

Permalink
Shorten version range in download buttons
Browse files Browse the repository at this point in the history
Display the latest + " and X more" instead of the full list. The full list remains in pinned version displays, the version page itself, etc.
  • Loading branch information
kennytv committed Aug 3, 2024
1 parent 432ed06 commit e1903b7
Show file tree
Hide file tree
Showing 11 changed files with 46 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import io.papermc.hangar.model.common.projects.Visibility;
import java.time.OffsetDateTime;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jdbi.v3.core.enums.EnumByOrdinal;
Expand All @@ -16,7 +17,7 @@ public class Version extends VersionCompact {

private final Map<Platform, Set<PluginDependency>> pluginDependencies = new EnumMap<>(Platform.class);
private final Map<Platform, Set<String>> platformDependencies = new EnumMap<>(Platform.class);
private final Map<Platform, String> platformDependenciesFormatted = new EnumMap<>(Platform.class);
private final Map<Platform, List<String>> platformDependenciesFormatted = new EnumMap<>(Platform.class);

public Version(final OffsetDateTime createdAt, @ColumnName("version_string") final String name, final Visibility visibility, final String description, @Nested("vs") final VersionStats stats, final String author, @EnumByOrdinal final ReviewState reviewState, @Nested("pc") final ProjectChannel channel, final PinnedStatus pinnedStatus) {
super(createdAt, name, visibility, description, stats, author, reviewState, channel, pinnedStatus);
Expand All @@ -30,7 +31,7 @@ public Map<Platform, Set<String>> getPlatformDependencies() {
return this.platformDependencies;
}

public Map<Platform, String> getPlatformDependenciesFormatted() {
public Map<Platform, List<String>> getPlatformDependenciesFormatted() {
return this.platformDependenciesFormatted;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ public static class PinnedVersion {
private final Type type;
private final String name;
private final ProjectChannel channel;
private final Map<Platform, String> platformDependenciesFormatted;
private final Map<Platform, List<String>> platformDependenciesFormatted;
private final Map<Platform, PlatformVersionDownload> downloads;

public PinnedVersion(final long versionId, final Type type, final String name, @Nested("pc") final ProjectChannel channel) {
Expand All @@ -149,7 +149,7 @@ public String getName() {
return this.name;
}

public Map<Platform, String> getPlatformDependenciesFormatted() {
public Map<Platform, List<String>> getPlatformDependenciesFormatted() {
return this.platformDependenciesFormatted;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,12 @@ public DownloadsAndDependencies addDownloadsAndDependencies(final String project
public DownloadsAndDependencies addDownloadsAndDependencies(final String user, final String project, final String versionName, final long versionId) {
//TODO All of this is dumb and needs to be redone into as little queries as possible
final Map<Platform, SortedSet<String>> platformDependencies = this.versionsApiDAO.getPlatformDependencies(versionId);
final Map<Platform, String> platformDependenciesFormatted = new EnumMap<>(Platform.class);
final Map<Platform, List<String>> platformDependenciesFormatted = new EnumMap<>(Platform.class);
platformDependencies.entrySet().parallelStream().forEach(entry -> {
final List<String> fullVersionsForPlatform = this.platformService.getFullVersionsForPlatform(entry.getKey());
final String formattedVersionRange = VersionFormatter.formatVersionRange(new ArrayList<>(entry.getValue()), fullVersionsForPlatform);
platformDependenciesFormatted.put(entry.getKey(), formattedVersionRange);
final Platform platform = entry.getKey();
final List<String> fullVersionsForPlatform = this.platformService.getFullVersionsForPlatform(platform);
final List<String> formattedVersionRange = VersionFormatter.formatVersionRange(new ArrayList<>(entry.getValue()), fullVersionsForPlatform);
platformDependenciesFormatted.put(platform, formattedVersionRange);
});

final Map<Platform, SortedSet<PluginDependency>> pluginDependencies = this.versionsApiDAO.getPluginDependencies(versionId).stream()
Expand All @@ -89,7 +90,7 @@ public DownloadsAndDependencies addDownloadsAndDependencies(final String user, f

public record DownloadsAndDependencies(Map<Platform, SortedSet<PluginDependency>> pluginDependencies,
Map<Platform, SortedSet<String>> platformDependencies,
Map<Platform, String> platformDependenciesFormatted,
Map<Platform, List<String>> platformDependenciesFormatted,
Map<Platform, PlatformVersionDownload> downloads
) {
public <T extends Version> T applyTo(final T version) {
Expand Down
29 changes: 17 additions & 12 deletions backend/src/main/java/io/papermc/hangar/util/VersionFormatter.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.papermc.hangar.util;

import java.util.ArrayList;
import java.util.List;

public final class VersionFormatter {
Expand All @@ -12,14 +13,14 @@ private VersionFormatter() {
*
* @param versions list of versions to stringify
* @param allVersions sorted list of all valid versions
* @return formatted version range string
* @return formatted version range strings from oldest to newest
* @throws IllegalArgumentException if versions contains a string not included in allVersions
*/
public static String formatVersionRange(final List<String> versions, final List<String> allVersions) {
public static List<String> formatVersionRange(final List<String> versions, final List<String> allVersions) {
if (versions.isEmpty()) {
return "";
return List.of("");
} else if (versions.size() == 1) {
return versions.get(0);
return List.of(versions.getFirst());
}

versions.sort((version1, version2) -> {
Expand All @@ -33,8 +34,8 @@ public static String formatVersionRange(final List<String> versions, final List<
return index1 - index2;
});

final StringBuilder builder = new StringBuilder();
String fromVersion = versions.get(0);
final List<String> formattedVersions = new ArrayList<>();
String fromVersion = versions.getFirst();
String lastVersion = fromVersion;
int lastVersionIndex = allVersions.indexOf(fromVersion);
for (int i = 1; i < versions.size(); i++) {
Expand All @@ -43,12 +44,11 @@ public static String formatVersionRange(final List<String> versions, final List<
if (versionIndex != lastVersionIndex + 1) {
// Append last version/range if a new range starts
if (!lastVersion.equals(fromVersion)) {
builder.append(fromVersion).append('-').append(lastVersion);
formattedVersions.add(fromVersion + '-' + lastVersion);
} else {
builder.append(fromVersion);
formattedVersions.add(fromVersion);
}

builder.append(", ");
fromVersion = version;
}

Expand All @@ -57,10 +57,15 @@ public static String formatVersionRange(final List<String> versions, final List<
}

// Append last version or range
builder.append(fromVersion);
if (!fromVersion.equals(lastVersion)) {
builder.append('-').append(lastVersion);
formattedVersions.add(fromVersion + '-' + lastVersion);
} else {
formattedVersions.add(fromVersion);
}
return builder.toString();
return formattedVersions;
}

public static String formatVersionRangeString(final List<String> versions, final List<String> allVersions) {
return String.join(", ", formatVersionRange(versions, allVersions));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ void testFormattedVersions() {
}

private void testFormatVersionNumbers(final String expected, final String... versions) {
Assertions.assertEquals(expected, VersionFormatter.formatVersionRange(new ArrayList<>(List.of(versions)), this.versions));
Assertions.assertEquals(expected, VersionFormatter.formatVersionRangeString(new ArrayList<>(List.of(versions)), this.versions));
}
}
13 changes: 9 additions & 4 deletions frontend/src/components/projects/DownloadButton.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,11 @@ function trackDownload(platform: string, version: { id?: number; versionId?: num
const id = version.id || version.versionId;
useInternalApi(`versions/version/${id}/${platform}/track`);
}
function formatVersionRange(versions: string[]): string {
// In download buttons, only show the latest version/version range + the remaining amount
return versions.length > 1 ? i18n.t("version.page.shortVersions", [versions.at(-1), versions.length - 1]) : versions[0];
}
</script>

<template>
Expand Down Expand Up @@ -107,7 +112,7 @@ function trackDownload(platform: string, version: { id?: number; versionId?: num
>
<PlatformLogo :platform="p" :size="24" class="mr-1 flex-shrink-0" />
{{ useBackendData.platforms.get(p)?.name }}
<span v-if="showVersions" class="ml-1">({{ v }})</span>
<span v-if="showVersions" class="ml-1">({{ formatVersionRange(v) }})</span>
<IconMdiOpenInNew v-if="isExternal(p, pinnedVersion)" class="ml-0.5 text-sm pb-0.5" />
</DropdownItem>
</DropdownButton>
Expand All @@ -132,7 +137,7 @@ function trackDownload(platform: string, version: { id?: number; versionId?: num
<div v-if="showSinglePlatform" class="inline-flex justify-center items-center font-normal text-0.75rem">
<PlatformLogo :platform="singlePlatform" :size="15" class="mr-1 flex-shrink-0" />
<span v-if="singleVersion?.platformDependencies && showVersions">
{{ singleVersion?.platformDependenciesFormatted[singlePlatform] }}
{{ formatVersionRange(singleVersion?.platformDependenciesFormatted[singlePlatform]) }}
</span>
</div>
</div>
Expand All @@ -158,7 +163,7 @@ function trackDownload(platform: string, version: { id?: number; versionId?: num
>
<PlatformLogo :platform="p" :size="24" class="mr-1 flex-shrink-0" />
{{ useBackendData.platforms.get(p)?.name }}
<span v-if="showVersions && version.platformDependencies" class="ml-1">({{ version.platformDependenciesFormatted[p] }})</span>
<span v-if="showVersions && version.platformDependencies" class="ml-1">({{ formatVersionRange(version.platformDependenciesFormatted[p]) }})</span>
<span v-if="v.fileInfo?.sizeBytes" class="ml-1"> ({{ formatSize(v.fileInfo.sizeBytes) }}) </span>
<IconMdiOpenInNew v-if="v.externalUrl" class="ml-0.5 text-sm pb-0.5" />
</DropdownItem>
Expand All @@ -183,7 +188,7 @@ function trackDownload(platform: string, version: { id?: number; versionId?: num
>
<PlatformLogo :platform="p" :size="24" class="mr-1 flex-shrink-0" />
{{ useBackendData.platforms.get(p)?.name }}
<span v-if="v.platformDependencies && showVersions" class="ml-1">({{ v.platformDependenciesFormatted[p] }})</span>
<span v-if="v.platformDependencies && showVersions" class="ml-1">({{ formatVersionRange(v.platformDependenciesFormatted[p]) }})</span>
<IconMdiOpenInNew v-if="v.downloads[p]?.externalUrl" class="ml-0.5 text-sm pb-0.5" />
</DropdownItem>
</DropdownButton>
Expand Down
1 change: 1 addition & 0 deletions frontend/src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,7 @@
"restore": "Restore",
"download": "Download",
"downloadExternal": "Download External",
"shortVersions": "{0} and {1} more",
"adminActions": "Admin actions",
"partiallyApproved": "Partially approved",
"approved": "Approved",
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/[user]/[project]/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ useHead(
<div class="flex flex-col">
<div v-for="(v, p) in version.platformDependenciesFormatted" :key="p" class="flex flex-row items-center">
<PlatformLogo :key="p" :platform="p" :size="20" class="mr-1 flex-shrink-0" />
<span :key="p" class="text-0.875rem light:text-gray-600">{{ v }}</span>
<span :key="p" class="text-0.875rem light:text-gray-600">{{ v.join(", ") }}</span>
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ function sortedDependencies(platform: Platform) {
const supportsString = computed(() => {
const result = [];
for (const platform in projectVersion.value?.platformDependenciesFormatted) {
result.push(titleCase(platform.toLowerCase()) + " " + projectVersion.value?.platformDependenciesFormatted[platform]);
result.push(titleCase(platform.toLowerCase()) + " " + projectVersion.value?.platformDependenciesFormatted[platform].join(", "));
}
return result.join(", ");
});
Expand Down Expand Up @@ -345,7 +345,7 @@ async function restoreVersion() {
<div v-for="platform in versionPlatforms" :key="platform" class="flex items-center mb-1">
<PlatformLogo :platform="platform" :size="24" class="mr-1 flex-shrink-0" />
{{ useBackendData.platforms.get(platform)?.name }}
({{ projectVersion?.platformDependenciesFormatted[platform] }})
({{ projectVersion?.platformDependenciesFormatted[platform].join(", ") }})
<span class="flex-grow" />
<PlatformVersionEditModal
v-if="hasPerms(NamedPermission.EditVersion)"
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/pages/[user]/[project]/versions/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ function getVisibilityTitle(visibility: Visibility) {
<div v-for="(v, p) in item.platformDependenciesFormatted" :key="p" class="basis-full">
<div class="inline-flex items-center">
<PlatformLogo :platform="p" :size="22" class="mr-1 flex-shrink-0" />
<span class="mr-3 text-0.95rem">{{ v }}</span>
<span class="mr-3 text-0.95rem">{{ v.join(", ") }}</span>
</div>
</div>
</div>
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/types/backend/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -959,7 +959,7 @@ export interface Version {
downloads: Record<string, PlatformVersionDownload>;
pluginDependencies: Record<string, PluginDependency[]>;
platformDependencies: Record<string, string[]>;
platformDependenciesFormatted: Record<string, string>;
platformDependenciesFormatted: Record<string, string[]>;
}

export interface VersionStats {
Expand Down Expand Up @@ -1022,7 +1022,7 @@ export interface HangarVersion {
downloads: Record<string, PlatformVersionDownload>;
pluginDependencies: Record<string, PluginDependency[]>;
platformDependencies: Record<string, string[]>;
platformDependenciesFormatted: Record<string, string>;
platformDependenciesFormatted: Record<string, string[]>;
/** @format int64 */
id: number;
approvedBy: string;
Expand Down Expand Up @@ -1147,7 +1147,7 @@ export interface PinnedVersion {
type: Type;
name: string;
channel: ProjectChannel;
platformDependenciesFormatted: Record<string, string>;
platformDependenciesFormatted: Record<string, string[]>;
downloads: Record<string, PlatformVersionDownload>;
}

Expand Down

0 comments on commit e1903b7

Please sign in to comment.