Skip to content

Commit 123bfee

Browse files
mbastianclaude
andcommitted
Fix bugs found in code review of the version-filtering changes
- Show the legacy-hidden default plugin count in SSR/no-JS output instead of the raw total - Drop legacy versions stuck in filter state (bookmarked URL, or unchecking "Show older Gephi versions") instead of permanently zeroing results with no recovery - Scope the "Show older versions" caret rotation to the summary icon instead of every icon in the disclosure - Pick the "latest version" download CTA via a real numeric version comparison instead of relying on source JSON key order - Log fetch failures in getLatestGephiVersion instead of swallowing them silently - Break exact-timestamp ties when grouping versions by keeping the latest-iterated build - Fix normalizeGephiVersion corrupting single-part version strings - Simplify a redundant length check Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
1 parent a9d4886 commit 123bfee

5 files changed

Lines changed: 68 additions & 27 deletions

File tree

‎src/components/plugins/PluginsFilters.tsx‎

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,23 @@ interface FilterStateType {
1313
}
1414

1515
function searchToState(urlSearchParam: URLSearchParams): FilterStateType {
16+
const showLegacy = urlSearchParam.get("legacy") === "1";
17+
const versions =
18+
urlSearchParam
19+
.get("versions")
20+
?.split("|")
21+
.map((v) => decodeURIComponent(v)) || [];
1622
return {
1723
query: urlSearchParam.get("query") || undefined,
18-
versions:
19-
urlSearchParam
20-
.get("versions")
21-
?.split("|")
22-
.map((v) => decodeURIComponent(v)) || [],
24+
// Drop any legacy version stuck in a bookmarked/old URL when legacy versions aren't shown,
25+
// otherwise it can never match a visible tag and silently zeroes the results.
26+
versions: showLegacy ? versions : versions.filter((v) => !isLegacyGephiVersion(v)),
2327
categories:
2428
urlSearchParam
2529
.get("categories")
2630
?.split("|")
2731
.map((v) => decodeURIComponent(v)) || [],
28-
showLegacy: urlSearchParam.get("legacy") === "1",
32+
showLegacy,
2933
};
3034
}
3135
function stateToSearch(state: FilterStateType): string {
@@ -163,7 +167,14 @@ export const PluginsFilters: FC<{ plugins: Plugin[] }> = ({ plugins }) => {
163167
id="show-legacy-checkbox"
164168
checked={state.showLegacy}
165169
onChange={(e) => {
166-
setState((state) => ({ ...state, showLegacy: e.target.checked }));
170+
const showLegacy = e.target.checked;
171+
setState((state) => ({
172+
...state,
173+
showLegacy,
174+
// Drop any checked legacy versions so they don't keep filtering to nothing
175+
// once their checkboxes disappear from the facet list.
176+
versions: showLegacy ? state.versions : state.versions.filter((v) => !isLegacyGephiVersion(v)),
177+
}));
167178
}}
168179
className="form-check-input"
169180
/>

‎src/components/plugins/utils.ts‎

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,58 @@ export function pluginElementId(id: string) {
44
return `gephi-plugin-${id}`;
55
}
66

7+
function parseGephiVersion(v: string): [number, number] {
8+
const parts = v.split(".").map((n) => parseInt(n, 10) || 0);
9+
return [parts[0] ?? 0, parts[1] ?? 0];
10+
}
11+
712
// Gephi 0.10+ no longer differentiates plugin builds at the patch level, so we
813
// only keep major.minor for those. Pre-0.10 ("legacy") builds did differentiate
914
// per patch, so we keep their full version string.
1015
export function isLegacyGephiVersion(v: string): boolean {
11-
const [major, minor] = v.split(".").map((n) => parseInt(n, 10) || 0);
16+
const [major, minor] = parseGephiVersion(v);
1217
return major === 0 && minor < 10;
1318
}
1419

1520
export function normalizeGephiVersion(v: string): string {
1621
if (isLegacyGephiVersion(v)) return v;
17-
const [major, minor] = v.split(".").map((n) => parseInt(n, 10) || 0);
22+
const [major, minor] = parseGephiVersion(v);
1823
return `${major}.${minor}`;
1924
}
2025

2126
export function pluginHasModernVersion(p: Plugin): boolean {
2227
return Object.keys(p.versions).some((v) => !isLegacyGephiVersion(v));
2328
}
2429

30+
// Descending comparator so the most recent version sorts first, regardless of
31+
// the order versions happen to appear in the source data.
32+
export function compareGephiVersionsDesc(a: string, b: string): number {
33+
const aParts = a.split(".").map((n) => parseInt(n, 10) || 0);
34+
const bParts = b.split(".").map((n) => parseInt(n, 10) || 0);
35+
for (let i = 0; i < Math.max(aParts.length, bParts.length); i++) {
36+
const diff = (bParts[i] ?? 0) - (aParts[i] ?? 0);
37+
if (diff !== 0) return diff;
38+
}
39+
return 0;
40+
}
41+
42+
// Groups a plugin's versions by normalized tag, keeping the most recently
43+
// updated build per tag.
44+
export function groupPluginVersionsByTag(versions: Plugin["versions"]): Record<string, Plugin["versions"][string]> {
45+
return Object.entries(versions).reduce<Record<string, Plugin["versions"][string]>>((acc, [v, info]) => {
46+
const tag = normalizeGephiVersion(v);
47+
if (!acc[tag] || new Date(info.last_update) >= new Date(acc[tag].last_update)) acc[tag] = info;
48+
return acc;
49+
}, {});
50+
}
51+
2552
export async function getLatestGephiVersion(): Promise<string | null> {
2653
try {
2754
const resp = await fetch("https://api.github.com/repos/gephi/gephi/releases/latest");
2855
const data = (await resp.json()) as { tag_name: string };
2956
return normalizeGephiVersion(data.tag_name.replace(/^v/, ""));
30-
} catch {
57+
} catch (err) {
58+
console.log("Failed to fetch the latest Gephi release version from GitHub.", err);
3159
return null;
3260
}
3361
}

‎src/pages/desktop/plugins/[id].astro‎

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,12 @@ import { Image } from "astro:assets";
66
import Banner from "../../../components/Banner.astro";
77
import Layout from "../../../layouts/Layout.astro";
88
import type { Plugin } from "../../../type";
9-
import { getLatestGephiVersion, isLegacyGephiVersion, normalizeGephiVersion } from "../../../components/plugins/utils";
9+
import {
10+
compareGephiVersionsDesc,
11+
getLatestGephiVersion,
12+
groupPluginVersionsByTag,
13+
isLegacyGephiVersion,
14+
} from "../../../components/plugins/utils";
1015
1116
interface Props {
1217
plugin: Plugin;
@@ -37,15 +42,8 @@ try {
3742
3843
// Since Gephi 0.10, plugin builds are no longer version-specific at the patch level, so
3944
// group download links by normalized version, keeping the most recently updated build per group.
40-
const groupedVersions = Object.entries(plugin.versions).reduce<Record<string, Plugin["versions"][string]>>(
41-
(acc, [v, info]) => {
42-
const tag = normalizeGephiVersion(v);
43-
if (!acc[tag] || new Date(info.last_update) > new Date(acc[tag].last_update)) acc[tag] = info;
44-
return acc;
45-
},
46-
{},
47-
);
48-
const sortedVersionTags = Object.keys(groupedVersions).reverse();
45+
const groupedVersions = groupPluginVersionsByTag(plugin.versions);
46+
const sortedVersionTags = Object.keys(groupedVersions).sort(compareGephiVersionsDesc);
4947
const modernVersionTags = sortedVersionTags.filter((v) => !isLegacyGephiVersion(v));
5048
const legacyVersionTags = sortedVersionTags.filter(isLegacyGephiVersion);
5149
const topVersionTag = modernVersionTags[0];
@@ -172,7 +170,7 @@ const topVersionIsLatestGephi = !!topVersionTag && topVersionTag === latestGephi
172170
instance.
173171
</div>
174172
{
175-
modernVersionTags.length > 0 || legacyVersionTags.length > 0 ? (
173+
sortedVersionTags.length > 0 ? (
176174
<>
177175
{modernVersionTags.length > 0 && (
178176
<ul class="list-unstyled">

‎src/pages/desktop/plugins/index.astro‎

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ import Default from "../../../images/plugins/default-screenshot.jpg";
77
import Layout from "../../../layouts/Layout.astro";
88
import { PluginsFilters } from "../../../components/plugins/PluginsFilters";
99
import type { Plugin } from "../../../type";
10-
import { pluginElementId } from "../../../components/plugins/utils";
10+
import { pluginElementId, pluginHasModernVersion } from "../../../components/plugins/utils";
1111
1212
const pluginsDataRequest = await fetch(
1313
"https://raw.githubusercontent.com/gephi/gephi-plugins/refs/heads/gh-pages/plugins/plugins.json",
@@ -16,6 +16,10 @@ const pluginsDataRequest = await fetch(
1616
const pluginsData: Plugin[] | null = pluginsDataRequest.ok
1717
? reverse(sortBy((await pluginsDataRequest.json()).plugins as Plugin[], (p) => new Date(p.last_update)))
1818
: null;
19+
20+
// Matches PluginsFilters' default (legacy plugins hidden) so the count doesn't flash/mismatch
21+
// before hydration, and stays correct for no-JS clients.
22+
const defaultVisibleCount = pluginsData?.filter(pluginHasModernVersion).length ?? 0;
1923
---
2024

2125
<Layout pageId="desktop-plugins">
@@ -47,7 +51,7 @@ const pluginsData: Plugin[] | null = pluginsDataRequest.ok
4751

4852
<section class="plugins-list-container container-fluid">
4953
<h2 id="plugins-list-total">
50-
{pluginsData.length || "No"} {pluginsData.length > 1 ? "plugins" : "plugin"}
54+
{defaultVisibleCount || "No"} {defaultVisibleCount > 1 ? "plugins" : "plugin"}
5155
</h2>
5256
<div class="plugins-list row">
5357
{pluginsData.map((p) => (

‎src/styles/_plugins.scss‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,12 +140,12 @@
140140
&::-webkit-details-marker {
141141
display: none;
142142
}
143-
}
144143

145-
svg {
146-
transition: all 0.2s ease-out;
144+
svg {
145+
transition: all 0.2s ease-out;
146+
}
147147
}
148-
&[open] svg {
148+
&[open] summary svg {
149149
transform: rotate(180deg);
150150
}
151151
}

0 commit comments

Comments
 (0)