Final pre-launch version: Update logic
This commit is contained in:
@@ -269,6 +269,9 @@
|
||||
<span id="status-protocol"></span>
|
||||
<span id="status-session-count">0 sessions</span>
|
||||
<span class="status-spacer"></span>
|
||||
<button class="status-update is-hidden" id="status-update" type="button">
|
||||
Update available
|
||||
</button>
|
||||
<span id="status-vault">🔒 Locked</span>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
@@ -125,6 +125,27 @@
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.status-update {
|
||||
border: 1px solid var(--accent);
|
||||
background: rgba(78, 205, 196, 0.12);
|
||||
color: var(--accent);
|
||||
font-size: var(--text-xs);
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
cursor: pointer;
|
||||
transition: background 150ms ease, color 150ms ease, border-color 150ms ease;
|
||||
}
|
||||
|
||||
.status-update:hover {
|
||||
background: rgba(78, 205, 196, 0.2);
|
||||
color: var(--text-primary);
|
||||
border-color: var(--accent-strong, var(--accent));
|
||||
}
|
||||
|
||||
.status-update.is-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Status bar indicator dots */
|
||||
.status-bar .status-dot {
|
||||
width: 6px;
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
this.exportImport = new ExportImportUI(this);
|
||||
this.sftp = new SFTPBrowser(this);
|
||||
this.snippets = new SnippetLibrary(this);
|
||||
this.updateInfo = null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -61,6 +62,7 @@
|
||||
await this.loadPreferences();
|
||||
await this.checkSecretStore();
|
||||
this.updateStatusBar();
|
||||
this.checkForUpdates(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -254,6 +256,11 @@
|
||||
);
|
||||
});
|
||||
|
||||
// App-wide commands from the native menu
|
||||
window.runtime.EventsOn("app:open-about", () => {
|
||||
this.settings.openTab("about");
|
||||
});
|
||||
|
||||
// Port-forwarding events
|
||||
window.runtime.EventsOn("session:forward:started", (payload) => {
|
||||
const fwd = payload.forward || {};
|
||||
@@ -503,6 +510,12 @@
|
||||
this._bindClick("btn-empty-connect", () => this.profileEditor.openNew());
|
||||
this._bindClick("btn-empty-quick", () => this.quickConnect());
|
||||
|
||||
const updateBtn = document.getElementById("status-update");
|
||||
if (updateBtn) {
|
||||
updateBtn.addEventListener("mousedown", (e) => e.preventDefault());
|
||||
updateBtn.addEventListener("click", () => this.settings.openTab("about"));
|
||||
}
|
||||
|
||||
const searchInput = document.getElementById("profile-search");
|
||||
if (searchInput) {
|
||||
searchInput.addEventListener("input", (e) =>
|
||||
@@ -851,6 +864,7 @@
|
||||
const connEl = document.getElementById("status-connection");
|
||||
const countEl = document.getElementById("status-session-count");
|
||||
const vaultEl = document.getElementById("status-vault");
|
||||
const updateEl = document.getElementById("status-update");
|
||||
if (!connEl) return;
|
||||
|
||||
const sessions = this.state.getAllSessions();
|
||||
@@ -874,6 +888,44 @@
|
||||
? "🔓 Unlocked"
|
||||
: "🔒 Locked";
|
||||
}
|
||||
|
||||
if (updateEl) {
|
||||
if (this.updateInfo && this.updateInfo.available) {
|
||||
const version = this.updateInfo.latestVersion
|
||||
? ` (${this.updateInfo.latestVersion})`
|
||||
: "";
|
||||
updateEl.textContent = `Update available${version}`;
|
||||
updateEl.classList.remove("is-hidden");
|
||||
} else {
|
||||
updateEl.textContent = "Update available";
|
||||
updateEl.classList.add("is-hidden");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async checkForUpdates(silent) {
|
||||
if (!window.go || !window.go.api || !window.go.api.Service) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const info = await window.go.api.Service.CheckForUpdates();
|
||||
this.setUpdateInfo(info);
|
||||
if (!silent && info && info.available) {
|
||||
this.notifications.info(
|
||||
`Update available: ${info.latestVersion || "new version"}`,
|
||||
);
|
||||
}
|
||||
} catch (err) {
|
||||
if (!silent) {
|
||||
this.notifications.error("Update check failed: " + err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setUpdateInfo(info) {
|
||||
this.updateInfo = info || null;
|
||||
this.updateStatusBar();
|
||||
}
|
||||
|
||||
// ── Internal helpers ─────────────────────────────────────────────
|
||||
|
||||
@@ -848,7 +848,7 @@
|
||||
body.innerHTML = `
|
||||
<div class="about-section">
|
||||
<h3 class="about-title">Nexus Terminal</h3>
|
||||
<p class="about-version">Version 1.0.0</p>
|
||||
<p class="about-version" data-role="app-version">Version …</p>
|
||||
<p class="about-desc">Developed by Andy Dixon - www.dixon.cx/nexus</p>
|
||||
<div class="about-links">
|
||||
<p>AES-256-GCM encrypted credential vault</p>
|
||||
@@ -864,6 +864,22 @@
|
||||
</div>
|
||||
`;
|
||||
|
||||
const versionEl = body.querySelector("[data-role='app-version']");
|
||||
if (versionEl) {
|
||||
if (window.go && window.go.api && window.go.api.Service) {
|
||||
window.go.api.Service.GetAppInfo()
|
||||
.then((info) => {
|
||||
const version = (info && info.version) || "dev";
|
||||
versionEl.textContent = `Version ${version}`;
|
||||
})
|
||||
.catch(() => {
|
||||
versionEl.textContent = "Version unavailable";
|
||||
});
|
||||
} else {
|
||||
versionEl.textContent = "Version unavailable";
|
||||
}
|
||||
}
|
||||
|
||||
const updateBtn = body.querySelector("#settings-check-update");
|
||||
if (updateBtn) {
|
||||
updateBtn.addEventListener("click", async () => {
|
||||
@@ -872,6 +888,9 @@
|
||||
try {
|
||||
const info = await window.go.api.Service.CheckForUpdates();
|
||||
const resultEl = body.querySelector("#settings-update-result");
|
||||
if (this.app && typeof this.app.setUpdateInfo === "function") {
|
||||
this.app.setUpdateInfo(info);
|
||||
}
|
||||
if (info.available) {
|
||||
resultEl.innerHTML =
|
||||
`<span style="color:var(--accent)">Update available: <strong>${info.latestVersion}</strong></span>` +
|
||||
|
||||
Reference in New Issue
Block a user