v1.10.0 #471

Merged
LukeGus merged 106 commits from dev-1.10.0 into main 2026-01-01 04:20:12 +00:00
11 changed files with 1585 additions and 1422 deletions
Showing only changes of commit 208110a433 - Show all commits

View File

@@ -705,6 +705,7 @@ export const DEFAULT_TERMINAL_CONFIG = {
startupSnippetId: null as number | null,
autoMosh: false,
moshCommand: "mosh-server new -s -l LANG=en_US.UTF-8",
sudoPasswordAutoFill: false,
};
export type TerminalConfigType = typeof DEFAULT_TERMINAL_CONFIG;

View File

@@ -799,7 +799,9 @@
"searchServers": "Server durchsuchen...",
"noServerFound": "Kein Server gefunden",
"jumpHostsOrder": "Verbindungen werden in dieser Reihenfolge hergestellt: Jump-Host 1 → Jump-Host 2 → ... → Ziel-Server",
"advancedAuthSettings": "Erweiterte Authentifizierungseinstellungen"
"advancedAuthSettings": "Erweiterte Authentifizierungseinstellungen",
"sudoPasswordAutoFill": "Sudo-Passwort automatisch ausfüllen",
"sudoPasswordAutoFillDesc": "Popup anzeigen, um das Passwort bei sudo-Befehlen automatisch einzufügen"
},
"terminal": {
"title": "Terminal",
@@ -833,7 +835,11 @@
"connectionTimeout": "Zeitüberschreitung der Verbindung",
"terminalTitle": "Terminal - {{host}}",
"terminalWithPath": "Terminal - {{host}} : {{path}}",
"runTitle": "Ausführen von {{command}} {{host}}"
"runTitle": "Ausführen von {{command}} {{host}}",
"sudoPasswordPopupTitle": "Passwort einfügen?",
"sudoPasswordPopupHint": "Drücken Sie Enter zum Einfügen, Esc zum Abbrechen",
"sudoPasswordPopupConfirm": "Einfügen",
"sudoPasswordPopupDismiss": "Abbrechen"
},
"fileManager": {
"title": "Dateimanager",
@@ -1635,4 +1641,4 @@
"close": "Schließen",
"hostManager": "Host-Manager"
}
}
}

View File

@@ -908,7 +908,9 @@
"quickActionName": "Action name",
"noSnippetFound": "No snippet found",
"quickActionsOrder": "Quick action buttons will appear in the order listed above on the Server Stats page",
"advancedAuthSettings": "Advanced Authentication Settings"
"advancedAuthSettings": "Advanced Authentication Settings",
"sudoPasswordAutoFill": "Sudo Password Auto-Fill",
"sudoPasswordAutoFillDesc": "Automatically offer to insert SSH password when sudo prompts for password"
},
"terminal": {
"title": "Terminal",
@@ -946,7 +948,11 @@
"totpRequired": "Two-Factor Authentication Required",
"totpCodeLabel": "Verification Code",
"totpPlaceholder": "000000",
"totpVerify": "Verify"
"totpVerify": "Verify",
"sudoPasswordPopupTitle": "Insert Password?",
"sudoPasswordPopupHint": "Press Enter to insert, Esc to dismiss",
"sudoPasswordPopupConfirm": "Insert",
"sudoPasswordPopupDismiss": "Dismiss"
},
"fileManager": {
"title": "File Manager",
@@ -1825,4 +1831,4 @@
"close": "Close",
"hostManager": "Host Manager"
}
}
}

View File

@@ -790,7 +790,9 @@
"searchServers": "Rechercher des serveurs...",
"noServerFound": "Aucun serveur trouvé",
"jumpHostsOrder": "Les connexions seront établies dans l'ordre : Serveur de rebond 1 → Serveur de rebond 2 → ... → Serveur cible",
"advancedAuthSettings": "Paramètres d'authentification avancés"
"advancedAuthSettings": "Paramètres d'authentification avancés",
"sudoPasswordAutoFill": "Remplissage automatique du mot de passe sudo",
"sudoPasswordAutoFillDesc": "Proposer automatiquement dinsérer le mot de passe SSH lorsque sudo demande un mot de passe"
},
"terminal": {
"title": "Terminal",
@@ -828,7 +830,11 @@
"totpRequired": "Authentification à deux facteurs requise",
"totpCodeLabel": "Code de vérification",
"totpPlaceholder": "000000",
"totpVerify": "Vérifier"
"totpVerify": "Vérifier",
"sudoPasswordPopupTitle": "Insérer le mot de passe ?",
"sudoPasswordPopupHint": "Appuyez sur Entrée pour insérer, Échap pour annuler",
"sudoPasswordPopupConfirm": "Insérer",
"sudoPasswordPopupDismiss": "Annuler"
},
"fileManager": {
"title": "Gestionnaire de fichiers",
@@ -1606,4 +1612,4 @@
"ram": "Mémoire (RAM)",
"notAvailable": "N/D"
}
}
}

View File

@@ -745,7 +745,9 @@
"searchServers": "Pesquisar servidores...",
"noServerFound": "Nenhum servidor encontrado",
"jumpHostsOrder": "As conexões serão feitas na ordem: Host de Salto 1 → Host de Salto 2 → ... → Servidor de Destino",
"advancedAuthSettings": "Configurações Avançadas de Autenticação"
"advancedAuthSettings": "Configurações Avançadas de Autenticação",
"sudoPasswordAutoFill": "Preenchimento automático da senha do sudo",
"sudoPasswordAutoFillDesc": "Oferecer automaticamente inserir a senha SSH quando o sudo solicitar uma senha"
},
"terminal": {
"title": "Terminal",
@@ -779,7 +781,11 @@
"connectionTimeout": "Tempo limite de conexão esgotado",
"terminalTitle": "Terminal - {{host}}",
"terminalWithPath": "Terminal - {{host}}:{{path}}",
"runTitle": "Executando {{command}} - {{host}}"
"runTitle": "Executando {{command}} - {{host}}",
"sudoPasswordPopupTitle": "Inserir Senha?",
"sudoPasswordPopupHint": "Pressione Enter para inserir, Esc para cancelar",
"sudoPasswordPopupConfirm": "Inserir",
"sudoPasswordPopupDismiss": "Cancelar"
},
"fileManager": {
"title": "Gerenciador de Arquivos",
@@ -1034,7 +1040,6 @@
"fileSavedSuccessfully": "Arquivo salvo com sucesso",
"autoSaveFailed": "Falha no salvamento automático",
"fileAutoSaved": "Arquivo salvo automaticamente",
"moveFileFailed": "Falha ao mover {{name}}",
"moveOperationFailed": "Falha na operação de mover",
"canOnlyCompareFiles": "Só é possível comparar dois arquivos",
@@ -1528,4 +1533,4 @@
"viewMobileAppDocs": "Instalar Aplicativo Móvel",
"mobileAppDocumentation": "Documentação do Aplicativo Móvel"
}
}
}

View File

@@ -858,7 +858,9 @@
"searchServers": "Поиск серверов...",
"noServerFound": "Сервер не найден",
"jumpHostsOrder": "Подключения будут выполнены в порядке: Промежуточный хост 1 → Промежуточный хост 2 → ... → Целевой сервер",
"advancedAuthSettings": "Расширенные настройки аутентификации"
"advancedAuthSettings": "Расширенные настройки аутентификации",
"sudoPasswordAutoFill": "Автозаполнение пароля sudo",
"sudoPasswordAutoFillDesc": "Показывать всплывающее окно для автоматического ввода пароля при выполнении команд sudo"
},
"terminal": {
"title": "Терминал",
@@ -896,7 +898,11 @@
"totpRequired": "Требуется двухфакторная аутентификация",
"totpCodeLabel": "Код проверки",
"totpPlaceholder": "000000",
"totpVerify": "Проверить"
"totpVerify": "Проверить",
"sudoPasswordPopupTitle": "Вставить пароль?",
"sudoPasswordPopupHint": "Нажмите Enter для вставки, Esc для отмены",
"sudoPasswordPopupConfirm": "Вставить",
"sudoPasswordPopupDismiss": "Отмена"
},
"fileManager": {
"title": "Файловый менеджер",
@@ -1722,4 +1728,4 @@
"close": "Закрыть",
"hostManager": "Менеджер хостов"
}
}
}

View File

@@ -893,7 +893,9 @@
"searchServers": "搜索服务器...",
"noServerFound": "未找到服务器",
"jumpHostsOrder": "连接将按顺序进行:跳板主机 1 → 跳板主机 2 → ... → 目标服务器",
"advancedAuthSettings": "高级身份验证设置"
"advancedAuthSettings": "高级身份验证设置",
"sudoPasswordAutoFill": "Sudo 密码自动填充",
"sudoPasswordAutoFillDesc": "在 sudo 命令时显示弹窗以自动输入密码"
},
"terminal": {
"title": "终端",
@@ -931,7 +933,11 @@
"reconnecting": "重新连接中... ({{attempt}}/{{max}})",
"reconnected": "重新连接成功",
"maxReconnectAttemptsReached": "已达到最大重连尝试次数",
"connectionTimeout": "连接超时"
"connectionTimeout": "连接超时",
"sudoPasswordPopupTitle": "插入密码?",
"sudoPasswordPopupHint": "按 Enter 插入Esc 取消",
"sudoPasswordPopupConfirm": "插入",
"sudoPasswordPopupDismiss": "取消"
},
"fileManager": {
"title": "文件管理器",
@@ -1686,4 +1692,4 @@
"close": "关闭",
"hostManager": "主机管理器"
}
}
}

View File

@@ -329,6 +329,7 @@ export interface TerminalConfig {
startupSnippetId: number | null;
autoMosh: boolean;
moshCommand: string;
sudoPasswordAutoFill: boolean;
}
// ============================================================================
@@ -338,13 +339,13 @@ export interface TerminalConfig {
export interface TabContextTab {
id: number;
type:
| "home"
| "terminal"
| "ssh_manager"
| "server"
| "admin"
| "file_manager"
| "user_profile";
| "home"
| "terminal"
| "ssh_manager"
| "server"
| "admin"
| "file_manager"
| "user_profile";
title: string;
hostConfig?: SSHHost;
terminalRef?: any;

View File

@@ -547,6 +547,7 @@ export function HostManagerEditor({
startupSnippetId: z.number().nullable(),
autoMosh: z.boolean(),
moshCommand: z.string(),
sudoPasswordAutoFill: z.boolean(),
})
.optional(),
forceKeyboardInteractive: z.boolean().optional(),
@@ -631,7 +632,7 @@ export function HostManagerEditor({
type FormData = z.infer<typeof formSchema>;
const form = useForm<FormData>({
resolver: zodResolver(formSchema),
resolver: zodResolver(formSchema) as any,
defaultValues: {
name: "",
ip: "",
@@ -2443,6 +2444,29 @@ export function HostManagerEditor({
/>
)}
<FormField
control={form.control}
name="terminalConfig.sudoPasswordAutoFill"
render={({ field }) => (
<FormItem className="flex flex-row items-center justify-between rounded-lg border p-3">
<div className="space-y-0.5">
<FormLabel>
{t("hosts.sudoPasswordAutoFill")}
</FormLabel>
<FormDescription>
{t("hosts.sudoPasswordAutoFillDesc")}
</FormDescription>
</div>
<FormControl>
<Switch
checked={field.value}
onCheckedChange={field.onChange}
/>
</FormControl>
</FormItem>
)}
/>
<div className="space-y-2">
<label className="text-sm font-medium">
Environment Variables

View File

@@ -0,0 +1,82 @@
import { useEffect } from "react";
import { useTranslation } from "react-i18next";
import { KeyRound } from "lucide-react";
import { Button } from "@/components/ui/button.tsx";
interface SudoPasswordPopupProps {
isOpen: boolean;
hostPassword: string;
backgroundColor: string;
onConfirm: (password: string) => void;
onDismiss: () => void;
}
export function SudoPasswordPopup({
isOpen,
hostPassword,
backgroundColor,
onConfirm,
onDismiss
}: SudoPasswordPopupProps) {
const { t } = useTranslation();
useEffect(() => {
if (!isOpen) return;
const handleKeyDown = (e: KeyboardEvent) => {
if (e.key === "Enter") {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
onConfirm(hostPassword);
} else if (e.key === "Escape") {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
onDismiss();
}
};
window.addEventListener("keydown", handleKeyDown, true);
return () => window.removeEventListener("keydown", handleKeyDown, true);
}, [isOpen, onConfirm, onDismiss, hostPassword]);
if (!isOpen) return null;
return (
<div
className="absolute bottom-4 right-4 z-50 backdrop-blur-sm border border-border rounded-lg shadow-lg p-4 min-w-[280px]"
style={{ backgroundColor: backgroundColor }}
>
<div className="flex items-center gap-3 mb-3">
<div className="p-2 bg-primary/10 rounded-full">
<KeyRound className="h-5 w-5 text-primary" />
</div>
<div>
<h4 className="font-medium text-sm">
{t("terminal.sudoPasswordPopupTitle", "Insert password?")}
</h4>
<p className="text-xs text-muted-foreground">
{t("terminal.sudoPasswordPopupHint", "Press Enter to insert, Esc to dismiss")}
</p>
</div>
</div>
<div className="flex gap-2 justify-end">
<Button
variant="ghost"
size="sm"
onClick={onDismiss}
>
{t("terminal.sudoPasswordPopupDismiss", "Dismiss")}
</Button>
<Button
variant="default"
size="sm"
onClick={() => onConfirm(hostPassword)}
>
{t("terminal.sudoPasswordPopupConfirm", "Insert")}
</Button>
</div>
</div>
);
}

File diff suppressed because it is too large Load Diff