* feat: AI translations at release, 7 new languages and regional fallback

* fix: proper plural forms for count strings and full translations

* fix: plural forms for selected, hidden and active counts

* fix: synced plugin updates failing on desktop and server-only plugins shown as stopped

* fix: restore rounded corners on app icons and favicon

* feat: desktop app auto updates with automatic, ask first or never modes

* feat: community and custom plugin registries

* feat: plugin guide for AI tools in the SDK with a lint check

* fix: keep the terminal WebSocket open past nginx's 60s default (#1588)

* chore: update changelog

* feat: show plugin download counts only and stop CI builds inflating them

* feat: hide installed plugins in the browse tab by default

* chore: pin bundled plugins to latest releases

* chore: update translations

* fix: focusing a saved password field and saving no longer erases it

* fix: tell desktop users when their 2.8 data needs 2.9 first

* fix: point windows update info at the x64 installer

* fix: keep desktop client tunnel sockets alive behind proxies

* chore: pin bundled plugins to latest releases

* fix: cover client tunnel keepalive in the c2s runtime tests

* fix: typing after opening a host no longer goes to the host search

* fix: accept tab and = separators in SSH config import (#1598)

* chore: update changelog

* chore: drop plugin versions from core changelog

* chore: update translations

* chore: lint, format, and bump version to 26.10.1

---------

Co-authored-by: Darnel Hunter <68697450+innotelinc@users.noreply.github.com>
Co-authored-by: Iain <Iain1970@protonmail.com>
This commit is contained in:
Luke Gustafson
2026-10-12 11:35:48 -05:00
committed by GitHub
co-authored by Darnel Hunter Iain
parent 6873bc92bb
commit 62ac931468
174 changed files with 94334 additions and 39995 deletions
+87
View File
@@ -0,0 +1,87 @@
import { useEffect, useRef } from "react";
import { useTranslation } from "react-i18next";
import { toast } from "sonner";
import {
desktopUpdates,
updateToastFor,
useDesktopUpdate,
} from "@/lib/desktop-updates";
const TOAST_ID = "desktop-update";
const LATER_KEY = "termix-desktop-update-later";
function readLater(): string | null {
try {
return localStorage.getItem(LATER_KEY);
} catch {
return null;
}
}
function saveLater(value: string) {
try {
localStorage.setItem(LATER_KEY, value);
} catch {
// Only means the toast comes back next launch.
}
}
/** Desktop only: tells the user about a new version and installs it. */
export function DesktopUpdateToasts() {
const { t } = useTranslation();
const state = useDesktopUpdate();
const shown = useRef<string | null>(null);
useEffect(() => {
const kind = updateToastFor(state);
if (!state || !kind) return;
const key = `${kind}:${state.version}`;
if (shown.current === key || readLater() === key) return;
shown.current = key;
const version = state.version;
const later = {
label: t("desktopUpdates.later"),
onClick: () => saveLater(key),
};
if (kind === "ready") {
toast(t("desktopUpdates.ready", { version }), {
id: TOAST_ID,
duration: Infinity,
description: t("desktopUpdates.readyHint"),
action: {
label: t("desktopUpdates.restart"),
onClick: () => void desktopUpdates()?.install(),
},
cancel: later,
});
} else if (kind === "prompt") {
toast(t("desktopUpdates.available", { version }), {
id: TOAST_ID,
duration: Infinity,
action: {
label: t("desktopUpdates.download"),
onClick: () => void desktopUpdates()?.download(),
},
cancel: later,
});
} else {
const url = state.releaseUrl;
toast(t("desktopUpdates.available", { version }), {
id: TOAST_ID,
duration: Infinity,
description: t("desktopUpdates.manualHint"),
action: {
label: t("desktopUpdates.download"),
onClick: () => {
if (url) window.open(url, "_blank", "noopener,noreferrer");
},
},
cancel: later,
});
}
}, [state, t]);
return null;
}