mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 14:15:24 +00:00
feat: convert serial console into the serial plugin
This commit is contained in:
1 parent
708eedb861
commit
791d8656a1
121 files changed
+2216
-1425
No files matched your search
+10
-5
@@ -30,17 +30,22 @@ import {
|
||||
Share2,
|
||||
} from "lucide-react";
|
||||
import { tabIcon } from "@/shell/tabUtils";
|
||||
import { isSessionTabType } from "@/shell/tab-registry";
|
||||
import { isSessionTabType, isShareableTabType } from "@/shell/tab-registry";
|
||||
import { isElectron } from "@/lib/electron";
|
||||
import type { Tab, TabType, SplitMode } from "@/types/ui-types";
|
||||
import { SPLIT_MODES, PANE_COUNTS } from "@/lib/theme";
|
||||
|
||||
/**
|
||||
* Tabs holding a live connection that can be refreshed and shared: the
|
||||
* registered session tabs. Serial sessions are not shareable.
|
||||
* Tabs holding a live connection that can be refreshed: the registered
|
||||
* session tabs.
|
||||
*/
|
||||
function isConnectionTab(type: TabType): boolean {
|
||||
return type !== "serial" && isSessionTabType(type);
|
||||
return isSessionTabType(type);
|
||||
}
|
||||
|
||||
/** Connection tabs that also offer "Share session". */
|
||||
function isShareableConnectionTab(type: TabType): boolean {
|
||||
return isConnectionTab(type) && isShareableTabType(type);
|
||||
}
|
||||
|
||||
export function TabBar({
|
||||
@@ -467,7 +472,7 @@ export function TabBar({
|
||||
<RefreshCw className="size-3" />
|
||||
</button>
|
||||
)}
|
||||
{isConnectionTab(tab.type) && onOpenShare && (
|
||||
{isShareableConnectionTab(tab.type) && onOpenShare && (
|
||||
<button
|
||||
onPointerDown={(e) => e.stopPropagation()}
|
||||
onClick={(e) => {
|
||||
|
||||
@@ -19,7 +19,6 @@ import { getTabType } from "./tab-registry";
|
||||
* not a meaningful part of an arrangement.
|
||||
*/
|
||||
const CORE_CAPTURABLE = new Set([
|
||||
"serial",
|
||||
"homepage",
|
||||
"termix-id",
|
||||
"session-logs",
|
||||
@@ -52,10 +51,7 @@ const CORE_UNSAVED = new Set([
|
||||
*/
|
||||
export function isUnregisteredPluginTabType(type: string): boolean {
|
||||
return (
|
||||
!CORE_UNSAVED.has(type) &&
|
||||
!CORE_CAPTURABLE.has(type) &&
|
||||
type !== "serial" &&
|
||||
!getTabType(type)
|
||||
!CORE_UNSAVED.has(type) && !CORE_CAPTURABLE.has(type) && !getTabType(type)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -94,14 +90,13 @@ export function buildLayoutTabSnapshots(
|
||||
const snapshots: WorkspaceTabSnapshot[] = capturable.map((tab) => ({
|
||||
slotId: slotIdByTabId.get(tab.id)!,
|
||||
type: tab.type,
|
||||
hostSyncId: tab.type === "serial" ? null : (tab.host?.syncId ?? null),
|
||||
hostSyncId: tab.host?.syncId ?? null,
|
||||
hostNameSnapshot: tab.host?.name ?? null,
|
||||
label: tab.label,
|
||||
customLabel: tab.customLabel,
|
||||
initialFilePath: tab.initialFilePath,
|
||||
initialPath: tab.initialPath,
|
||||
data: tab.data,
|
||||
serialConfig: tab.type === "serial" ? tab.serialConfig : undefined,
|
||||
}));
|
||||
|
||||
return { snapshots, slotIdByTabId };
|
||||
@@ -139,14 +134,9 @@ export function resolveLayoutTabTarget(
|
||||
snapshot: WorkspaceTabSnapshot,
|
||||
allHosts: Host[],
|
||||
):
|
||||
| { kind: "serial" }
|
||||
| { kind: "singleton"; host?: Host }
|
||||
| { kind: "host"; host: Host }
|
||||
| { kind: "skip" } {
|
||||
if (snapshot.type === "serial") {
|
||||
return snapshot.serialConfig ? { kind: "serial" } : { kind: "skip" };
|
||||
}
|
||||
|
||||
let host: Host | undefined;
|
||||
if (snapshot.hostSyncId) {
|
||||
host = allHosts.find((h) => h.syncId === snapshot.hostSyncId);
|
||||
|
||||
@@ -61,6 +61,8 @@ export interface TabTypeDef {
|
||||
persistent?: boolean;
|
||||
singleton?: boolean;
|
||||
session?: boolean;
|
||||
/** Whether a session tab offers "Share session". Default true. */
|
||||
shareable?: boolean;
|
||||
hostless?: boolean;
|
||||
restore?: (host: Host) => boolean;
|
||||
activityTypes?: string[];
|
||||
@@ -91,7 +93,7 @@ export const resetTabTypes = registry.reset;
|
||||
/** Core tab types that are saved and reopened after login. */
|
||||
const CORE_PERSISTENT = new Set<string>();
|
||||
/** Core tab types that hold a live session (close confirm, refresh). */
|
||||
const CORE_SESSION = new Set(["serial"]);
|
||||
const CORE_SESSION = new Set<string>();
|
||||
/** Core tab types that restore without a host. */
|
||||
const CORE_HOSTLESS = new Set(["dashboard"]);
|
||||
|
||||
@@ -115,6 +117,11 @@ export function isSessionTabType(type: string): boolean {
|
||||
return CORE_SESSION.has(type) || !!registry.get(type)?.session;
|
||||
}
|
||||
|
||||
/** Whether a session tab of this type offers "Share session". Default true. */
|
||||
export function isShareableTabType(type: string): boolean {
|
||||
return registry.get(type)?.shareable !== false;
|
||||
}
|
||||
|
||||
export function isHostlessTabType(type: string): boolean {
|
||||
return CORE_HOSTLESS.has(type) || !!registry.get(type)?.hostless;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
LayoutPanelLeft,
|
||||
Server,
|
||||
Settings,
|
||||
Usb,
|
||||
User,
|
||||
Fingerprint,
|
||||
Hammer,
|
||||
@@ -15,7 +14,6 @@ import {
|
||||
} from "lucide-react";
|
||||
import { lazy, Suspense } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import type { SerialHandle } from "@/features/serial/serial-types";
|
||||
import type { Tab, TabType } from "@/types/ui-types";
|
||||
import { hostToSSHHost } from "@/lib/host-to-ssh-host";
|
||||
import { PluginViewPlaceholder } from "@/plugin-host/PluginViewPlaceholder";
|
||||
@@ -46,11 +44,6 @@ const HomepageCanvas = lazy(() =>
|
||||
default: m.HomepageCanvas,
|
||||
})),
|
||||
);
|
||||
const Serial = lazy(() =>
|
||||
import("@/features/serial/Serial").then((m) => ({
|
||||
default: m.Serial,
|
||||
})),
|
||||
);
|
||||
// Rail panels promoted to full tabs.
|
||||
const TermixIdPanel = lazy(() =>
|
||||
import("@/sidebar/TermixIdPanel").then((m) => ({ default: m.TermixIdPanel })),
|
||||
@@ -134,8 +127,6 @@ export function tabIcon(type: TabType) {
|
||||
return <User className="size-3.5" />;
|
||||
case "admin-settings":
|
||||
return <Settings className="size-3.5" />;
|
||||
case "serial":
|
||||
return <Usb className="size-3.5" />;
|
||||
case "homepage":
|
||||
return <LayoutGrid className="size-3.5" />;
|
||||
case "collab":
|
||||
@@ -237,18 +228,6 @@ export function renderTabContent(tab: Tab, context: TabRenderContext) {
|
||||
/>,
|
||||
);
|
||||
|
||||
case "serial":
|
||||
if (!tab.serialConfig)
|
||||
return <EmptyState icon={Usb} messageKey="serial.notSupportedTitle" />;
|
||||
return withTabSuspense(
|
||||
<Serial
|
||||
ref={tab.terminalRef as React.Ref<SerialHandle>}
|
||||
config={tab.serialConfig}
|
||||
isVisible={isVisible}
|
||||
instanceId={tab.instanceId}
|
||||
/>,
|
||||
);
|
||||
|
||||
case "homepage":
|
||||
return withTabSuspense(<HomepageCanvas />);
|
||||
|
||||
|
||||
Reference in new issue
Block a user