* feat: shell controller, TabStage, layout and theme plugins with repair view

* feat: move the classic layout into its own bundled plugin

* feat: move color themes into a bundled themes plugin

* fix: plugin tests and type checks work with a linked sdk

* fix: home tab, layout switch and missing layout fallbacks for looks

* chore: add classic layout and themes to the readme

* chore: drop example plugin links from the plugin guide

* feat: plugin filters by type, paged browse, hide plugins needing newer termix

* feat: move desktop, status, import, audit and branding features into plugins

* feat: host lock api so a plugin can load hosts from a config file (#1581)

* chore: add hosts config to the plugin table

* feat: login policy hook for plugins and optional https redirect (#1584)

* chore: add login security to the plugin table

* feat: api key socket tickets so a master can open remote sessions (#1654)

* feat: sync moves to a plugin, desktop gets multiple accounts (#1580, #1654)

* chore: add sync to the plugin table

* feat: move the sync screens and wizard out of core into the plugin (#1580)

* fix: add a neutral linked desktop hook for plugins (#1580)

* fix: show the linked account's name and admin flag in the app (#1580)

* feat: ssh transport providers, core ssh relay and plugin folders api

* feat: support FIDO2 security keys through ssh agent

* feat: add companion panels beside host tabs

* feat: mTLS client certificates for desktop server links

* feat: native web view for plugins in the desktop app

* fix: detect the desktop link window by Electron's default user agent

Fixes #1675

* fix: changelog for desktop link fix

* fix: keep text primary keys in the plugin data export

* fix: ship sharp binaries for Windows arm64 builds

* feat: client cert on the sync link types (sdk 1.0.18)

* chore: update translations

* feat: themed title bar for the desktop app (#1690)

* chore: changelog for the themed title bar

* fix: draw the title bar in the sidebar color

* feat: per host layout for the terminal panel bar

* chore: sdk 1.0.19 for the panel bar layout

* chore: bundle all 43 plugins for 26.10.3

* chore: update translations

---------

Co-authored-by: SirHephaistos <60616553+SirHephaistos@users.noreply.github.com>
Co-authored-by: Giovanny Aranda <garanda21@gmail.com>
This commit is contained in:
authored and GitHub committed 2026-10-20 16:03:29 -05:00
1 parent aff29a9581
commit a89ccc6b07
577 files changed
+76479 -101831

No files matched your search

+42 -28
View File
@@ -42,6 +42,7 @@ import {
import {
challengeSecondFactor,
getLoginMethods,
getRememberDeviceAllowed,
startLoginRedirect,
submitLoginMethod,
verifySecondFactor,
@@ -137,7 +138,7 @@ function hasDesktopManualLogout() {
return localStorage.getItem(DESKTOP_MANUAL_LOGOUT_KEY) === "true";
}
function storeAuth(username: string) {
export function storeAuth(username: string) {
localStorage.setItem(
STORAGE_KEY,
JSON.stringify({ loggedIn: true, username }),
@@ -232,6 +233,7 @@ export function Auth({ onLogin }: AuthProps) {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [rememberAllowed, setRememberAllowed] = useState(true);
const [rememberMe, setRememberMe] = useState(() => {
try {
return localStorage.getItem("rememberMe") === "true";
@@ -395,6 +397,12 @@ export function Auth({ onLogin }: AuthProps) {
void startPreLoginPlugins()
.catch(() => {})
.finally(() => setAuthPluginsLoading(false));
getRememberDeviceAllowed()
.then((allowed) => {
setRememberAllowed(allowed);
if (!allowed) setRememberMe(false);
})
.catch(() => {});
getLoginMethods()
.then((methods) => setAuthMethods(methods))
.catch(() => setAuthMethods([]))
@@ -1525,19 +1533,21 @@ export function Auth({ onLogin }: AuthProps) {
{view === "external" && (
<div className="flex flex-col gap-4">
<div className="flex items-center gap-2">
<Checkbox
id="rememberSSO"
checked={rememberMe}
onCheckedChange={(v) => setRememberMe(v === true)}
/>
<label
htmlFor="rememberSSO"
className="text-xs text-muted-foreground cursor-pointer"
>
{t("auth.rememberMe")}
</label>
</div>
{rememberAllowed && (
<div className="flex items-center gap-2">
<Checkbox
id="rememberSSO"
checked={rememberMe}
onCheckedChange={(v) => setRememberMe(v === true)}
/>
<label
htmlFor="rememberSSO"
className="text-xs text-muted-foreground cursor-pointer"
>
{t("auth.rememberMe")}
</label>
</div>
)}
<div className="flex flex-col gap-3">
{externalMethods.map((method) =>
@@ -1573,20 +1583,24 @@ export function Auth({ onLogin }: AuthProps) {
/>
</Field>
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<Checkbox
id="rememberMe"
checked={rememberMe}
onCheckedChange={(v) => setRememberMe(v === true)}
disabled={loading}
/>
<label
htmlFor="rememberMe"
className="text-xs text-muted-foreground cursor-pointer"
>
{t("auth.rememberMe")}
</label>
</div>
{rememberAllowed ? (
<div className="flex items-center gap-2">
<Checkbox
id="rememberMe"
checked={rememberMe}
onCheckedChange={(v) => setRememberMe(v === true)}
disabled={loading}
/>
<label
htmlFor="rememberMe"
className="text-xs text-muted-foreground cursor-pointer"
>
{t("auth.rememberMe")}
</label>
</div>
) : (
<span />
)}
{passwordResetAllowed && (
<button
type="button"