mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-30 15:15:24 +00:00
feat(ssh-terminal): add a duplicate tab action (#1510)
This commit is contained in:
1 parent
55d7c8837b
commit
fef33142b3
4 files changed
+55
-2
No files matched your search
@@ -79,7 +79,8 @@
|
|||||||
"clipboardReadFailed": "Failed to read from clipboard. Make sure clipboard permissions are granted.",
|
"clipboardReadFailed": "Failed to read from clipboard. Make sure clipboard permissions are granted.",
|
||||||
"clipboardWriteFailed": "Failed to copy to clipboard. Make sure the page is served over HTTPS or localhost.",
|
"clipboardWriteFailed": "Failed to copy to clipboard. Make sure the page is served over HTTPS or localhost.",
|
||||||
"connected": "Connected",
|
"connected": "Connected",
|
||||||
"totpCodeLabel": "Verification Code"
|
"totpCodeLabel": "Verification Code",
|
||||||
|
"duplicateTab": "Duplicate tab"
|
||||||
},
|
},
|
||||||
"terminalToolbar": {
|
"terminalToolbar": {
|
||||||
"detachTmux": "Detach tmux",
|
"detachTmux": "Detach tmux",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import "@xterm/xterm/css/xterm.css";
|
|||||||
import { lazy, Suspense, type ComponentType } from "react";
|
import { lazy, Suspense, type ComponentType } from "react";
|
||||||
import {
|
import {
|
||||||
Braces,
|
Braces,
|
||||||
|
Copy,
|
||||||
Hammer,
|
Hammer,
|
||||||
History,
|
History,
|
||||||
Laptop,
|
Laptop,
|
||||||
@@ -12,6 +13,7 @@ import {
|
|||||||
import type {
|
import type {
|
||||||
PanelProps,
|
PanelProps,
|
||||||
PluginHostRecord,
|
PluginHostRecord,
|
||||||
|
PluginTabRecord,
|
||||||
StandaloneViewProps,
|
StandaloneViewProps,
|
||||||
TabProps,
|
TabProps,
|
||||||
TermixApp,
|
TermixApp,
|
||||||
@@ -117,6 +119,26 @@ export function activate(app: TermixApp): void {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
app.registerAction(
|
||||||
|
"terminal.duplicateTab",
|
||||||
|
((_handle: unknown, tab?: PluginTabRecord) => {
|
||||||
|
if (tab?.type === "terminal" && tab.host) {
|
||||||
|
app.tabs.openTab(tab.host, "terminal", { forceNewTab: true });
|
||||||
|
}
|
||||||
|
}) as never,
|
||||||
|
{ permission: "use" },
|
||||||
|
);
|
||||||
|
app.registerSlotContribution("tab.menu", {
|
||||||
|
actionId: "terminal.duplicateTab",
|
||||||
|
titleKey: "terminal.duplicateTab",
|
||||||
|
icon: Copy,
|
||||||
|
kind: "button",
|
||||||
|
when: ({ tab }) => {
|
||||||
|
const target = tab as PluginTabRecord | undefined;
|
||||||
|
return target?.type === "terminal" && !!target.host;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
app.registerHostAction({
|
app.registerHostAction({
|
||||||
id: "terminal",
|
id: "terminal",
|
||||||
titleKey: "nav.terminal",
|
titleKey: "nav.terminal",
|
||||||
|
|||||||
@@ -63,6 +63,36 @@ describe(`${manifest.id} activate`, () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("duplicates only the SSH connection configuration into a fresh tab", async () => {
|
||||||
|
rendered = await renderWithApp(plugin, { manifest, locales });
|
||||||
|
const host = { id: 7, name: "server", ip: "192.0.2.1", port: 22 };
|
||||||
|
expect(rendered.registered.slot("tab.menu")).toContain(
|
||||||
|
"terminal.duplicateTab",
|
||||||
|
);
|
||||||
|
await rendered.app.invokeAction("terminal.duplicateTab", undefined, {
|
||||||
|
id: "old-tab",
|
||||||
|
type: "terminal",
|
||||||
|
host,
|
||||||
|
instanceId: "old-instance",
|
||||||
|
data: { initialPath: "/tmp", joinSharedSessionId: "shared-session" },
|
||||||
|
});
|
||||||
|
expect(rendered.shellCalls).toEqual([
|
||||||
|
{
|
||||||
|
method: "openTab",
|
||||||
|
args: [
|
||||||
|
{ ...host, pluginSettings: {} },
|
||||||
|
"terminal",
|
||||||
|
{ forceNewTab: true },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
await rendered.app.invokeAction("terminal.duplicateTab", undefined, {
|
||||||
|
id: "local",
|
||||||
|
type: "local-terminal",
|
||||||
|
});
|
||||||
|
expect(rendered.shellCalls).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
it("owns the host editor's Terminal tab in the SSH group", async () => {
|
it("owns the host editor's Terminal tab in the SSH group", async () => {
|
||||||
rendered = await renderWithApp(plugin, { manifest, locales });
|
rendered = await renderWithApp(plugin, { manifest, locales });
|
||||||
expect(rendered.registered.hostEditorSections()).toEqual(["terminal"]);
|
expect(rendered.registered.hostEditorSections()).toEqual(["terminal"]);
|
||||||
|
|||||||
@@ -713,7 +713,7 @@ export function TabBar({
|
|||||||
<ActionSlot
|
<ActionSlot
|
||||||
slotId="tab.menu"
|
slotId="tab.menu"
|
||||||
when={{ tab: ctxTab, handle: ctxTab.terminalRef?.current }}
|
when={{ tab: ctxTab, handle: ctxTab.terminalRef?.current }}
|
||||||
context={() => [ctxTab.terminalRef?.current]}
|
context={() => [ctxTab.terminalRef?.current, ctxTab]}
|
||||||
renderItem={(contribution, invoke) => (
|
renderItem={(contribution, invoke) => (
|
||||||
<button
|
<button
|
||||||
className="flex items-center gap-2 w-full px-3 py-1.5 text-xs text-left hover:bg-accent hover:text-accent-foreground"
|
className="flex items-center gap-2 w-full px-3 py-1.5 text-xs text-left hover:bg-accent hover:text-accent-foreground"
|
||||||
|
|||||||
Reference in new issue
Block a user