mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-08-29 10:21:34 +00:00
fix: unify connection toolbar visibility (#1357)
This commit is contained in:
+1
-1
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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,16 +587,19 @@ const GuacamoleAppInner = React.forwardRef<
|
||||
onClose={() => setFileBrowserOpen(false)}
|
||||
/>
|
||||
)}
|
||||
<GuacamoleToolbar
|
||||
displayRef={displayRef}
|
||||
protocol={resolvedProtocol}
|
||||
touchMode={touchMode}
|
||||
hasFilesystem={filesystem !== null}
|
||||
fileBrowserOpen={fileBrowserOpen}
|
||||
onToggleFileBrowser={() => setFileBrowserOpen((open) => !open)}
|
||||
onTouchModeChange={setTouchMode}
|
||||
zoom={displayZoom}
|
||||
/>
|
||||
{hostConfig.enableTerminalToolbar !== false && !toolbarHidden && (
|
||||
<GuacamoleToolbar
|
||||
displayRef={displayRef}
|
||||
protocol={resolvedProtocol}
|
||||
touchMode={touchMode}
|
||||
hasFilesystem={filesystem !== null}
|
||||
fileBrowserOpen={fileBrowserOpen}
|
||||
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>
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
)}
|
||||
|
||||
|
||||
@@ -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();
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user