+
{renderActiveView()}
diff --git a/src/apps/Homepage/Homepage.tsx b/src/apps/Homepage/Homepage.tsx
index 60aa9464..0279f175 100644
--- a/src/apps/Homepage/Homepage.tsx
+++ b/src/apps/Homepage/Homepage.tsx
@@ -68,16 +68,14 @@ export function Homepage({onSelectView}: HomepageProps): React.ReactElement {
}, []);
return (
-
-
-
-
-
+ )}
{(!internalLoggedIn && (!authLoading || !getCookie("jwt"))) && (
<>
+
+
+
);
}
\ No newline at end of file
diff --git a/src/apps/Homepage/HomepageAuth.tsx b/src/apps/Homepage/HomepageAuth.tsx
index a078cfcf..185ac43d 100644
--- a/src/apps/Homepage/HomepageAuth.tsx
+++ b/src/apps/Homepage/HomepageAuth.tsx
@@ -249,50 +249,50 @@ export function HomepageAuth({
)}
{(internalLoggedIn || (authLoading && getCookie("jwt"))) && (
+
-
-
-
-
- Logged in!
-
- You are logged in! Use the sidebar to access all available tools. To get started,
- create an SSH Host in the SSH Manager tab. Once created, you can connect to that
- host using the other apps in the sidebar.
-
-
+
+ Logged in!
+
+ You are logged in! Use the sidebar to access all available tools. To get started,
+ create an SSH Host in the SSH Manager tab. Once created, you can connect to that
+ host using the other apps in the sidebar.
+
+
-
- )}
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
diff --git a/src/apps/Homepage/HomepageSidebar.tsx b/src/apps/Homepage/HomepageSidebar.tsx
index 8608b8db..30f4e524 100644
--- a/src/apps/Homepage/HomepageSidebar.tsx
+++ b/src/apps/Homepage/HomepageSidebar.tsx
@@ -14,7 +14,7 @@ import {
SidebarGroupLabel,
SidebarMenu,
SidebarMenuButton,
- SidebarMenuItem, SidebarProvider,
+ SidebarMenuItem, SidebarProvider, SidebarInset,
} from "@/components/ui/sidebar.tsx"
import {
@@ -44,6 +44,7 @@ interface SidebarProps {
disabled?: boolean;
isAdmin?: boolean;
username?: string | null;
+ children?: React.ReactNode;
}
function handleLogout() {
@@ -72,7 +73,8 @@ export function HomepageSidebar({
getView,
disabled,
isAdmin,
- username
+ username,
+ children,
}: SidebarProps): React.ReactElement {
const [adminSheetOpen, setAdminSheetOpen] = React.useState(false);
const [allowRegistration, setAllowRegistration] = React.useState(true);
@@ -160,7 +162,7 @@ export function HomepageSidebar({
};
return (
-
+
@@ -430,6 +432,9 @@ export function HomepageSidebar({
)}
+
+ {children}
+
)
diff --git a/src/apps/Homepage/HompageUpdateLog.tsx b/src/apps/Homepage/HompageUpdateLog.tsx
index 7453dd8c..3a72c18f 100644
--- a/src/apps/Homepage/HompageUpdateLog.tsx
+++ b/src/apps/Homepage/HompageUpdateLog.tsx
@@ -98,7 +98,7 @@ export function HomepageUpdateLog({loggedIn}: HomepageUpdateLogProps) {
};
return (
-
+
@@ -332,6 +344,19 @@ export function SSHSidebar({onSelectView, onHostConnect, allTabs, runCommandOnTa
+
+
+
+
diff --git a/src/apps/SSH/Terminal/SSHTerminal.tsx b/src/apps/SSH/Terminal/SSHTerminal.tsx
index c198469c..e26a1236 100644
--- a/src/apps/SSH/Terminal/SSHTerminal.tsx
+++ b/src/apps/SSH/Terminal/SSHTerminal.tsx
@@ -52,6 +52,49 @@ export const SSHTerminal = forwardRef(function SSHTermina
fitAddonRef.current?.fit();
}
+ function getCookie(name: string) {
+ return document.cookie.split('; ').reduce((r, v) => {
+ const parts = v.split('=');
+ return parts[0] === name ? decodeURIComponent(parts[1]) : r;
+ }, "");
+ }
+
+ function getUseRightClickCopyPaste() {
+ return getCookie("rightClickCopyPaste") === "true"
+ }
+
+ async function writeTextToClipboard(text: string): Promise {
+ try {
+ if (navigator.clipboard && navigator.clipboard.writeText) {
+ await navigator.clipboard.writeText(text);
+ return;
+ }
+ } catch (_) {
+ }
+ const textarea = document.createElement('textarea');
+ textarea.value = text;
+ textarea.style.position = 'fixed';
+ textarea.style.left = '-9999px';
+ document.body.appendChild(textarea);
+ textarea.focus();
+ textarea.select();
+ try {
+ document.execCommand('copy');
+ } finally {
+ document.body.removeChild(textarea);
+ }
+ }
+
+ async function readTextFromClipboard(): Promise {
+ try {
+ if (navigator.clipboard && navigator.clipboard.readText) {
+ return await navigator.clipboard.readText();
+ }
+ } catch (_) {
+ }
+ return '';
+ }
+
useEffect(() => {
if (!terminal || !xtermRef.current || !hostConfig) return;
@@ -59,7 +102,7 @@ export const SSHTerminal = forwardRef(function SSHTermina
cursorBlink: true,
cursorStyle: 'bar',
scrollback: 10000,
- fontSize: 15,
+ fontSize: 14,
fontFamily: '"JetBrains Mono Nerd Font", "MesloLGS NF", "FiraCode Nerd Font", "Cascadia Code", "JetBrains Mono", Consolas, "Courier New", monospace',
theme: {
background: '#09090b',
@@ -88,6 +131,31 @@ export const SSHTerminal = forwardRef(function SSHTermina
terminal.loadAddon(webLinksAddon);
terminal.open(xtermRef.current);
+ const element = xtermRef.current;
+ const handleContextMenu = async (e: MouseEvent) => {
+ if (!getUseRightClickCopyPaste()) return;
+ e.preventDefault();
+ e.stopPropagation();
+ try {
+ if (terminal.hasSelection()) {
+ const selection = terminal.getSelection();
+ if (selection) {
+ await writeTextToClipboard(selection);
+ terminal.clearSelection();
+ }
+ } else {
+ const pasteText = await readTextFromClipboard();
+ if (pasteText) {
+ terminal.paste(pasteText);
+ }
+ }
+ } catch (_) {
+ }
+ };
+ if (element) {
+ element.addEventListener('contextmenu', handleContextMenu);
+ }
+
const resizeObserver = new ResizeObserver(() => {
if (resizeTimeout.current) clearTimeout(resizeTimeout.current);
resizeTimeout.current = setTimeout(() => {
@@ -158,6 +226,9 @@ export const SSHTerminal = forwardRef(function SSHTermina
return () => {
resizeObserver.disconnect();
+ if (element) {
+ element.removeEventListener('contextmenu', handleContextMenu);
+ }
if (resizeTimeout.current) clearTimeout(resizeTimeout.current);
if (pingIntervalRef.current) {
clearInterval(pingIntervalRef.current);
Updates & Releases
diff --git a/src/apps/SSH/Terminal/SSHSidebar.tsx b/src/apps/SSH/Terminal/SSHSidebar.tsx index 634db0d2..f890d4fc 100644 --- a/src/apps/SSH/Terminal/SSHSidebar.tsx +++ b/src/apps/SSH/Terminal/SSHSidebar.tsx @@ -38,6 +38,7 @@ import { import {ScrollArea} from "@/components/ui/scroll-area.tsx"; import {Input} from "@/components/ui/input.tsx"; import {getSSHHosts} from "@/apps/SSH/ssh-axios"; +import {Checkbox} from "@/components/ui/checkbox.tsx"; interface SSHHost { id: number; @@ -186,6 +187,17 @@ export function SSHSidebar({onSelectView, onHostConnect, allTabs, runCommandOnTa } }; + function getCookie(name: string) { + return document.cookie.split('; ').reduce((r, v) => { + const parts = v.split('='); + return parts[0] === name ? decodeURIComponent(parts[1]) : r; + }, ""); + } + + const updateRightClickCopyPaste = (checked) => { + document.cookie = `rightClickCopyPaste=${checked}; expires=2147483647; path=/`; + } + return (
+
+
+