All checks were successful
PostgreSQL Compatibility Matrix / PG14 smoke (push) Successful in 9s
PostgreSQL Compatibility Matrix / PG15 smoke (push) Successful in 8s
PostgreSQL Compatibility Matrix / PG16 smoke (push) Successful in 8s
PostgreSQL Compatibility Matrix / PG17 smoke (push) Successful in 8s
PostgreSQL Compatibility Matrix / PG18 smoke (push) Successful in 8s
Introduced a front-end mechanism to notify users of available service updates and enhanced the service info page to reflect update status dynamically. Removed backend audit log writes for version checks to streamline operations and improve performance. Updated styling to visually highlight update notifications.
147 lines
5.0 KiB
JavaScript
147 lines
5.0 KiB
JavaScript
import React, { useEffect, useState } from "react";
|
|
import { apiFetch } from "../api";
|
|
import { useAuth } from "../state";
|
|
|
|
function formatUptime(seconds) {
|
|
const total = Math.max(0, Number(seconds || 0));
|
|
const d = Math.floor(total / 86400);
|
|
const h = Math.floor((total % 86400) / 3600);
|
|
const m = Math.floor((total % 3600) / 60);
|
|
const s = total % 60;
|
|
if (d > 0) return `${d}d ${h}h ${m}m`;
|
|
if (h > 0) return `${h}h ${m}m ${s}s`;
|
|
return `${m}m ${s}s`;
|
|
}
|
|
|
|
export function ServiceInfoPage() {
|
|
const { tokens, refresh, serviceInfo } = useAuth();
|
|
const [info, setInfo] = useState(null);
|
|
const [message, setMessage] = useState("");
|
|
const [error, setError] = useState("");
|
|
const [busy, setBusy] = useState(false);
|
|
|
|
const load = async () => {
|
|
setError("");
|
|
const data = await apiFetch("/service/info", {}, tokens, refresh);
|
|
setInfo(data);
|
|
};
|
|
|
|
useEffect(() => {
|
|
load().catch((e) => setError(String(e.message || e)));
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (serviceInfo) setInfo(serviceInfo);
|
|
}, [serviceInfo]);
|
|
|
|
const checkNow = async () => {
|
|
try {
|
|
setBusy(true);
|
|
setError("");
|
|
setMessage("");
|
|
const result = await apiFetch("/service/info/check", { method: "POST" }, tokens, refresh);
|
|
await load();
|
|
if (result.last_check_error) {
|
|
setMessage(`Version check finished with warning: ${result.last_check_error}`);
|
|
} else if (result.update_available) {
|
|
setMessage(`Update available: ${result.latest_version}`);
|
|
} else {
|
|
setMessage("Version check completed. No update detected.");
|
|
}
|
|
} catch (e) {
|
|
setError(String(e.message || e));
|
|
} finally {
|
|
setBusy(false);
|
|
}
|
|
};
|
|
|
|
if (!info) {
|
|
return <div className="card">Loading service information...</div>;
|
|
}
|
|
|
|
return (
|
|
<div className="service-page">
|
|
<h2>Service Information</h2>
|
|
<p className="muted">Runtime details, installed version, and update check status for this NexaPG instance.</p>
|
|
{error && <div className="card error">{error}</div>}
|
|
{message && <div className="test-connection-result ok service-msg">{message}</div>}
|
|
|
|
<div className={`card service-hero ${info.update_available ? "update" : "ok"}`}>
|
|
<div>
|
|
<strong className="service-hero-title">
|
|
{info.update_available ? `Update available: ${info.latest_version}` : "Service is up to date"}
|
|
</strong>
|
|
<p className="muted service-hero-sub">
|
|
Automatic release checks run every 30 seconds. Source: official NexaPG upstream releases.
|
|
</p>
|
|
</div>
|
|
<button type="button" className="secondary-btn" disabled={busy} onClick={checkNow}>
|
|
Check Now
|
|
</button>
|
|
</div>
|
|
|
|
<div className="grid three">
|
|
<div className="card service-card">
|
|
<h3>Application</h3>
|
|
<div className="overview-kv">
|
|
<span>App Name</span>
|
|
<strong>{info.app_name}</strong>
|
|
<span>Environment</span>
|
|
<strong>{info.environment}</strong>
|
|
<span>API Prefix</span>
|
|
<strong>{info.api_prefix}</strong>
|
|
</div>
|
|
</div>
|
|
<div className="card service-card">
|
|
<h3>Runtime</h3>
|
|
<div className="overview-kv">
|
|
<span>Host</span>
|
|
<strong>{info.hostname}</strong>
|
|
<span>Python</span>
|
|
<strong>{info.python_version}</strong>
|
|
<span>Uptime</span>
|
|
<strong>{formatUptime(info.uptime_seconds)}</strong>
|
|
</div>
|
|
</div>
|
|
<div className="card service-card">
|
|
<h3>Version Status</h3>
|
|
<div className="overview-kv">
|
|
<span>Current NexaPG Version</span>
|
|
<strong>{info.app_version}</strong>
|
|
<span>Latest Known Version</span>
|
|
<strong>{info.latest_version || "-"}</strong>
|
|
<span>Update Status</span>
|
|
<strong className={info.update_available ? "service-status-update" : "service-status-ok"}>
|
|
{info.update_available ? "Update available" : "Up to date"}
|
|
</strong>
|
|
<span>Last Check</span>
|
|
<strong>{info.last_checked_at ? new Date(info.last_checked_at).toLocaleString() : "never"}</strong>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="card service-card">
|
|
<h3>Release Source</h3>
|
|
<p className="muted">
|
|
Update checks run against the official NexaPG repository. This source is fixed in code and cannot be changed
|
|
via UI.
|
|
</p>
|
|
<div className="overview-kv">
|
|
<span>Source Repository</span>
|
|
<strong>{info.update_source}</strong>
|
|
<span>Latest Reference Type</span>
|
|
<strong>{info.latest_ref || "-"}</strong>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="card service-card">
|
|
<h3>Version Control Policy</h3>
|
|
<p className="muted">
|
|
Version and update-source settings are not editable in the app. Only code maintainers of the official NexaPG
|
|
repository can change that behavior.
|
|
</p>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|