@@ -162,11 +167,7 @@ export function TunnelObject({
size="sm"
variant="outline"
onClick={() =>
- onTunnelAction(
- "disconnect",
- host,
- tunnelIndex,
- )
+ onTunnelAction("disconnect", host, idx)
}
className="h-7 px-2 text-red-600 dark:text-red-400 border-red-500/30 dark:border-red-400/30 hover:bg-red-500/10 dark:hover:bg-red-400/10 hover:border-red-500/50 dark:hover:border-red-400/50 text-xs"
>
@@ -179,7 +180,7 @@ export function TunnelObject({
size="sm"
variant="outline"
onClick={() =>
- onTunnelAction("cancel", host, tunnelIndex)
+ onTunnelAction("cancel", host, idx)
}
className="h-7 px-2 text-orange-600 dark:text-orange-400 border-orange-500/30 dark:border-orange-400/30 hover:bg-orange-500/10 dark:hover:bg-orange-400/10 hover:border-orange-500/50 dark:hover:border-orange-400/50 text-xs"
>
@@ -191,7 +192,7 @@ export function TunnelObject({
size="sm"
variant="outline"
onClick={() =>
- onTunnelAction("connect", host, tunnelIndex)
+ onTunnelAction("connect", host, idx)
}
disabled={isConnecting || isDisconnecting}
className="h-7 px-2 text-green-600 dark:text-green-400 border-green-500/30 dark:border-green-400/30 hover:bg-green-500/10 dark:hover:bg-green-400/10 hover:border-green-500/50 dark:hover:border-green-400/50 text-xs"
@@ -344,15 +345,20 @@ export function TunnelObject({
{!compact && (
- {t("tunnels.tunnelConnections")} ({host.tunnelConnections.length})
+ {t("tunnels.tunnelConnections")} (
+ {tunnelIndex !== undefined ? 1 : host.tunnelConnections.length})
)}
{host.tunnelConnections && host.tunnelConnections.length > 0 ? (
- {host.tunnelConnections.map((tunnel, tunnelIndex) => {
- const status = getTunnelStatus(tunnelIndex);
+ {(tunnelIndex !== undefined
+ ? [tunnelIndex]
+ : host.tunnelConnections.map((_, idx) => idx)
+ ).map((idx) => {
+ const tunnel = host.tunnelConnections[idx];
+ const status = getTunnelStatus(idx);
const statusDisplay = getTunnelStatusDisplay(status);
- const tunnelName = `${host.id}::${tunnelIndex}::${host.name || `${host.username}@${host.ip}`}::${tunnel.sourcePort}::${tunnel.endpointHost}::${tunnel.endpointPort}`;
+ const tunnelName = `${host.id}::${idx}::${host.name || `${host.username}@${host.ip}`}::${tunnel.sourcePort}::${tunnel.endpointHost}::${tunnel.endpointPort}`;
const isActionLoading = tunnelActions[tunnelName];
const statusValue =
status?.status?.toUpperCase() || "DISCONNECTED";
@@ -364,7 +370,7 @@ export function TunnelObject({
return (
@@ -395,11 +401,7 @@ export function TunnelObject({
size="sm"
variant="outline"
onClick={() =>
- onTunnelAction(
- "disconnect",
- host,
- tunnelIndex,
- )
+ onTunnelAction("disconnect", host, idx)
}
className="h-7 px-2 text-red-600 dark:text-red-400 border-red-500/30 dark:border-red-400/30 hover:bg-red-500/10 dark:hover:bg-red-400/10 hover:border-red-500/50 dark:hover:border-red-400/50 text-xs"
>
@@ -412,7 +414,7 @@ export function TunnelObject({
size="sm"
variant="outline"
onClick={() =>
- onTunnelAction("cancel", host, tunnelIndex)
+ onTunnelAction("cancel", host, idx)
}
className="h-7 px-2 text-orange-600 dark:text-orange-400 border-orange-500/30 dark:border-orange-400/30 hover:bg-orange-500/10 dark:hover:bg-orange-400/10 hover:border-orange-500/50 dark:hover:border-orange-400/50 text-xs"
>
@@ -424,7 +426,7 @@ export function TunnelObject({
size="sm"
variant="outline"
onClick={() =>
- onTunnelAction("connect", host, tunnelIndex)
+ onTunnelAction("connect", host, idx)
}
disabled={isConnecting || isDisconnecting}
className="h-7 px-2 text-green-600 dark:text-green-400 border-green-500/30 dark:border-green-400/30 hover:bg-green-500/10 dark:hover:bg-green-400/10 hover:border-green-500/50 dark:hover:border-green-400/50 text-xs"
diff --git a/src/ui/desktop/apps/features/tunnel/TunnelViewer.tsx b/src/ui/desktop/apps/features/tunnel/TunnelViewer.tsx
index 51ef337e..f63324b9 100644
--- a/src/ui/desktop/apps/features/tunnel/TunnelViewer.tsx
+++ b/src/ui/desktop/apps/features/tunnel/TunnelViewer.tsx
@@ -47,16 +47,12 @@ export function TunnelViewer({
{activeHost.tunnelConnections.map((t, idx) => (
- onTunnelAction(action, activeHost, idx)
- }
+ onTunnelAction={onTunnelAction}
compact
bare
/>
diff --git a/src/ui/desktop/apps/host-manager/hosts/tabs/HostSharingTab.tsx b/src/ui/desktop/apps/host-manager/hosts/tabs/HostSharingTab.tsx
index d66f3bf1..0f94d9e5 100644
--- a/src/ui/desktop/apps/host-manager/hosts/tabs/HostSharingTab.tsx
+++ b/src/ui/desktop/apps/host-manager/hosts/tabs/HostSharingTab.tsx
@@ -279,6 +279,17 @@ export function HostSharingTab({
{t("rbac.shareHost")}
+
+ window.open("https://docs.termix.site/rbac", "_blank")
+ }
+ >
+ {t("common.documentation")}
+
+
setShareType(v as "user" | "role")}
diff --git a/src/ui/desktop/navigation/TOTPDialog.tsx b/src/ui/desktop/navigation/TOTPDialog.tsx
index b871e97f..ae9d292e 100644
--- a/src/ui/desktop/navigation/TOTPDialog.tsx
+++ b/src/ui/desktop/navigation/TOTPDialog.tsx
@@ -30,14 +30,13 @@ export function TOTPDialog({
className="absolute inset-0 bg-canvas rounded-md"
style={{ backgroundColor: backgroundColor || undefined }}
/>
-
+
{t("terminal.totpRequired")}
-
{prompt}