1
1
import React , { useState , useEffect } from "react" ;
2
+ import Admonition from "@docusaurus/theme-classic/lib/theme/Admonition" ;
2
3
3
4
// Function to calculate the Levenshtein distance between two strings
4
5
function levenshteinDistance ( a , b ) {
@@ -49,13 +50,16 @@ function highlightSubstring(str, substr) {
49
50
}
50
51
51
52
const Packages = ( ) => {
52
- const [ packages , setPackages ] = useState ( [ ] ) ;
53
+ const [ allPackages , setAllPackages ] = useState ( [ ] ) ;
54
+ const [ latestPackages , setLatestPackages ] = useState ( [ ] ) ;
53
55
const [ searchTerm , setSearchTerm ] = useState ( "" ) ;
54
56
55
57
useEffect ( ( ) => {
56
- const fetchData = async ( ) => {
58
+ const fetchAllData = async ( ) => {
57
59
try {
58
- const response = await fetch ( "https://raw.githubusercontent.com/conda-forge/feedstock-outputs/gh-pages/feedstock-outputs.json" ) ;
60
+ const response = await fetch (
61
+ "https://raw.githubusercontent.com/conda-forge/feedstock-outputs/single-file/feedstock-outputs.json"
62
+ ) ;
59
63
const data = await response . json ( ) ;
60
64
61
65
if ( typeof data === "object" && data !== null ) {
@@ -65,29 +69,56 @@ const Packages = () => {
65
69
repos,
66
70
} ) ) ;
67
71
68
- setPackages ( packagesArray ) ;
72
+ setAllPackages ( packagesArray ) ;
69
73
} else {
70
74
console . error ( "Invalid data format. Expected an object." ) ;
71
75
}
72
76
} catch ( error ) {
73
77
console . error ( "Error fetching packages:" , error ) ;
74
78
}
75
79
} ;
76
-
77
- fetchData ( ) ;
80
+ const fetchLatestData = async ( ) => {
81
+ try {
82
+ const response = await fetch (
83
+ "https://conda.anaconda.org/conda-forge/rss.xml"
84
+ ) ;
85
+ // parse the RSS feed into an XML document
86
+ const xml = await response . text ( ) ;
87
+ const parser = new DOMParser ( ) ;
88
+ const doc = parser . parseFromString ( xml , "text/xml" ) ;
89
+ const titles = doc . querySelectorAll ( "title" ) ;
90
+ const dates = doc . querySelectorAll ( "pubDate" ) ;
91
+ // Convert the object into an array of { name, date } objects
92
+ var latestPackagesArray = [ ] ;
93
+ // The first 'title' element is the feed title, so we skip it
94
+ titles . forEach (
95
+ ( title , index ) =>
96
+ index &&
97
+ latestPackagesArray . push ( {
98
+ name : title . textContent . split ( " " ) [ 0 ] ,
99
+ date : dates [ index - 1 ] . textContent ,
100
+ } )
101
+ ) ;
102
+ setLatestPackages ( latestPackagesArray ) ;
103
+ } catch ( error ) {
104
+ console . error ( "Error fetching latest packages:" , error ) ;
105
+ }
106
+ } ;
107
+ fetchLatestData ( ) ;
108
+ fetchAllData ( ) ;
78
109
} , [ ] ) ;
79
110
80
111
const searchTermLower = searchTerm . toLowerCase ( ) ;
81
112
var filteredPackages = [ ] ;
82
113
if ( searchTerm . length >= 3 ) {
83
114
// For queries with three or more characters, search the entire string for a match
84
- filteredPackages = packages . filter ( ( pkg ) =>
115
+ filteredPackages = allPackages . filter ( ( pkg ) =>
85
116
pkg . name . toLowerCase ( ) . includes ( searchTermLower )
86
117
) ;
87
118
} else if ( searchTerm . length > 0 ) {
88
119
// For queries with less than three characters,
89
120
// only search if the package name starts with the query for performance reasons
90
- filteredPackages = packages . filter ( ( pkg ) =>
121
+ filteredPackages = allPackages . filter ( ( pkg ) =>
91
122
pkg . name . toLowerCase ( ) . startsWith ( searchTermLower )
92
123
) ;
93
124
}
@@ -108,78 +139,134 @@ const Packages = () => {
108
139
setSearchTerm ( event . target . value ) ;
109
140
} ;
110
141
142
+ var renderResultsBlock ;
143
+ var resultsPill ;
144
+ if ( searchTerm . length ) {
145
+ // This is the results table, displayed when the user enters a search term
146
+ renderResultsBlock = (
147
+ < table >
148
+ < thead >
149
+ < tr >
150
+ < th > Package</ th >
151
+ < th > Feedstock(s)</ th >
152
+ </ tr >
153
+ </ thead >
154
+ < tbody >
155
+ { ( filteredPackages . length &&
156
+ filteredPackages . map ( ( pkg ) => (
157
+ < tr key = { pkg . name } >
158
+ < td >
159
+ < a
160
+ href = { `https://anaconda.org/conda-forge/${ pkg . name } ` }
161
+ target = "_blank"
162
+ title = { `View ${ pkg . name } on anaconda.org` }
163
+ >
164
+ { highlightSubstring ( pkg . name , searchTermLower ) }
165
+ </ a >
166
+ </ td >
167
+ < td >
168
+ { pkg . repos . map ( ( repo ) => (
169
+ < span >
170
+ < a
171
+ href = { `https://github.com/conda-forge/${ repo } -feedstock` }
172
+ target = "_blank"
173
+ title = { `View ${ repo } -feedstock on GitHub` }
174
+ >
175
+ { repo } -feedstock
176
+ </ a >
177
+
178
+ < br />
179
+ </ span >
180
+ ) ) }
181
+ </ td >
182
+ </ tr >
183
+ ) ) ) || (
184
+ < tr >
185
+ < td colSpan = "2" > No packages found</ td >
186
+ </ tr >
187
+ ) }
188
+ </ tbody >
189
+ </ table >
190
+ ) ;
191
+ resultsPill = (
192
+ < span className = "badge badge--info margin-left--sm" >
193
+ { filteredPackages . length } package(s) found
194
+ </ span >
195
+ ) ;
196
+ } else {
197
+ // Without a search term, display the most recently updated feedstocks
198
+ renderResultsBlock = (
199
+ < div >
200
+ < Admonition type = "tip" coll >
201
+ < p >
202
+ The following packages have been published to{ " " }
203
+ < a href = "https://anaconda.org/conda-forge" target = "_blank" >
204
+ Anaconda.org
205
+ </ a > { " " }
206
+ recently.
207
+ Check{ " " }
208
+ < a href = "https://github.com/conda-forge/feedstock/commits" >
209
+ conda-forge/feedstocks
210
+ </ a > { " " }
211
+ for the last updates in our feedstocks.
212
+ </ p >
213
+ </ Admonition >
214
+ < table >
215
+ < thead >
216
+ < tr >
217
+ < th > #</ th >
218
+ < th > Package</ th >
219
+ < th > Feedstock</ th >
220
+ < th > Last updated</ th >
221
+ </ tr >
222
+ </ thead >
223
+ < tbody >
224
+ { latestPackages . map ( ( item , index ) => (
225
+ < tr key = { item . name } >
226
+ < td > { index + 1 } </ td >
227
+ < td >
228
+ < a
229
+ href = { `https://anaconda.org/conda-forge/${ item . name } ` }
230
+ target = "_blank"
231
+ >
232
+ { item . name }
233
+ </ a >
234
+ </ td >
235
+ < td > ...</ td >
236
+ < td > { item . date } </ td >
237
+ </ tr >
238
+ ) ) }
239
+ </ tbody >
240
+ </ table >
241
+ </ div >
242
+ ) ;
243
+ resultsPill = (
244
+ < span className = "badge badge--success margin-left--sm" >
245
+ { allPackages . length } packages loaded
246
+ </ span >
247
+ ) ;
248
+ }
249
+
111
250
return (
112
- < div
113
- className = { [ "container" , "margin-vert--lg" ] . join ( " " ) }
114
- >
251
+ < div className = { [ "container" , "margin-vert--lg" ] . join ( " " ) } >
115
252
< div className = "row" >
116
253
< main className = "col col--12" >
117
254
< h1 > Packages in conda-forge</ h1 >
118
- < form className = "margin-vert--md" >
255
+ < form id = "filterPackages" className = "margin-vert--md" >
119
256
< div className = "navbar__search" >
120
- < label htmlFor = "search " >
257
+ < label htmlFor = "filterPackages " >
121
258
< input
122
259
type = "text"
123
260
placeholder = "Filter items..."
124
261
value = { searchTerm }
125
262
onChange = { handleSearchChange }
126
263
className = "navbar__search-input"
127
264
/>
128
- { ( searchTerm . length && (
129
- < span class = "badge badge--info margin-left--sm" >
130
- { filteredPackages . length } package(s) found
131
- </ span >
132
- ) ) || (
133
- < span class = "badge badge--success margin-left--sm" >
134
- { packages . length } packages loaded
135
- </ span >
136
- ) }
265
+ { resultsPill }
137
266
</ label >
138
267
</ div >
139
268
</ form >
140
- < table >
141
- < thead >
142
- < tr >
143
- < th > Package</ th >
144
- < th > Feedstock(s)</ th >
145
- </ tr >
146
- </ thead >
147
- < tbody >
148
- { ( filteredPackages . length &&
149
- filteredPackages . map ( ( pkg ) => (
150
- < tr key = { pkg . name } >
151
- < td >
152
- < a
153
- href = { `https://anaconda.org/conda-forge/${ pkg . name } ` }
154
- target = "_blank"
155
- title = { `View ${ pkg . name } on anaconda.org` }
156
- >
157
- { highlightSubstring ( pkg . name , searchTermLower ) }
158
- </ a >
159
- </ td >
160
- < td >
161
- { pkg . repos . map ( ( repo ) => (
162
- < span >
163
- < a
164
- href = { `https://github.com/conda-forge/${ repo } -feedstock` }
165
- target = "_blank"
166
- title = { `View ${ repo } -feedstock on GitHub` }
167
- >
168
- { repo } -feedstock
169
- </ a >
170
-
171
- < br />
172
- </ span >
173
- ) ) }
174
- </ td >
175
- </ tr >
176
- ) ) ) || (
177
- < tr >
178
- < td colSpan = "2" > Use the search bar to find packages</ td >
179
- </ tr >
180
- ) }
181
- </ tbody >
182
- </ table >
269
+ { renderResultsBlock }
183
270
</ main >
184
271
</ div >
185
272
</ div >
0 commit comments