mirror of
https://github.com/StarFleetCPTN/GoMFT.git
synced 2026-09-08 15:41:20 +02:00
feat: Implement version checking and update notification in dashboard
- Added functionality to fetch the latest GitHub release version. - Enhanced the dashboard to display current and latest version information. - Updated the version comparison logic to handle special cases and non-semver formats. - Improved the dashboard template to link to the latest release on GitHub.
This commit is contained in:
@@ -50,6 +50,11 @@ func isNewerVersionAvailable(current, latest string) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Special case for DEV versions - always show update available
|
||||||
|
if current == "DEV" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
// Strip 'v' prefix if present for comparison
|
// Strip 'v' prefix if present for comparison
|
||||||
if strings.HasPrefix(current, "v") {
|
if strings.HasPrefix(current, "v") {
|
||||||
current = current[1:]
|
current = current[1:]
|
||||||
@@ -62,6 +67,12 @@ func isNewerVersionAvailable(current, latest string) bool {
|
|||||||
currentParts := strings.Split(current, ".")
|
currentParts := strings.Split(current, ".")
|
||||||
latestParts := strings.Split(latest, ".")
|
latestParts := strings.Split(latest, ".")
|
||||||
|
|
||||||
|
// Handle non-semver format in either version
|
||||||
|
if len(currentParts) < 2 || len(latestParts) < 2 {
|
||||||
|
// If format doesn't match semver pattern, do string comparison
|
||||||
|
return current != latest && latest != ""
|
||||||
|
}
|
||||||
|
|
||||||
// Compare major, minor, patch versions
|
// Compare major, minor, patch versions
|
||||||
for i := 0; i < len(currentParts) && i < len(latestParts); i++ {
|
for i := 0; i < len(currentParts) && i < len(latestParts); i++ {
|
||||||
// Parse to integers
|
// Parse to integers
|
||||||
@@ -310,7 +321,7 @@ templ Dashboard(ctx context.Context, data DashboardData) {
|
|||||||
<i class="fas fa-exclamation-triangle w-3 h-3 mr-1"></i>
|
<i class="fas fa-exclamation-triangle w-3 h-3 mr-1"></i>
|
||||||
{ data.CurrentVersion }
|
{ data.CurrentVersion }
|
||||||
</span>
|
</span>
|
||||||
<a href="https://github.com/starfleetcptn/gomft/releases/tag/{ data.LatestVersion }" target="_blank"
|
<a href={ templ.SafeURL(fmt.Sprintf("https://github.com/starfleetcptn/gomft/releases/tag/%s", data.LatestVersion)) } target="_blank"
|
||||||
class="bg-green-100 text-green-800 text-xs font-medium inline-flex items-center px-2.5 py-0.5 rounded-full dark:bg-green-900 dark:text-green-300 hover:bg-green-200 dark:hover:bg-green-800">
|
class="bg-green-100 text-green-800 text-xs font-medium inline-flex items-center px-2.5 py-0.5 rounded-full dark:bg-green-900 dark:text-green-300 hover:bg-green-200 dark:hover:bg-green-800">
|
||||||
<i class="fas fa-arrow-circle-up w-3 h-3 mr-1"></i>
|
<i class="fas fa-arrow-circle-up w-3 h-3 mr-1"></i>
|
||||||
{ data.LatestVersion } Available
|
{ data.LatestVersion } Available
|
||||||
|
|||||||
@@ -364,7 +364,7 @@ templ LayoutWithContext(title string, ctx context.Context) {
|
|||||||
hx-get="/notifications/dropdown"
|
hx-get="/notifications/dropdown"
|
||||||
hx-trigger="click once"
|
hx-trigger="click once"
|
||||||
hx-target="#notification-dropdown-content"
|
hx-target="#notification-dropdown-content"
|
||||||
data-dropdown-placement="bottom-end"
|
data-dropdown-placement="bottom-start"
|
||||||
>
|
>
|
||||||
<span class="sr-only">View notifications</span>
|
<span class="sr-only">View notifications</span>
|
||||||
<i class="fas fa-bell"></i>
|
<i class="fas fa-bell"></i>
|
||||||
@@ -375,10 +375,10 @@ templ LayoutWithContext(title string, ctx context.Context) {
|
|||||||
</div>
|
</div>
|
||||||
<!-- Notification dropdown -->
|
<!-- Notification dropdown -->
|
||||||
<div
|
<div
|
||||||
class="hidden overflow-hidden z-50 my-4 max-w-sm md:max-w-md w-full text-base list-none bg-white rounded divide-y divide-gray-100 shadow-lg dark:divide-gray-600 dark:bg-gray-700 rounded-xl"
|
class="hidden overflow-hidden z-50 my-4 max-w-sm md:max-w-md w-full text-base list-none bg-white rounded divide-y divide-gray-100 shadow-lg dark:divide-gray-600 dark:bg-gray-700 rounded-xl fixed"
|
||||||
id="notification-dropdown"
|
id="notification-dropdown"
|
||||||
style="min-width: 320px; width: 100%;"
|
style="min-width: 320px; width: 100%;"
|
||||||
data-dropdown-placement="bottom-end"
|
data-dropdown-placement="bottom-start"
|
||||||
>
|
>
|
||||||
<div id="notification-dropdown-content">
|
<div id="notification-dropdown-content">
|
||||||
<!-- Content will be loaded dynamically via HTMX -->
|
<!-- Content will be loaded dynamically via HTMX -->
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
"net/http"
|
"net/http"
|
||||||
@@ -13,6 +14,36 @@ import (
|
|||||||
"github.com/starfleetcptn/gomft/internal/db"
|
"github.com/starfleetcptn/gomft/internal/db"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// getLatestGitHubRelease fetches the latest release tag from GitHub
|
||||||
|
func getLatestGitHubRelease() string {
|
||||||
|
// Create an HTTP client with a timeout
|
||||||
|
client := &http.Client{
|
||||||
|
Timeout: 5 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a request to the GitHub API
|
||||||
|
resp, err := client.Get("https://api.github.com/repos/starfleetcptn/gomft/releases/latest")
|
||||||
|
if err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
// Check if the response was successful
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the response
|
||||||
|
var release struct {
|
||||||
|
TagName string `json:"tag_name"`
|
||||||
|
}
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&release); err != nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return release.TagName
|
||||||
|
}
|
||||||
|
|
||||||
// HandleDashboard handles the GET /dashboard route
|
// HandleDashboard handles the GET /dashboard route
|
||||||
func (h *Handlers) HandleDashboard(c *gin.Context) {
|
func (h *Handlers) HandleDashboard(c *gin.Context) {
|
||||||
|
|
||||||
@@ -71,6 +102,12 @@ func (h *Handlers) HandleDashboard(c *gin.Context) {
|
|||||||
// Get the rclone version
|
// Get the rclone version
|
||||||
rcloneVersion := components.GetRcloneVersion()
|
rcloneVersion := components.GetRcloneVersion()
|
||||||
|
|
||||||
|
// Set current version from the application version
|
||||||
|
currentVersion := components.AppVersion
|
||||||
|
|
||||||
|
// Get the latest release version from GitHub
|
||||||
|
latestVersion := getLatestGitHubRelease()
|
||||||
|
|
||||||
data := components.DashboardData{
|
data := components.DashboardData{
|
||||||
RecentJobs: recentHistory,
|
RecentJobs: recentHistory,
|
||||||
ActiveTransfers: int(totalJobs),
|
ActiveTransfers: int(totalJobs),
|
||||||
@@ -78,6 +115,8 @@ func (h *Handlers) HandleDashboard(c *gin.Context) {
|
|||||||
FailedTransfers: int(failedJobs),
|
FailedTransfers: int(failedJobs),
|
||||||
Configs: configsMap,
|
Configs: configsMap,
|
||||||
RcloneVersion: rcloneVersion,
|
RcloneVersion: rcloneVersion,
|
||||||
|
CurrentVersion: currentVersion,
|
||||||
|
LatestVersion: latestVersion,
|
||||||
}
|
}
|
||||||
|
|
||||||
components.Dashboard(components.CreateTemplateContext(c), data).Render(c, c.Writer)
|
components.Dashboard(components.CreateTemplateContext(c), data).Render(c, c.Writer)
|
||||||
|
|||||||
Reference in New Issue
Block a user