* 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

+38 -6
View File
@@ -1,5 +1,10 @@
/* eslint-disable react-refresh/only-export-components */
import { prepareClientCacheVersion } from "@/lib/client-cache-version";
import {
TitleBar,
TITLE_BAR_OFFSET,
useTitleBarOverlayColors,
} from "@/shell/TitleBar";
import { StrictMode, Suspense, lazy, useState, useRef, useEffect } from "react";
import { createRoot } from "react-dom/client";
import "./ui/index.css";
@@ -14,6 +19,7 @@ import {
Auth,
getStoredAuth,
clearStoredAuth,
storeAuth,
markDesktopManualLogout,
clearDesktopManualLogout,
} from "@/auth/Auth";
@@ -32,6 +38,9 @@ import {
} from "@/plugin-host/loader";
import { settledPromise } from "@/plugin-host/plugin-store";
import { resetShellBridge } from "@/plugin-host/shell-bridge";
import { loadLook, resetLook } from "@/look/look-store";
import { resetPluginThemes } from "@/look/theme-registry";
import { resetPluginLayouts } from "@/look/layout-registry";
import { preloadPermissions } from "@/hooks/use-permissions";
import { getUserPreferences } from "@/api/open-tabs-api";
import { standaloneViewFor } from "@/shell/tab-registry";
@@ -156,6 +165,8 @@ function FullscreenAppGate() {
}
function App() {
// Keeps the window controls the system draws in the colors of the theme.
useTitleBarOverlayColors();
const stored = getStoredAuth();
const [phase, setPhase] = useState<Phase>(
stored?.loggedIn ? "verifying" : "idle-auth",
@@ -192,7 +203,12 @@ function App() {
if (phase !== "verifying") return;
appReadyPromise
.then(() => getUserInfo())
.then(async () => {
.then(async (info) => {
// The stored name can be an earlier account, after a switch or rename.
if (info.username) {
setAuthUsername(info.username);
storeAuth(info.username);
}
if (isElectron()) {
try {
const token = await getCurrentToken();
@@ -209,6 +225,7 @@ function App() {
.then(() => settledPromise()),
preloadPermissions(),
getUserPreferences().catch(() => undefined),
loadLook(),
]);
await enterApp();
})
@@ -296,12 +313,10 @@ function App() {
.then(() => settledPromise()),
preloadPermissions(),
getUserPreferences().catch(() => undefined),
loadLook(),
]);
await enterApp();
})();
if (isElectron()) {
window.electronAPI?.startC2SAutoStartTunnels?.().catch(() => {});
}
}
function handleLogout(options?: LogoutOptions) {
@@ -321,6 +336,9 @@ function App() {
// should survive into the next session.
void stopPluginRuntime();
resetShellBridge();
resetLook();
resetPluginThemes();
resetPluginLayouts();
clearStoredAuth();
localStorage.removeItem("jwt");
if (isElectron() && options?.manual) {
@@ -359,10 +377,17 @@ function App() {
const { t } = useTranslation();
const isTransitioning = phase === "fading-in" || phase === "fading-out";
// The desktop app draws a title bar on top of the window, so everything
// below it starts lower. The bar sets the offset only while it shows.
const titleBarOffset = TITLE_BAR_OFFSET;
if (phase === "verifying" || phase === "loading-app") {
return (
<div className="fixed inset-0 flex items-center justify-center bg-background">
<div
className="fixed inset-0 flex items-center justify-center bg-background"
style={{ paddingTop: titleBarOffset }}
>
<TitleBar />
<div className="flex flex-col items-center gap-4">
<div className="w-5 h-5 border-2 border-primary border-t-transparent rounded-full animate-spin" />
<p className="text-sm text-muted-foreground">{t("common.loading")}</p>
@@ -373,8 +398,13 @@ function App() {
return (
<>
<TitleBar />
{isTransitioning && (
<div className="fixed inset-0 z-0 flex items-center justify-center bg-background">
<div
className="fixed inset-0 z-0 flex items-center justify-center bg-background"
style={{ paddingTop: titleBarOffset }}
>
<div className="flex flex-col items-center gap-4">
<div className="w-5 h-5 border-2 border-primary border-t-transparent rounded-full animate-spin" />
<p className="text-sm text-muted-foreground">
@@ -405,6 +435,7 @@ function App() {
style={{
opacity: appOpacity,
pointerEvents: phase === "idle-app" ? "auto" : "none",
paddingTop: titleBarOffset,
}}
>
<Suspense fallback={null}>
@@ -421,6 +452,7 @@ function App() {
style={{
opacity: authOpacity,
pointerEvents: phase === "idle-auth" ? "auto" : "none",
paddingTop: titleBarOffset,
}}
>
<Auth onLogin={handleLogin} />