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 enableFileManager: boolean; // SSH only
enableDocker: boolean; // SSH only enableDocker: boolean; // SSH only
enableTmuxMonitor: boolean; // SSH only enableTmuxMonitor: boolean; // SSH only
enableTerminalToolbar: boolean; // SSH only enableTerminalToolbar: boolean; // SSH, RDP, VNC, and Telnet
enableRemoteDesktop: boolean; // RDP, VNC only enableRemoteDesktop: boolean; // RDP, VNC only
} }
+5 -1
View File
@@ -174,7 +174,7 @@ interface GuacamoleAppInnerProps {
| "rdpPassword" | "rdpPassword"
| "vncUser" | "vncUser"
| "vncPassword" | "vncPassword"
>; > & { enableTerminalToolbar?: boolean };
hostName: string; hostName: string;
tabId?: string; tabId?: string;
protocol?: "rdp" | "vnc" | "telnet"; protocol?: "rdp" | "vnc" | "telnet";
@@ -208,6 +208,7 @@ const GuacamoleAppInner = React.forwardRef<
const [displayZoom, setDisplayZoom] = useState(1); const [displayZoom, setDisplayZoom] = useState(1);
const [filesystem, setFilesystem] = useState<Guacamole.Object | null>(null); const [filesystem, setFilesystem] = useState<Guacamole.Object | null>(null);
const [fileBrowserOpen, setFileBrowserOpen] = useState(false); const [fileBrowserOpen, setFileBrowserOpen] = useState(false);
const [toolbarHidden, setToolbarHidden] = useState(false);
const [pendingUploads, setPendingUploads] = useState<File[]>([]); const [pendingUploads, setPendingUploads] = useState<File[]>([]);
const guacConfig = parseGuacamoleConfig(hostConfig.guacamoleConfig); const guacConfig = parseGuacamoleConfig(hostConfig.guacamoleConfig);
@@ -586,6 +587,7 @@ const GuacamoleAppInner = React.forwardRef<
onClose={() => setFileBrowserOpen(false)} onClose={() => setFileBrowserOpen(false)}
/> />
)} )}
{hostConfig.enableTerminalToolbar !== false && !toolbarHidden && (
<GuacamoleToolbar <GuacamoleToolbar
displayRef={displayRef} displayRef={displayRef}
protocol={resolvedProtocol} protocol={resolvedProtocol}
@@ -595,7 +597,9 @@ const GuacamoleAppInner = React.forwardRef<
onToggleFileBrowser={() => setFileBrowserOpen((open) => !open)} onToggleFileBrowser={() => setFileBrowserOpen((open) => !open)}
onTouchModeChange={setTouchMode} onTouchModeChange={setTouchMode}
zoom={displayZoom} zoom={displayZoom}
onHide={() => setToolbarHidden(true)}
/> />
)}
{shareModalOpen && guacamoleConnectionId && ( {shareModalOpen && guacamoleConnectionId && (
<ShareSessionModal <ShareSessionModal
open={shareModalOpen} open={shareModalOpen}
@@ -19,6 +19,7 @@ import {
ZoomIn, ZoomIn,
ZoomOut, ZoomOut,
Scan, Scan,
X,
} from "lucide-react"; } from "lucide-react";
import { import {
Tooltip, Tooltip,
@@ -42,6 +43,7 @@ interface GuacamoleToolbarProps {
onToggleFileBrowser?: () => void; onToggleFileBrowser?: () => void;
onTouchModeChange?: (mode: GuacamoleTouchMode) => void; onTouchModeChange?: (mode: GuacamoleTouchMode) => void;
zoom?: number; zoom?: number;
onHide?: () => void;
} }
const MODIFIER_KEYSYMS = { const MODIFIER_KEYSYMS = {
@@ -130,6 +132,7 @@ export const GuacamoleToolbar: React.FC<GuacamoleToolbarProps> = ({
onToggleFileBrowser, onToggleFileBrowser,
onTouchModeChange, onTouchModeChange,
zoom = 1, zoom = 1,
onHide,
}) => { }) => {
const { t } = useTranslation(); const { t } = useTranslation();
const [position, setPosition] = useState({ x: 0, y: 12 }); const [position, setPosition] = useState({ x: 0, y: 12 });
@@ -569,6 +572,14 @@ export const GuacamoleToolbar: React.FC<GuacamoleToolbarProps> = ({
{t("guacamole.toolbar.collapse")} {t("guacamole.toolbar.collapse")}
</TooltipContent> </TooltipContent>
</Tooltip> </Tooltip>
{onHide && (
<TipIconBtn
tooltip={t("guacamole.toolbar.hide")}
onClick={onHide}
>
<X className="size-3.5" />
</TipIconBtn>
)}
</div> </div>
)} )}
</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", "enableTmuxMonitorDesc": "Show this host in the Tmux Monitor and add its tmux actions to the sidebar",
"enableTerminalToolbar": "Enable Terminal Toolbar", "enableTerminalToolbar": "Enable Terminal Toolbar",
"enableTerminalToolbarDesc": "Show a quick-access toolbar docked to the active terminal for this host's tools and live stats", "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", "tabProxmox": "Proxmox",
"proxmoxIntegration": "Proxmox Integration", "proxmoxIntegration": "Proxmox Integration",
"enableProxmox": "Enable Proxmox", "enableProxmox": "Enable Proxmox",
@@ -2043,6 +2046,7 @@
"collapse": "Collapse toolbar", "collapse": "Collapse toolbar",
"expand": "Expand toolbar", "expand": "Expand toolbar",
"dragHandle": "Drag to reposition", "dragHandle": "Drag to reposition",
"hide": "Hide for this session. To disable it permanently, open Host Settings → General → Connection Toolbar.",
"zoomIn": "Zoom in", "zoomIn": "Zoom in",
"zoomOut": "Zoom out", "zoomOut": "Zoom out",
"resetZoom": "Reset zoom", "resetZoom": "Reset zoom",
+1
View File
@@ -222,6 +222,7 @@ function hostToSSHHost(h: Host): SSHHost {
enableTunnel: h.enableTunnel ?? false, enableTunnel: h.enableTunnel ?? false,
enableFileManager: h.enableFileManager ?? false, enableFileManager: h.enableFileManager ?? false,
enableDocker: h.enableDocker ?? false, enableDocker: h.enableDocker ?? false,
enableTerminalToolbar: h.enableTerminalToolbar ?? true,
dockerConfig: h.dockerConfig ?? null, dockerConfig: h.dockerConfig ?? null,
showTerminalInSidebar: true, showTerminalInSidebar: true,
showFileManagerInSidebar: true, showFileManagerInSidebar: true,
-17
View File
@@ -25,7 +25,6 @@ import {
Globe, Globe,
Info, Info,
Layers, // --- tmux-monitor --- Layers, // --- tmux-monitor ---
LayoutGrid,
Network, Network,
Palette, Palette,
Pencil, Pencil,
@@ -2193,22 +2192,6 @@ export function HostEditor({
</SettingRow> </SettingRow>
</div> </div>
</SectionCard> </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 type { Host } from "@/types/ui-types";
import { import {
Globe, Globe,
LayoutGrid,
Monitor, Monitor,
MousePointerClick, MousePointerClick,
Plus, Plus,
@@ -172,6 +173,23 @@ export function HostEditorGeneralTab({
</div> </div>
</SectionCard> </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 <SectionCard
title={t("hosts.connectionDetails")} title={t("hosts.connectionDetails")}
icon={<Globe className="size-3.5" />} icon={<Globe className="size-3.5" />}
@@ -78,4 +78,32 @@ describe("GuacamoleToolbar Windows key", () => {
expect(zoomIn).toHaveBeenCalledOnce(); expect(zoomIn).toHaveBeenCalledOnce();
expect(resetZoom).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();
});
}); });