version display on instances page

This commit is contained in:
2025-06-23 15:46:29 +02:00
parent af375a2b5c
commit 4cf9cca116
3 changed files with 276 additions and 61 deletions

View File

@@ -45,27 +45,57 @@
{% block content %}
{{ header(
title="Instances",
description="Manage your DocuPulse instances",
title="Instance Management",
description="Manage and monitor your DocuPulse instances",
icon="fa-server",
buttons=[
{
'text': 'Launch New Instance',
'url': '#',
'icon': 'fa-rocket',
'class': 'btn-primary',
'onclick': 'showAddInstanceModal()'
},
{
'text': 'Add Existing Instance',
'url': '#',
'icon': 'fa-link',
'class': 'btn-primary',
'onclick': 'showAddExistingInstanceModal()'
'onclick': 'showAddInstanceModal()',
'icon': 'fa-plus',
'class': 'btn-primary'
}
]
) }}
<!-- Latest Version Information -->
<div class="container-fluid mb-4">
<div class="row">
<div class="col-12">
<div class="card border-0 shadow-sm">
<div class="card-body">
<div class="row align-items-center">
<div class="col-md-8">
<h5 class="card-title mb-2">
<i class="fas fa-code-branch me-2" style="color: var(--primary-color);"></i>
Latest Available Version
</h5>
<div class="d-flex align-items-center">
<div class="me-4">
<span class="badge bg-success fs-6" id="latestVersionBadge">
<i class="fas fa-spinner fa-spin me-1"></i> Loading...
</span>
</div>
<div>
<small class="text-muted">
<i class="fas fa-clock me-1"></i>
Last checked: <span id="lastChecked" class="text-muted">Loading...</span>
</small>
</div>
</div>
</div>
<div class="col-md-4 text-end">
<button class="btn btn-outline-primary btn-sm" onclick="refreshLatestVersion()">
<i class="fas fa-sync-alt me-1"></i> Refresh
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row">
<div class="col-12">
@@ -84,7 +114,6 @@
<th>Main URL</th>
<th>Status</th>
<th>Version</th>
<th>Branch</th>
<th>Connection Token</th>
<th>Actions</th>
</tr>
@@ -126,16 +155,6 @@
<span class="badge bg-secondary version-badge">unknown</span>
{% endif %}
</td>
<td>
{% if instance.deployed_branch %}
<span class="badge bg-light text-dark branch-badge" data-bs-toggle="tooltip"
title="Deployed branch: {{ instance.deployed_branch }}">
{{ instance.deployed_branch }}
</span>
{% else %}
<span class="badge bg-secondary branch-badge">unknown</span>
{% endif %}
</td>
<td>
{% if instance.connection_token %}
<span class="badge bg-success" data-bs-toggle="tooltip" title="Instance is authenticated">
@@ -729,10 +748,16 @@ document.addEventListener('DOMContentLoaded', function() {
// Fetch company names for all instances
fetchCompanyNames();
// Fetch latest version information
fetchLatestVersion();
}, 100);
// Set up periodic status checks (every 30 seconds)
setInterval(checkAllInstanceStatuses, 30000);
// Set up periodic latest version checks (every 5 minutes)
setInterval(fetchLatestVersion, 300000);
// Update color picker functionality
const primaryColor = document.getElementById('primaryColor');
@@ -914,16 +939,12 @@ async function fetchInstanceStats(instanceUrl, instanceId, jwtToken) {
// Function to fetch version information for an instance
async function fetchVersionInfo(instanceUrl, instanceId) {
const row = document.querySelector(`[data-instance-id="${instanceId}"]`).closest('tr');
const versionCell = row.querySelector('td:nth-child(9)'); // Version column
const branchCell = row.querySelector('td:nth-child(10)'); // Branch column
const versionCell = row.querySelector('td:nth-child(9)'); // Version column (adjusted after removing branch)
// Show loading state
if (versionCell) {
versionCell.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Loading...';
}
if (branchCell) {
branchCell.innerHTML = '<i class="fas fa-spinner fa-spin"></i> Loading...';
}
try {
const apiKey = document.querySelector(`[data-instance-id="${instanceId}"]`).dataset.token;
@@ -961,41 +982,41 @@ async function fetchVersionInfo(instanceUrl, instanceId) {
const deployedAt = data.deployed_at || 'unknown';
if (appVersion !== 'unknown') {
// Get the latest version for comparison
const latestVersionBadge = document.getElementById('latestVersionBadge');
const latestVersion = latestVersionBadge ? latestVersionBadge.textContent.replace('Loading...', '').trim() : null;
// Determine if this instance is up to date
let badgeClass = 'bg-secondary';
let statusIcon = 'fas fa-tag';
let tooltipText = `App Version: ${appVersion}<br>Git Commit: ${gitCommit}<br>Deployed: ${deployedAt}`;
if (latestVersion && appVersion === latestVersion) {
badgeClass = 'bg-success';
statusIcon = 'fas fa-check-circle';
tooltipText += '<br><strong>✅ Up to date</strong>';
} else if (latestVersion && appVersion !== latestVersion) {
badgeClass = 'bg-danger';
statusIcon = 'fas fa-exclamation-triangle';
tooltipText += `<br><strong>⚠️ Outdated (Latest: ${latestVersion})</strong>`;
}
versionCell.innerHTML = `
<span class="badge bg-info version-badge" data-bs-toggle="tooltip"
title="App Version: ${appVersion}<br>Git Commit: ${gitCommit}<br>Deployed: ${deployedAt}">
${appVersion.length > 8 ? appVersion.substring(0, 8) : appVersion}
<span class="badge ${badgeClass} version-badge" data-bs-toggle="tooltip"
title="${tooltipText}">
<i class="${statusIcon} me-1"></i>${appVersion.length > 8 ? appVersion.substring(0, 8) : appVersion}
</span>`;
} else {
versionCell.innerHTML = '<span class="badge bg-secondary version-badge">unknown</span>';
}
}
// Update branch cell
if (branchCell) {
const gitBranch = data.git_branch || 'unknown';
if (gitBranch !== 'unknown') {
branchCell.innerHTML = `
<span class="badge bg-light text-dark branch-badge" data-bs-toggle="tooltip"
title="Deployed branch: ${gitBranch}">
${gitBranch}
</span>`;
} else {
branchCell.innerHTML = '<span class="badge bg-secondary branch-badge">unknown</span>';
}
}
// Update tooltips
const versionBadge = versionCell?.querySelector('[data-bs-toggle="tooltip"]');
const branchBadge = branchCell?.querySelector('[data-bs-toggle="tooltip"]');
if (versionBadge) {
new bootstrap.Tooltip(versionBadge);
}
if (branchBadge) {
new bootstrap.Tooltip(branchBadge);
}
} catch (error) {
console.error(`Error fetching version info for instance ${instanceId}:`, error);
@@ -1007,16 +1028,12 @@ async function fetchVersionInfo(instanceUrl, instanceId) {
<i class="fas fa-exclamation-triangle"></i> Error
</span>`;
}
if (branchCell) {
branchCell.innerHTML = `
<span class="text-warning" data-bs-toggle="tooltip" title="Error: ${error.message}">
<i class="fas fa-exclamation-triangle"></i> Error
</span>`;
}
// Add tooltips for error states
const errorBadges = [versionCell, branchCell].map(cell => cell?.querySelector('[data-bs-toggle="tooltip"]')).filter(Boolean);
errorBadges.forEach(badge => new bootstrap.Tooltip(badge));
const errorBadge = versionCell?.querySelector('[data-bs-toggle="tooltip"]');
if (errorBadge) {
new bootstrap.Tooltip(errorBadge);
}
}
}
@@ -1130,8 +1147,7 @@ async function fetchCompanyNames() {
row.querySelector('td:nth-child(3)'), // Rooms
row.querySelector('td:nth-child(4)'), // Conversations
row.querySelector('td:nth-child(5)'), // Data
row.querySelector('td:nth-child(9)'), // Version
row.querySelector('td:nth-child(10)') // Branch
row.querySelector('td:nth-child(9)') // Version
];
cells.forEach(cell => {
@@ -2019,5 +2035,109 @@ async function refreshAllVersionInfo() {
console.error('Error refreshing version information:', error);
}
}
// Function to fetch latest version information
async function fetchLatestVersion() {
console.log('Fetching latest version information...');
const versionBadge = document.getElementById('latestVersionBadge');
const commitSpan = document.getElementById('latestCommit');
const checkedSpan = document.getElementById('lastChecked');
// Show loading state
if (versionBadge) {
versionBadge.innerHTML = '<i class="fas fa-spinner fa-spin me-1"></i> Loading...';
versionBadge.className = 'badge bg-secondary fs-6';
}
try {
const response = await fetch('/api/latest-version', {
method: 'GET',
headers: {
'Accept': 'application/json',
'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content
}
});
if (!response.ok) {
const errorText = await response.text();
console.error(`HTTP error ${response.status}:`, errorText);
throw new Error(`Server returned ${response.status}: ${errorText}`);
}
const data = await response.json();
console.log('Received latest version data:', data);
if (data.success) {
// Update version badge
if (versionBadge) {
const version = data.latest_version;
if (version !== 'unknown') {
versionBadge.innerHTML = `<i class="fas fa-tag me-1"></i>${version}`;
versionBadge.className = 'badge bg-success fs-6';
} else {
versionBadge.innerHTML = '<i class="fas fa-question-circle me-1"></i>Unknown';
versionBadge.className = 'badge bg-warning fs-6';
}
}
// Update commit information
if (commitSpan) {
const commit = data.latest_commit;
if (commit !== 'unknown') {
commitSpan.textContent = commit.substring(0, 8);
commitSpan.title = commit;
} else {
commitSpan.textContent = 'Unknown';
}
}
// Update last checked time
if (checkedSpan) {
const lastChecked = data.last_checked;
if (lastChecked) {
const date = new Date(lastChecked);
checkedSpan.textContent = date.toLocaleString();
} else {
checkedSpan.textContent = 'Never';
}
}
} else {
// Handle error response
if (versionBadge) {
versionBadge.innerHTML = '<i class="fas fa-exclamation-triangle me-1"></i>Error';
versionBadge.className = 'badge bg-danger fs-6';
}
if (commitSpan) {
commitSpan.textContent = 'Error';
}
if (checkedSpan) {
checkedSpan.textContent = 'Error';
}
console.error('Error in latest version response:', data.error);
}
} catch (error) {
console.error('Error fetching latest version:', error);
// Show error state
if (versionBadge) {
versionBadge.innerHTML = '<i class="fas fa-exclamation-triangle me-1"></i>Error';
versionBadge.className = 'badge bg-danger fs-6';
}
if (commitSpan) {
commitSpan.textContent = 'Error';
}
if (checkedSpan) {
checkedSpan.textContent = 'Error';
}
}
}
// Function to refresh latest version (called by button)
async function refreshLatestVersion() {
console.log('Manual refresh of latest version requested');
await fetchLatestVersion();
}
</script>
{% endblock %}