From 6b73c52a93faef60a5dc6f3bd990e69d5e817f03 Mon Sep 17 00:00:00 2001 From: jaimergp Date: Fri, 2 Feb 2024 18:48:16 +0100 Subject: [PATCH 1/5] load RSS feed from anaconda.org --- src/components/Packages/index.jsx | 217 +++++++++++++++++++++--------- 1 file changed, 152 insertions(+), 65 deletions(-) diff --git a/src/components/Packages/index.jsx b/src/components/Packages/index.jsx index d56964eae2..216c32a48d 100644 --- a/src/components/Packages/index.jsx +++ b/src/components/Packages/index.jsx @@ -1,4 +1,5 @@ import React, { useState, useEffect } from "react"; +import Admonition from "@docusaurus/theme-classic/lib/theme/Admonition"; // Function to calculate the Levenshtein distance between two strings function levenshteinDistance(a, b) { @@ -49,13 +50,16 @@ function highlightSubstring(str, substr) { } const Packages = () => { - const [packages, setPackages] = useState([]); + const [allPackages, setAllPackages] = useState([]); + const [latestPackages, setLatestPackages] = useState([]); const [searchTerm, setSearchTerm] = useState(""); useEffect(() => { - const fetchData = async () => { + const fetchAllData = async () => { try { - const response = await fetch("https://raw.githubusercontent.com/conda-forge/feedstock-outputs/gh-pages/feedstock-outputs.json"); + const response = await fetch( + "https://raw.githubusercontent.com/conda-forge/feedstock-outputs/single-file/feedstock-outputs.json" + ); const data = await response.json(); if (typeof data === "object" && data !== null) { @@ -65,7 +69,7 @@ const Packages = () => { repos, })); - setPackages(packagesArray); + setAllPackages(packagesArray); } else { console.error("Invalid data format. Expected an object."); } @@ -73,21 +77,48 @@ const Packages = () => { console.error("Error fetching packages:", error); } }; - - fetchData(); + const fetchLatestData = async () => { + try { + const response = await fetch( + "https://conda.anaconda.org/conda-forge/rss.xml" + ); + // parse the RSS feed into an XML document + const xml = await response.text(); + const parser = new DOMParser(); + const doc = parser.parseFromString(xml, "text/xml"); + const titles = doc.querySelectorAll("title"); + const dates = doc.querySelectorAll("pubDate"); + // Convert the object into an array of { name, date } objects + var latestPackagesArray = []; + // The first 'title' element is the feed title, so we skip it + titles.forEach( + (title, index) => + index && + latestPackagesArray.push({ + name: title.textContent.split(" ")[0], + date: dates[index - 1].textContent, + }) + ); + setLatestPackages(latestPackagesArray); + } catch (error) { + console.error("Error fetching latest packages:", error); + } + }; + fetchLatestData(); + fetchAllData(); }, []); const searchTermLower = searchTerm.toLowerCase(); var filteredPackages = []; if (searchTerm.length >= 3) { // For queries with three or more characters, search the entire string for a match - filteredPackages = packages.filter((pkg) => + filteredPackages = allPackages.filter((pkg) => pkg.name.toLowerCase().includes(searchTermLower) ); } else if (searchTerm.length > 0) { // For queries with less than three characters, // only search if the package name starts with the query for performance reasons - filteredPackages = packages.filter((pkg) => + filteredPackages = allPackages.filter((pkg) => pkg.name.toLowerCase().startsWith(searchTermLower) ); } @@ -108,16 +139,122 @@ const Packages = () => { setSearchTerm(event.target.value); }; + var renderResultsBlock; + var resultsPill; + if (searchTerm.length) { + // This is the results table, displayed when the user enters a search term + renderResultsBlock = ( + + + + + + + + + {(filteredPackages.length && + filteredPackages.map((pkg) => ( + + + + + ))) || ( + + + + )} + +
PackageFeedstock(s)
+ + {highlightSubstring(pkg.name, searchTermLower)} + + + {pkg.repos.map((repo) => ( + + + {repo}-feedstock + + +
+
+ ))} +
No packages found
+ ); + resultsPill = ( + + {filteredPackages.length} package(s) found + + ); + } else { + // Without a search term, display the most recently updated feedstocks + renderResultsBlock = ( +
+ +

+ The following packages have been published to{" "} + + Anaconda.org + {" "} + recently. + Check{" "} + + conda-forge/feedstocks + {" "} + for the last updates in our feedstocks. +

+
+ + + + + + + + + + + {latestPackages.map((item, index) => ( + + + + + + + ))} + +
#PackageFeedstockLast updated
{index + 1} + + {item.name} + + ...{item.date}
+
+ ); + resultsPill = ( + + {allPackages.length} packages loaded + + ); + } + return ( -
+

Packages in conda-forge

-
+
-
- - - - - - - - - {(filteredPackages.length && - filteredPackages.map((pkg) => ( - - - - - ))) || ( - - - - )} - -
PackageFeedstock(s)
- - {highlightSubstring(pkg.name, searchTermLower)} - - - {pkg.repos.map((repo) => ( - - - {repo}-feedstock - - -
-
- ))} -
Use the search bar to find packages
+ {renderResultsBlock}
From 4f6350f8ee479f0f465736cd78ebfa126b99bde3 Mon Sep 17 00:00:00 2001 From: jaimergp Date: Mon, 5 Feb 2024 12:22:06 +0100 Subject: [PATCH 2/5] store feedstock-outputs as an object and query it as needed --- src/components/Packages/index.jsx | 98 +++++++++++++++++-------------- 1 file changed, 55 insertions(+), 43 deletions(-) diff --git a/src/components/Packages/index.jsx b/src/components/Packages/index.jsx index 216c32a48d..a6e4d8202a 100644 --- a/src/components/Packages/index.jsx +++ b/src/components/Packages/index.jsx @@ -50,7 +50,7 @@ function highlightSubstring(str, substr) { } const Packages = () => { - const [allPackages, setAllPackages] = useState([]); + const [allPackages, setAllPackages] = useState({}); const [latestPackages, setLatestPackages] = useState([]); const [searchTerm, setSearchTerm] = useState(""); @@ -63,13 +63,7 @@ const Packages = () => { const data = await response.json(); if (typeof data === "object" && data !== null) { - // Convert the object into an array of { pkg_name, repositories } objects - const packagesArray = Object.entries(data).map(([name, repos]) => ({ - name, - repos, - })); - - setAllPackages(packagesArray); + setAllPackages(Object.fromEntries(Object.entries(data).map(([key, value]) => [key.toLowerCase(), value]))); } else { console.error("Invalid data format. Expected an object."); } @@ -110,28 +104,24 @@ const Packages = () => { const searchTermLower = searchTerm.toLowerCase(); var filteredPackages = []; - if (searchTerm.length >= 3) { - // For queries with three or more characters, search the entire string for a match - filteredPackages = allPackages.filter((pkg) => - pkg.name.toLowerCase().includes(searchTermLower) - ); - } else if (searchTerm.length > 0) { - // For queries with less than three characters, - // only search if the package name starts with the query for performance reasons - filteredPackages = allPackages.filter((pkg) => - pkg.name.toLowerCase().startsWith(searchTermLower) - ); + var inclusionCriteria; + if (searchTerm.length > 0) { + if (searchTerm.length >= 3) { + inclusionCriteria = (name) => name.includes(searchTermLower); + } else { + inclusionCriteria = (name) => name.startsWith(searchTermLower); + } + for (const name in allPackages) { + if (inclusionCriteria(name)) { + filteredPackages.push(name); + } + } } + // Sort the filtered packages in place by their Levenshtein distance filteredPackages.sort((a, b) => { - const aDistance = levenshteinDistance( - a.name.toLowerCase(), - searchTermLower - ); - const bDistance = levenshteinDistance( - b.name.toLowerCase(), - searchTermLower - ); + const aDistance = levenshteinDistance(a, searchTermLower); + const bDistance = levenshteinDistance(b, searchTermLower); return aDistance - bDistance; }); @@ -154,19 +144,19 @@ const Packages = () => { {(filteredPackages.length && filteredPackages.map((pkg) => ( - + - {highlightSubstring(pkg.name, searchTermLower)} + {highlightSubstring(pkg, searchTermLower)} - {pkg.repos.map((repo) => ( - + {allPackages[pkg].map((repo) => ( + {

- The following packages have been published to{" "} - + The following packages have recently received updates in{" "} + Anaconda.org - {" "} - recently. - Check{" "} - + + . Check{" "} + conda-forge/feedstocks {" "} - for the last updates in our feedstocks. + for an overview of the latest commits in our feedstocks.

@@ -216,7 +213,7 @@ const Packages = () => { - + @@ -228,11 +225,26 @@ const Packages = () => { {item.name} - + ))} @@ -242,7 +254,7 @@ const Packages = () => { ); resultsPill = ( - {allPackages.length} packages loaded + {Object.keys(allPackages).length} packages loaded ); } From f55c8d102ff2f62e8ca0e616e562a8d9dc5afe41 Mon Sep 17 00:00:00 2001 From: jaimergp Date: Mon, 5 Feb 2024 13:09:14 +0100 Subject: [PATCH 3/5] fix pill foreground contrast --- src/css/custom.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/css/custom.css b/src/css/custom.css index 47bd46de13..76763e4d79 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -63,6 +63,7 @@ --ifm-color-info: #64b5f6; --ifm-color-warning: #ffb74d; --ifm-color-danger: #ff8a65; + --ifm-badge-color: var(--ifm-background-color); --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); --gradient: linear-gradient( 60deg, From 4adba43ea2f604246f10ed40e8dc16c9a26b4476 Mon Sep 17 00:00:00 2001 From: jaimergp Date: Mon, 5 Feb 2024 13:10:22 +0100 Subject: [PATCH 4/5] fix htmlFor association --- src/components/Packages/index.jsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/components/Packages/index.jsx b/src/components/Packages/index.jsx index 76297a619d..cc3e2d93ed 100644 --- a/src/components/Packages/index.jsx +++ b/src/components/Packages/index.jsx @@ -273,8 +273,9 @@ const Packages = () => {

Packages in conda-forge

-
# PackageFeedstockFeedstock(s) Last updated
... + {(allPackages[item.name.toLowerCase()] || []).map((repo) => ( + + + {repo}-feedstock + +
+
+ ))} +
{item.date}
); resultsPill = ( - + {filteredPackages.length} package(s) found ); @@ -260,7 +260,7 @@ const Packages = () => {
); resultsPill = ( - + {Object.keys(allPackages).length} packages loaded ); diff --git a/src/css/custom.css b/src/css/custom.css index 76763e4d79..7e7b7e1037 100644 --- a/src/css/custom.css +++ b/src/css/custom.css @@ -63,7 +63,7 @@ --ifm-color-info: #64b5f6; --ifm-color-warning: #ffb74d; --ifm-color-danger: #ff8a65; - --ifm-badge-color: var(--ifm-background-color); + --ifm-badge-color: var(--ifm-color-black); --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); --gradient: linear-gradient( 60deg,