diff --git a/templates/main/instances.html b/templates/main/instances.html
index 61ec53b..5120841 100644
--- a/templates/main/instances.html
+++ b/templates/main/instances.html
@@ -40,6 +40,15 @@
background-color: #d1ecf1 !important;
border-color: #bee5eb !important;
}
+
+ .badge.bg-orange {
+ background-color: #fd7e14 !important;
+ color: white !important;
+ }
+
+ .badge.bg-orange:hover {
+ background-color: #e55a00 !important;
+ }
{% endblock %}
@@ -742,15 +751,13 @@ document.addEventListener('DOMContentLoaded', function() {
}
// Wait a short moment to ensure the table is rendered
- setTimeout(() => {
- // Check statuses on page load
+ setTimeout(async () => {
+ // First fetch latest version information
+ await fetchLatestVersion();
+
+ // Then check statuses and fetch company names
checkAllInstanceStatuses();
-
- // Fetch company names for all instances
fetchCompanyNames();
-
- // Fetch latest version information
- fetchLatestVersion();
}, 100);
// Set up periodic status checks (every 30 seconds)
@@ -936,6 +943,49 @@ async function fetchInstanceStats(instanceUrl, instanceId, jwtToken) {
}
}
+// Function to compare semantic versions and determine update type
+function compareSemanticVersions(currentVersion, latestVersion) {
+ try {
+ // Parse versions into parts (handle cases like "1.0" or "1.0.0")
+ const parseVersion = (version) => {
+ const parts = version.split('.').map(part => {
+ const num = parseInt(part, 10);
+ return isNaN(num) ? 0 : num;
+ });
+ // Ensure we have at least 3 parts (major.minor.patch)
+ while (parts.length < 3) {
+ parts.push(0);
+ }
+ return parts.slice(0, 3); // Only take first 3 parts
+ };
+
+ const current = parseVersion(currentVersion);
+ const latest = parseVersion(latestVersion);
+
+ // Compare major version
+ if (current[0] < latest[0]) {
+ return 'major';
+ }
+
+ // Compare minor version
+ if (current[1] < latest[1]) {
+ return 'minor';
+ }
+
+ // Compare patch version
+ if (current[2] < latest[2]) {
+ return 'patch';
+ }
+
+ // If we get here, current version is newer or equal
+ return 'up_to_date';
+
+ } catch (error) {
+ console.error('Error comparing semantic versions:', error);
+ return 'unknown';
+ }
+}
+
// Function to fetch version information for an instance
async function fetchVersionInfo(instanceUrl, instanceId) {
const row = document.querySelector(`[data-instance-id="${instanceId}"]`).closest('tr');
@@ -984,7 +1034,23 @@ async function fetchVersionInfo(instanceUrl, instanceId) {
if (appVersion !== 'unknown') {
// Get the latest version for comparison
const latestVersionBadge = document.getElementById('latestVersionBadge');
- const latestVersion = latestVersionBadge ? latestVersionBadge.textContent.replace('Loading...', '').trim() : null;
+ let latestVersion = latestVersionBadge ? latestVersionBadge.textContent.replace('Loading...', '').trim() : null;
+
+ // If latest version is not available yet, wait a bit and try again
+ if (!latestVersion || latestVersion === '') {
+ // Show loading state while waiting for latest version
+ versionCell.innerHTML = `
+
+ ${appVersion.length > 8 ? appVersion.substring(0, 8) : appVersion}
+ `;
+
+ // Wait a bit and retry the comparison
+ setTimeout(() => {
+ fetchVersionInfo(instanceUrl, instanceId);
+ }, 2000);
+ return;
+ }
// Determine if this instance is up to date
let badgeClass = 'bg-secondary';
@@ -992,13 +1058,40 @@ async function fetchVersionInfo(instanceUrl, instanceId) {
let tooltipText = `App Version: ${appVersion}
Git Commit: ${gitCommit}
Deployed: ${deployedAt}`;
if (latestVersion && appVersion === latestVersion) {
+ // Exact match - green
badgeClass = 'bg-success';
statusIcon = 'fas fa-check-circle';
tooltipText += '
✅ Up to date';
} else if (latestVersion && appVersion !== latestVersion) {
- badgeClass = 'bg-danger';
- statusIcon = 'fas fa-exclamation-triangle';
- tooltipText += `
⚠️ Outdated (Latest: ${latestVersion})`;
+ // Compare semantic versions
+ const versionComparison = compareSemanticVersions(appVersion, latestVersion);
+
+ switch (versionComparison) {
+ case 'patch':
+ // Only patch version different - yellow
+ badgeClass = 'bg-warning';
+ statusIcon = 'fas fa-exclamation-triangle';
+ tooltipText += `
🟡 Patch update available (Latest: ${latestVersion})`;
+ break;
+ case 'minor':
+ // Minor version different - orange
+ badgeClass = 'bg-orange';
+ statusIcon = 'fas fa-exclamation-triangle';
+ tooltipText += `
🟠 Minor update available (Latest: ${latestVersion})`;
+ break;
+ case 'major':
+ // Major version different - red
+ badgeClass = 'bg-danger';
+ statusIcon = 'fas fa-exclamation-triangle';
+ tooltipText += `
🔴 Major update available (Latest: ${latestVersion})`;
+ break;
+ default:
+ // Unknown format or comparison failed - red
+ badgeClass = 'bg-danger';
+ statusIcon = 'fas fa-exclamation-triangle';
+ tooltipText += `
🔴 Outdated (Latest: ${latestVersion})`;
+ break;
+ }
}
versionCell.innerHTML = `