fix: unify connection toolbar visibility (#1357)

This commit is contained in:
ZacharyZcR
2026-08-28 10:37:05 +08:00
committed by GitHub
parent 0f39ce6369
commit 9a8f0ba888
8 changed files with 78 additions and 29 deletions
+1 -1
View File
@@ -111,7 +111,7 @@ export interface HostFeatureFlags {
enableFileManager: boolean; // SSH only
enableDocker: boolean; // SSH only
enableTmuxMonitor: boolean; // SSH only
enableTerminalToolbar: boolean; // SSH only
enableTerminalToolbar: boolean; // SSH, RDP, VNC, and Telnet
enableRemoteDesktop: boolean; // RDP, VNC only
}
+5 -1
View File
@@ -174,7 +174,7 @@ interface GuacamoleAppInnerProps {
| "rdpPassword"
| "vncUser"
| "vncPassword"
>;
> & { enableTerminalToolbar?: boolean };
hostName: string;
tabId?: string;
protocol?: "rdp" | "vnc" | "telnet";
@@ -208,6 +208,7 @@ const GuacamoleAppInner = React.forwardRef<
const [displayZoom, setDisplayZoom] = useState(1);
const [filesystem, setFilesystem] = useState<Guacamole.Object | null>(null);
const [fileBrowserOpen, setFileBrowserOpen] = useState(false);
const [toolbarHidden, setToolbarHidden] = useState(false);
const [pendingUploads, setPendingUploads] = useState<File[]>([]);
const guacConfig = parseGuacamoleConfig(hostConfig.guacamoleConfig);
@@ -586,6 +587,7 @@ const GuacamoleAppInner = React.forwardRef<
onClose={() => setFileBrowserOpen(false)}
/>
)}
{hostConfig.enableTerminalToolbar !== false && !toolbarHidden && (
<GuacamoleToolbar
displayRef={displayRef}
protocol={resolvedProtocol}
@@ -595,7 +597,9 @@ const GuacamoleAppInner = React.forwardRef<
onToggleFileBrowser={() => setFileBrowserOpen((open) => !open)}
onTouchModeChange={setTouchMode}
zoom={displayZoom}
onHide={() => setToolbarHidden(true)}
/>
)}
{shareModalOpen && guacamoleConnectionId && (
<ShareSessionModal
open={shareModalOpen}
@@ -19,6 +19,7 @@ import {
ZoomIn,
ZoomOut,
Scan,
X,
} from "lucide-react";
import {
Tooltip,
@@ -42,6 +43,7 @@ interface GuacamoleToolbarProps {
onToggleFileBrowser?: () => void;
onTouchModeChange?: (mode: GuacamoleTouchMode) => void;
zoom?: number;
onHide?: () => void;
}
const MODIFIER_KEYSYMS = {
@@ -130,6 +132,7 @@ export const GuacamoleToolbar: React.FC<GuacamoleToolbarProps> = ({
onToggleFileBrowser,
onTouchModeChange,
zoom = 1,
onHide,
}) => {
const { t } = useTranslation();
const [position, setPosition] = useState({ x: 0, y: 12 });
@@ -569,6 +572,14 @@ export const GuacamoleToolbar: React.FC<GuacamoleToolbarProps> = ({
{t("guacamole.toolbar.collapse")}
</TooltipContent>
</Tooltip>
{onHide && (
<TipIconBtn
tooltip={t("guacamole.toolbar.hide")}
onClick={onHide}
>
<X className="size-3.5" />
</TipIconBtn>
)}
</div>
)}
</div>
+4
View File
@@ -1142,6 +1142,9 @@
"enableTmuxMonitorDesc": "Show this host in the Tmux Monitor and add its tmux actions to the sidebar",
"enableTerminalToolbar": "Enable Terminal Toolbar",
"enableTerminalToolbarDesc": "Show a quick-access toolbar docked to the active terminal for this host's tools and live stats",
"connectionToolbar": "Connection Toolbar",
"showConnectionToolbar": "Show connection toolbar",
"showConnectionToolbarDesc": "Show the toolbar in this host's SSH, RDP, VNC, and Telnet sessions. You can also hide it temporarily from the toolbar itself.",
"tabProxmox": "Proxmox",
"proxmoxIntegration": "Proxmox Integration",
"enableProxmox": "Enable Proxmox",
@@ -2043,6 +2046,7 @@
"collapse": "Collapse toolbar",
"expand": "Expand toolbar",
"dragHandle": "Drag to reposition",
"hide": "Hide for this session. To disable it permanently, open Host Settings → General → Connection Toolbar.",
"zoomIn": "Zoom in",
"zoomOut": "Zoom out",
"resetZoom": "Reset zoom",
+1
View File
@@ -222,6 +222,7 @@ function hostToSSHHost(h: Host): SSHHost {
enableTunnel: h.enableTunnel ?? false,
enableFileManager: h.enableFileManager ?? false,
enableDocker: h.enableDocker ?? false,
enableTerminalToolbar: h.enableTerminalToolbar ?? true,
dockerConfig: h.dockerConfig ?? null,
showTerminalInSidebar: true,
showFileManagerInSidebar: true,
-17
View File
@@ -25,7 +25,6 @@ import {
Globe,
Info,
Layers, // --- tmux-monitor ---
LayoutGrid,
Network,
Palette,
Pencil,
@@ -2193,22 +2192,6 @@ export function HostEditor({
</SettingRow>
</div>
</SectionCard>
<SectionCard
title={t("terminalToolbar.title")}
icon={<LayoutGrid className="size-3.5" />}
>
<div className="flex flex-col gap-4 py-3">
<SettingRow
label={t("hosts.enableTerminalToolbar")}
description={t("hosts.enableTerminalToolbarDesc")}
>
<FakeSwitch
checked={form.enableTerminalToolbar}
onChange={(v) => setField("enableTerminalToolbar", v)}
/>
</SettingRow>
</div>
</SectionCard>
</>
)}
+18
View File
@@ -8,6 +8,7 @@ import { FakeSwitch, SectionCard, SettingRow } from "@/components/section-card";
import type { Host } from "@/types/ui-types";
import {
Globe,
LayoutGrid,
Monitor,
MousePointerClick,
Plus,
@@ -172,6 +173,23 @@ export function HostEditorGeneralTab({
</div>
</SectionCard>
<SectionCard
title={t("hosts.connectionToolbar")}
icon={<LayoutGrid className="size-3.5" />}
>
<div className="flex flex-col gap-4 py-3">
<SettingRow
label={t("hosts.showConnectionToolbar")}
description={t("hosts.showConnectionToolbarDesc")}
>
<FakeSwitch
checked={form.enableTerminalToolbar}
onChange={(value) => setField("enableTerminalToolbar", value)}
/>
</SettingRow>
</div>
</SectionCard>
<SectionCard
title={t("hosts.connectionDetails")}
icon={<Globe className="size-3.5" />}
@@ -78,4 +78,32 @@ describe("GuacamoleToolbar Windows key", () => {
expect(zoomIn).toHaveBeenCalledOnce();
expect(resetZoom).toHaveBeenCalledOnce();
});
it("offers an explicit session-only hide action", () => {
const onHide = vi.fn();
const displayRef = {
current: {
disconnect: vi.fn(),
isConnected: () => true,
sendKey: vi.fn(),
sendMouse: vi.fn(),
setClipboard: vi.fn(),
getFilesystem: () => null,
zoomIn: vi.fn(() => 1.25),
zoomOut: vi.fn(() => 0.75),
resetZoom: vi.fn(() => 1),
} satisfies GuacamoleDisplayHandle,
} as React.RefObject<GuacamoleDisplayHandle>;
const { getByLabelText } = render(
<GuacamoleToolbar
displayRef={displayRef}
protocol="rdp"
onHide={onHide}
/>,
);
fireEvent.click(getByLabelText("guacamole.toolbar.hide"));
expect(onHide).toHaveBeenCalledOnce();
});
});