Skip to content

Commit

Permalink
Merge pull request #23 from PelicanPlatform/fix-download-card
Browse files Browse the repository at this point in the history
Download card improvement
  • Loading branch information
CannonLock authored May 29, 2024
2 parents 579b949 + 023bf1e commit 2441f17
Show file tree
Hide file tree
Showing 7 changed files with 222 additions and 144 deletions.
113 changes: 69 additions & 44 deletions components/DownloadsComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
"use client"
import React, { useState, useEffect, useMemo } from 'react';
import { Box, CircularProgress } from '@mui/material';
import { Box, CircularProgress, MenuItem, Select, SelectChangeEvent, Typography } from '@mui/material';
import fetchFilteredReleases from "../utils/fetchReleases";
import { FilteredRelease } from '../utils/types';
import {OperatingSystems, Architectures} from './Filters';
import { FilteredRelease, ArchEnums, OSEnums, SemverRegex } from '../utils/types';
import {OperatingSystems, Architectures, Versions} from './Filters';
import ReleasesTable from './ReleasesTable';
import data from '../public/static/releases-table-data.json';
import { DarkLightContainer } from '@/utils/darkLightContainer';
import { useTheme } from '@mui/material/styles';
import { parseEnum } from '@/utils/utils';

const architectures = {
"PowerPC": ["ppc64el", "ppc64le"],
"ARM64": ["aarch64", "arm64"],
"AMD64": ["amd64", "x86_64"]
};
interface optionMatrix {
arch: ArchEnums | ""
os: OSEnums | ""
version: string
}

const DownloadsComponent: React.FC = () => {
const [originalData, setOriginalData] = useState<FilteredRelease[]>([]);
const [loading, setLoading] = useState<boolean>(true);
const [error, setError] = useState<string | null>(null);
const [selectedOptions, setSelectedOptions] = React.useState({
arch: 'AMD64',
os: 'linux',
const [versions, setVersions] = useState([])
const [selectedOptions, setSelectedOptions] = useState<optionMatrix>({
arch: ArchEnums.X86_64,
os: OSEnums.Linux,
version: ""
});

const theme = useTheme();
Expand All @@ -33,7 +36,7 @@ const DownloadsComponent: React.FC = () => {
if (newArch !== selectedOptions.arch) {
setSelectedOptions(prevOptions => ({
...prevOptions,
arch: newArch || ''
arch: newArch as ArchEnums || ''
}));
}
};
Expand All @@ -45,7 +48,7 @@ const DownloadsComponent: React.FC = () => {
if (newOs !== selectedOptions.os) {
setSelectedOptions(prevOptions => ({
...prevOptions,
os: newOs || ''
os: newOs as OSEnums || ''
}));
}
};
Expand All @@ -56,44 +59,71 @@ const DownloadsComponent: React.FC = () => {
try {
const releases = await fetchFilteredReleases(); // This function should return an array of FilteredRelease
setOriginalData(releases);
console.log(releases);
setSelectedOptions((prev) => ({...prev, version: prev.version ? prev.version : releases[0].version}))
setVersions(releases.map(release => release.version).filter(version => version >= "v7.6.5"))
} catch (e) {
setError('Failed to fetch release assets');
console.error(e);
} finally {
setLoading(false);
}
};

const params = new URLSearchParams(window?.location.search)
const qVersion = params.get("version")
const qArch = parseEnum(params.get("arch"), ArchEnums)
const qOS = parseEnum(params.get("os"), OSEnums)
const queryMatrix: optionMatrix = {
arch: qArch || '',
os: qOS || '',
version: SemverRegex.test(qVersion) ? qVersion : ""
}
setSelectedOptions((prev) => (
{
arch: queryMatrix.arch ? queryMatrix.arch : prev.arch,
os: queryMatrix.os ? queryMatrix.os : prev.os,
version: queryMatrix.version ? queryMatrix.version : prev.version,
}
))

fetchAssets();
}, []);


const filteredData = useMemo(() => {
const architectureIdentifiers = selectedOptions.arch ? (architectures[selectedOptions.arch] || []) : [];
const selectedArch = selectedOptions.arch;
const filteredByVersion = structuredClone(originalData.filter((release) => release.version == selectedOptions.version)[0])
if (!filteredByVersion) {
return undefined
}

// Now, filter assets within those releases based on the selected OS and Arch
const releasesWithFilteredAssets = originalData.map(release => {
const filteredAssets = release.assets.filter(asset => {
const osMatch = !selectedOptions.os || asset.operatingSystem.toLowerCase().includes(selectedOptions.os.toLowerCase());
const archMatch = !selectedOptions.arch || architectureIdentifiers.some(archIdentifier => asset.architecture.includes(archIdentifier));
const filteredAssets = filteredByVersion.assets.filter(asset => {
const osMatch = !selectedOptions.os || asset.osInternal.toLowerCase().includes(selectedOptions.os.toLowerCase());
const archMatch = !selectedArch || asset.architecture === selectedArch;

return osMatch && archMatch;
})
.sort((a, b) => {
// Sort by file extension
const extA = a.name.split('.').pop();
const extB = b.name.split('.').pop();
if (extA < extB) return -1;
if (extA > extB) return 1;

// If extensions are the same, sort by name
return a.name.localeCompare(b.name);
// Sort by OS
const byOS = a.osDisplayed.localeCompare(b.osDisplayed)
if (byOS === 0) {
if (a.specialPackage && b.specialPackage) {
return a.name.localeCompare(b.name)
} else if (a.specialPackage && !b.specialPackage) {
return 1
} else {
return -1
}
} else {
return byOS
}
});

// Return the release with the filtered assets
return { ...release, assets: filteredAssets };
}).filter(release => release.assets.length > 0); // Keep only releases with matching assets

return releasesWithFilteredAssets;
}, [selectedOptions.arch, selectedOptions.os, originalData]);

filteredByVersion.assets = filteredAssets
return filteredByVersion;

}, [selectedOptions, originalData]);


const renderContent = () => {
Expand All @@ -110,18 +140,15 @@ const DownloadsComponent: React.FC = () => {
alignItems: 'center',
justifyContent: 'center',
width: '100%',
margin: theme.spacing(1),
[theme.breakpoints.down('sm')]: {
flexDirection: 'column',
},
}}>
<OperatingSystems handle={handleOs} defaultOs={selectedOptions.os} defaultArch={selectedOptions.arch} data={data.operating_systems} />
<Architectures handle={handleArch} defaultArch={selectedOptions.arch} defaultOs={selectedOptions.os} archData={architectures} />
<Versions handleChange={(e) => {setSelectedOptions((prev) => ({...prev, version: e.target.value}))}} versions={versions} value={selectedOptions.version}/>
<OperatingSystems handle={handleOs} defaultOs={selectedOptions.os} defaultArch={selectedOptions.arch} data={Object.values(OSEnums)} />
<Architectures handle={handleArch} defaultArch={selectedOptions.arch} defaultOs={selectedOptions.os} archs={Object.values(ArchEnums)} />
</Box>
{filteredData.map(release => (
<ReleasesTable key={release.version} release={release} data={data.table_rows} />
))
}
{filteredData && <ReleasesTable key={filteredData.version} release={filteredData} rowNames={data.table_rows} />}
</>
);
}
Expand All @@ -135,9 +162,7 @@ const DownloadsComponent: React.FC = () => {
alignItems: 'center',
margin: '1em auto',
overflow: 'auto',
[theme.breakpoints.down('md')]: {
padding: theme.spacing(2),
},
padding: theme.spacing(1),
}}>
{renderContent()}
</Box>
Expand Down
56 changes: 23 additions & 33 deletions components/Filters.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,24 @@
import React from 'react';
import { Box, ToggleButton, ToggleButtonGroup, Typography } from '@mui/material';
import { Box, ToggleButton, ToggleButtonGroup, Typography, Select, MenuItem, SelectChangeEvent } from '@mui/material';
import { compatibilityRules, ArchitecturesProps, OperatingSystemsProps, VersionProps } from '../utils/types';

export const Architectures:React.FC<ArchitecturesProps> = ({handle, defaultArch, archData, defaultOs}) => {

export const Versions:React.FC<VersionProps> = ({handleChange, value, versions}) => {
return (
<Box sx={{ display: "flex", flexDirection:"column", alignItems:"center", margin: "0 20px 0 0"}}>
<Typography variant="overline" display="block" gutterBottom>Versions</Typography>
<Select size='small' aria-label='Version Selection' value={value} onChange={handleChange}>
{versions.map((version) => {
return (
<MenuItem key={version} value={version}>{version}</MenuItem>
)
})}
</Select>
</Box>
)
}

export const Architectures:React.FC<ArchitecturesProps> = ({handle, defaultArch, archs, defaultOs}) => {

const isDisabled = (arch: string) => {
// If an OS is selected, check if the current arch is compatible
Expand All @@ -12,10 +28,6 @@ export const Architectures:React.FC<ArchitecturesProps> = ({handle, defaultArch,
return false;
};

const architectureOptions = Object.entries(archData).map(([key, value]) => ({
label: key,
value: value.join(', ') // Joining all chipset identifiers for a given architecture
}));
return (
<Box sx={{ display: "flex", flexDirection:"column", alignItems:"center", margin: "0 10px"}}>
<Typography variant="overline" display="block" gutterBottom>
Expand All @@ -29,13 +41,13 @@ export const Architectures:React.FC<ArchitecturesProps> = ({handle, defaultArch,
onChange={handle}
size="small"
>
{architectureOptions.map((option) => (
{archs.map((option) => (
<ToggleButton
key={option.label}
value={option.label}
disabled={isDisabled(option.label)}
key={option}
value={option}
disabled={isDisabled(option)}
>
{option.label}
{option}
</ToggleButton>
))}
</ToggleButtonGroup>
Expand Down Expand Up @@ -78,25 +90,3 @@ export const OperatingSystems:React.FC<OperatingSystemsProps> = ({handle, defaul
)
}

export const Version:React.FC<VersionProps> = ({handle, defaultVersion, data}) => {
return (
<Box sx={{ display: "flex", flexDirection:"column", alignItems:"center", margin: "0 0 0 10px"}}>
<Typography variant="overline" display="block" gutterBottom>
Versions
</Typography>
<ToggleButtonGroup
color="primary"
value={defaultVersion}
exclusive
aria-label="Version"
onChange={handle}
size='small'
>
{data.map((version) => (
<ToggleButton key={version} value={version}>{version}</ToggleButton>
))}
</ToggleButtonGroup>
</Box>

)
}
33 changes: 22 additions & 11 deletions components/ReleasesTable.tsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,44 @@
import React from 'react';
import {
Typography, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, Link, Tooltip}
Typography, Table, TableBody, TableCell, TableContainer, TableHead, TableRow, Paper, Link, Tooltip,
Chip}
from '@mui/material';
import InfoIcon from '@mui/icons-material/Info';
import { ReleasesTableProps } from '../utils/types';

const ReleasesTable: React.FC<ReleasesTableProps> = ({ release , data }) => {
const OSDFNote = "This package is compatible with Open Science Data Federation (OSDF). Download this package if you plan to use it in OSDF."
const ServerNote = "This package includes Pelican origin/cache server dependencies. Download this package if you want to serve a Pelican origin or cache server."

const ReleasesTable: React.FC<ReleasesTableProps> = ({ release , rowNames }) => {
return(
<TableContainer component={Paper} sx={{marginTop:"15px"}}>
<Table aria-label="simple table">
<Table aria-label="download table">
<TableHead>
<TableRow>
{data.map((tableRows) => (
<TableCell align='center' key={tableRows}><Typography variant='h6' >{tableRows}</Typography></TableCell>
))}
</TableRow>
<TableRow>
{rowNames.map((rowName) => (
<TableCell align='center' key={rowName}><Typography variant='h6' >{rowName}</Typography></TableCell>
))}
</TableRow>
</TableHead>
<TableBody>
{release.assets.map((asset, index) => (
<TableRow key={index}>
<TableCell align='center'>{release.version}</TableCell>
<TableCell align='center'>{asset.architecture}</TableCell>
<TableCell align='center'>{asset.osDisplayed}</TableCell>
<TableCell align='center'>
<Link href={asset.downloadUrl}>
{asset.name}
</Link>
<Tooltip title={asset.packageDescription} placement='right' arrow>
<InfoIcon sx={{fontSize:"20px", marginLeft:"4px"}} />
</Tooltip>
</TableCell>
<TableCell>
{
asset.specialPackage && (
<Tooltip title={asset.specialPackage === "OSDF" ? OSDFNote : ServerNote} placement='right' arrow>
<Chip label={asset.specialPackage} color="primary" variant="outlined"/>
</Tooltip>
)
}
</TableCell>
</TableRow>
))}
Expand Down
10 changes: 3 additions & 7 deletions public/static/releases-table-data.json
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
{
"operating_systems": [
"linux",
"darwin",
"windows"
],

"table_rows": [
"Version",
"Architecture",
"File"
"OS",
"File",
"Note"
]
}
Loading

0 comments on commit 2441f17

Please sign in to comment.