feat: use GitHub API for desktop download links#91
Conversation
…on version - Create githubRelease.ts utility to fetch latest release from GitHub API - Update downloads page to use dynamic GitHub release data - Add graceful fallback to package.json version if API fails - Include loading indicator while fetching release info - Fixes issue where NPM version bumps before desktop releases Fixes #89 Co-authored-by: AnthonyRonning <AnthonyRonning@users.noreply.github.com>
|
""" WalkthroughThe download page logic was refactored to fetch the latest release version and download URLs for desktop platforms directly from GitHub at runtime, replacing the previous approach that used static URLs based on the local package version. A new utility module was added to handle GitHub API interactions and extract release information. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant DownloadPage
participant githubReleaseUtil as githubRelease.ts
participant GitHubAPI
User->>DownloadPage: Visit downloads page
DownloadPage->>githubReleaseUtil: getLatestDownloadInfo()
githubReleaseUtil->>GitHubAPI: Fetch latest release JSON
GitHubAPI-->>githubReleaseUtil: Return release data
githubReleaseUtil-->>DownloadPage: Return download URLs, version, release URL
DownloadPage-->>User: Render download links and version info
Assessment against linked issues
Assessment against linked issues: Out-of-scope changesNo out-of-scope changes found. Possibly related PRs
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
⏰ Context from checks skipped due to timeout of 90000ms (1)
✨ Finishing Touches
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
PR Summary
Added GitHub release API integration for accurate desktop download links, replacing NPM package version with dynamic latest release data.
- Added
frontend/src/utils/githubRelease.tswith typed interfaces and error handling for fetching release data - Updated
frontend/src/routes/downloads.tsxto use dynamic GitHub API data with loading states and fallback logic - Implemented graceful fallback to package.json version if GitHub API fails
- Added proper error handling and type safety for API responses
- Structured download URL generation to support all desktop platforms consistently
2 file(s) reviewed, 3 comment(s)
Edit PR Review Bot Settings | Greptile
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (5)
frontend/src/utils/githubRelease.ts (2)
66-71: Handle potential edge cases in download URL construction.The current implementation assumes specific asset naming patterns but doesn't handle cases where assets might be missing or have different names.
Consider making the URL construction more robust by checking the actual assets in the release:
export async function getLatestDownloadInfo(): Promise<DownloadInfo | null> { const release = await fetchLatestRelease(); if (!release) { return null; } + + // Fetch full release data with assets if needed + const fullRelease = await fetch(`https://api.github.com/repos/OpenSecretCloud/Maple/releases/latest`); + const releaseData = await fullRelease.json(); + + // Find actual asset URLs instead of constructing them + const findAsset = (pattern: RegExp) => + releaseData.assets?.find(asset => pattern.test(asset.name))?.browser_download_url; // Extract version number from tag (remove 'v' prefix if present) const version = release.tag_name.startsWith("v") ? release.tag_name.slice(1) : release.tag_name; const baseDownloadUrl = `https://github.com/OpenSecretCloud/Maple/releases/download/${release.tag_name}`; return { version, tagName: release.tag_name, downloadUrls: { - macOS: `${baseDownloadUrl}/Maple_${version}_universal.dmg`, - linuxAppImage: `${baseDownloadUrl}/Maple_${version}_amd64.AppImage`, - linuxDeb: `${baseDownloadUrl}/Maple_${version}_amd64.deb`, - linuxRpm: `${baseDownloadUrl}/Maple-${version}-1.x86_64.rpm`, + macOS: findAsset(/Maple_.*_universal\.dmg$/) || `${baseDownloadUrl}/Maple_${version}_universal.dmg`, + linuxAppImage: findAsset(/Maple_.*_amd64\.AppImage$/) || `${baseDownloadUrl}/Maple_${version}_amd64.AppImage`, + linuxDeb: findAsset(/Maple_.*_amd64\.deb$/) || `${baseDownloadUrl}/Maple_${version}_amd64.deb`, + linuxRpm: findAsset(/Maple-.*\.x86_64\.rpm$/) || `${baseDownloadUrl}/Maple-${version}-1.x86_64.rpm`, }, releaseUrl: release.html_url, }; }
5-10: Consider adding more fields to GitHubRelease interface.The interface is minimal but functional. Consider adding fields that might be useful for future enhancements.
interface GitHubRelease { tag_name: string; name: string; published_at: string; html_url: string; + prerelease: boolean; + draft: boolean; + assets?: Array<{ + name: string; + browser_download_url: string; + size: number; + }>; }frontend/src/routes/downloads.tsx (3)
31-36: Consider consolidating related state into a single object.Multiple related state variables can lead to synchronization issues and make the code harder to maintain.
Consider consolidating the download-related state:
- const [downloadUrls, setDownloadUrls] = useState<DownloadUrls>(FALLBACK_URLS); - const [currentVersion, setCurrentVersion] = useState<string>(FALLBACK_VERSION); - const [releaseUrl, setReleaseUrl] = useState<string>( - `https://github.com/OpenSecretCloud/Maple/releases/tag/${FALLBACK_TAG}` - ); - const [isLoading, setIsLoading] = useState<boolean>(true); + const [releaseState, setReleaseState] = useState({ + downloadUrls: FALLBACK_URLS, + currentVersion: FALLBACK_VERSION, + releaseUrl: `https://github.com/OpenSecretCloud/Maple/releases/tag/${FALLBACK_TAG}`, + isLoading: true, + error: null as string | null + });Then update the useEffect accordingly:
if (downloadInfo) { - setDownloadUrls(downloadInfo.downloadUrls); - setCurrentVersion(downloadInfo.version); - setReleaseUrl(downloadInfo.releaseUrl); + setReleaseState(prev => ({ + ...prev, + downloadUrls: downloadInfo.downloadUrls, + currentVersion: downloadInfo.version, + releaseUrl: downloadInfo.releaseUrl, + error: null + })); } } catch (error) { console.error("Failed to load latest release info:", error); - // Keep fallback values + setReleaseState(prev => ({ + ...prev, + error: "Failed to load latest release information" + })); } finally { - setIsLoading(false); + setReleaseState(prev => ({ ...prev, isLoading: false })); }
163-164: Enhance the loading indicator for better UX.The current loading indicator is subtle and might not be noticeable to users. Consider making it more prominent or replacing it with a skeleton loader.
<p className="text-sm"> - Current version: <span className="font-mono text-foreground">{currentVersion}</span> - {isLoading && <span className="text-[hsl(var(--marketing-text-muted))]"> (loading...)</span>} •{" "} + Current version: {isLoading ? ( + <span className="inline-block w-16 h-4 bg-[hsl(var(--marketing-text-muted))]/20 rounded animate-pulse"></span> + ) : ( + <span className="font-mono text-foreground">{currentVersion}</span> + )} •{" "} <a href={releaseUrl} className="text-[hsl(var(--purple))] hover:underline" target="_blank" rel="noopener noreferrer" > - Release notes + {isLoading ? "Loading..." : "Release notes"} </a> </p>
47-49: Consider showing error messages to users.Currently, API errors are only logged to the console. Users won't know if something went wrong and might assume the fallback URLs are the latest.
Add error state and display it to users:
} catch (error) { console.error("Failed to load latest release info:", error); - // Keep fallback values + setReleaseState(prev => ({ + ...prev, + error: "Unable to fetch latest release information. Showing fallback version." + })); } finally {Then display the error message in the UI:
<div className="text-center mt-8 space-y-2 text-[hsl(var(--marketing-text-muted))] max-w-2xl mx-auto"> + {error && ( + <p className="text-orange-500 text-sm mb-2"> + ⚠️ {error} + </p> + )} <p>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
frontend/src/routes/downloads.tsx(6 hunks)frontend/src/utils/githubRelease.ts(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
- GitHub Check: build-ios
- GitHub Check: build-macos (universal-apple-darwin)
- GitHub Check: build-linux
- GitHub Check: browseruse-tests
🔇 Additional comments (3)
frontend/src/utils/githubRelease.ts (1)
61-71:Details
✅ Verification successful
Verify download URL patterns match actual GitHub release assets.
The constructed download URLs follow specific naming patterns. Ensure these patterns match the actual file names in your GitHub releases.
Please verify that these URL patterns are correct by checking a recent release:
🏁 Script executed:
#!/bin/bash # Description: Verify that the constructed download URLs match actual GitHub release assets # Fetch the latest release data and extract asset names echo "Fetching latest release assets..." gh api repos/OpenSecretCloud/Maple/releases/latest --jq '.assets[].name' echo -e "\nExpected patterns based on the code:" echo "- Maple_VERSION_universal.dmg (macOS)" echo "- Maple_VERSION_amd64.AppImage (Linux AppImage)" echo "- Maple_VERSION_amd64.deb (Linux Deb)" echo "- Maple-VERSION-1.x86_64.rpm (Linux RPM)"Length of output: 807
Download URL patterns verified
Confirmed that for the latest release (v1.0.5), the generated URLs for macOS (.dmg), Linux AppImage (.AppImage), .deb, and RPM exactly match the asset names on GitHub. No changes required.frontend/src/routes/downloads.tsx (2)
8-9: Good addition of required imports.The imports for React hooks and the new GitHub release utility are correctly added.
19-28: Excellent fallback mechanism implementation.The fallback constants provide a robust safety net if the GitHub API fails, ensuring users can still download the application.
Add runtime validation to ensure the GitHub releases API response contains the expected fields before casting to GitHubRelease interface. This prevents runtime errors from malformed API responses and provides better error messages for debugging. Co-authored-by: AnthonyRonning <AnthonyRonning@users.noreply.github.com>
Deploying maple with
|
| Latest commit: |
1381e14
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://66c81b31.maple-ca8.pages.dev |
| Branch Preview URL: | https://claude-issue-89-20250602-170.maple-ca8.pages.dev |
Fixes #89
This PR updates the downloads page to use GitHub's latest release API instead of the NPM package.json version for constructing desktop download links.
Changes
githubRelease.tsutility to fetch latest GitHub releaseBenefits
Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Refactor