Add terminal code snippets feature #341
@@ -281,7 +281,14 @@ router.post(
|
|||||||
sshDataObj.keyPassword = keyPassword || null;
|
sshDataObj.keyPassword = keyPassword || null;
|
||||||
sshDataObj.keyType = keyType;
|
sshDataObj.keyType = keyType;
|
||||||
sshDataObj.password = null;
|
sshDataObj.password = null;
|
||||||
|
} else if (effectiveAuthType === "none") {
|
||||||
|
// No authentication credentials - set all to null
|
||||||
|
sshDataObj.password = null;
|
||||||
|
sshDataObj.key = null;
|
||||||
|
sshDataObj.keyPassword = null;
|
||||||
|
sshDataObj.keyType = null;
|
||||||
} else {
|
} else {
|
||||||
|
// credential type or fallback - set all to null except credentialId
|
||||||
sshDataObj.password = null;
|
sshDataObj.password = null;
|
||||||
sshDataObj.key = null;
|
sshDataObj.key = null;
|
||||||
sshDataObj.keyPassword = null;
|
sshDataObj.keyPassword = null;
|
||||||
@@ -471,7 +478,14 @@ router.put(
|
|||||||
sshDataObj.keyType = keyType;
|
sshDataObj.keyType = keyType;
|
||||||
}
|
}
|
||||||
sshDataObj.password = null;
|
sshDataObj.password = null;
|
||||||
|
} else if (effectiveAuthType === "none") {
|
||||||
|
// No authentication credentials - set all to null
|
||||||
|
sshDataObj.password = null;
|
||||||
|
sshDataObj.key = null;
|
||||||
|
sshDataObj.keyPassword = null;
|
||||||
|
sshDataObj.keyType = null;
|
||||||
} else {
|
} else {
|
||||||
|
// credential type or fallback - set all to null except credentialId
|
||||||
sshDataObj.password = null;
|
sshDataObj.password = null;
|
||||||
sshDataObj.key = null;
|
sshDataObj.key = null;
|
||||||
sshDataObj.keyPassword = null;
|
sshDataObj.keyPassword = null;
|
||||||
@@ -1356,10 +1370,12 @@ router.post(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!["password", "key", "credential"].includes(hostData.authType)) {
|
if (
|
||||||
|
!["password", "key", "credential", "none"].includes(hostData.authType)
|
||||||
|
) {
|
||||||
results.failed++;
|
results.failed++;
|
||||||
results.errors.push(
|
results.errors.push(
|
||||||
`Host ${i + 1}: Invalid authType. Must be 'password', 'key', or 'credential'`,
|
`Host ${i + 1}: Invalid authType. Must be 'password', 'key', 'credential', or 'none'`,
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1391,6 +1407,8 @@ router.post(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// "none" authType requires no validation - no credentials needed
|
||||||
|
|
||||||
const sshDataObj: any = {
|
const sshDataObj: any = {
|
||||||
userId: userId,
|
userId: userId,
|
||||||
name: hostData.name || `${hostData.username}@${hostData.ip}`,
|
name: hostData.name || `${hostData.username}@${hostData.ip}`,
|
||||||
|
|||||||
@@ -639,6 +639,8 @@
|
|||||||
"password": "Password",
|
"password": "Password",
|
||||||
"key": "Key",
|
"key": "Key",
|
||||||
"credential": "Credential",
|
"credential": "Credential",
|
||||||
|
"none": "None",
|
||||||
|
"noneDescription": "No authentication credentials required. You can add credentials later or use SSH agent for authentication.",
|
||||||
"selectCredential": "Select Credential",
|
"selectCredential": "Select Credential",
|
||||||
"selectCredentialPlaceholder": "Choose a credential...",
|
"selectCredentialPlaceholder": "Choose a credential...",
|
||||||
"credentialRequired": "Credential is required when using credential authentication",
|
"credentialRequired": "Credential is required when using credential authentication",
|
||||||
|
|||||||
@@ -635,6 +635,8 @@
|
|||||||
"password": "密码",
|
"password": "密码",
|
||||||
"key": "密钥",
|
"key": "密钥",
|
||||||
"credential": "凭证",
|
"credential": "凭证",
|
||||||
|
"none": "无",
|
||||||
|
"noneDescription": "无需认证凭证。您可以稍后添加凭证或使用 SSH 代理进行认证。",
|
||||||
"selectCredential": "选择凭证",
|
"selectCredential": "选择凭证",
|
||||||
"selectCredentialPlaceholder": "选择一个凭证...",
|
"selectCredentialPlaceholder": "选择一个凭证...",
|
||||||
"credentialRequired": "使用凭证认证时需要选择凭证",
|
"credentialRequired": "使用凭证认证时需要选择凭证",
|
||||||
|
|||||||
+2
-2
@@ -18,7 +18,7 @@ export interface SSHHost {
|
|||||||
folder: string;
|
folder: string;
|
||||||
tags: string[];
|
tags: string[];
|
||||||
pin: boolean;
|
pin: boolean;
|
||||||
authType: "password" | "key" | "credential";
|
authType: "password" | "key" | "credential" | "none";
|
||||||
password?: string;
|
password?: string;
|
||||||
key?: string;
|
key?: string;
|
||||||
keyPassword?: string;
|
keyPassword?: string;
|
||||||
@@ -47,7 +47,7 @@ export interface SSHHostData {
|
|||||||
folder?: string;
|
folder?: string;
|
||||||
tags?: string[];
|
tags?: string[];
|
||||||
pin?: boolean;
|
pin?: boolean;
|
||||||
authType: "password" | "key" | "credential";
|
authType: "password" | "key" | "credential" | "none";
|
||||||
password?: string;
|
password?: string;
|
||||||
key?: File | null;
|
key?: File | null;
|
||||||
keyPassword?: string;
|
keyPassword?: string;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ interface SSHHost {
|
|||||||
folder: string;
|
folder: string;
|
||||||
tags: string[];
|
tags: string[];
|
||||||
pin: boolean;
|
pin: boolean;
|
||||||
authType: string;
|
authType: "password" | "key" | "credential" | "none";
|
||||||
password?: string;
|
password?: string;
|
||||||
key?: string;
|
key?: string;
|
||||||
keyPassword?: string;
|
keyPassword?: string;
|
||||||
@@ -79,9 +79,9 @@ export function HostManagerEditor({
|
|||||||
const [credentials, setCredentials] = useState<any[]>([]);
|
const [credentials, setCredentials] = useState<any[]>([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
const [authTab, setAuthTab] = useState<"password" | "key" | "credential">(
|
const [authTab, setAuthTab] = useState<
|
||||||
"password",
|
"password" | "key" | "credential" | "none"
|
||||||
);
|
>("password");
|
||||||
const [keyInputMethod, setKeyInputMethod] = useState<"upload" | "paste">(
|
const [keyInputMethod, setKeyInputMethod] = useState<"upload" | "paste">(
|
||||||
"upload",
|
"upload",
|
||||||
);
|
);
|
||||||
@@ -174,7 +174,7 @@ export function HostManagerEditor({
|
|||||||
folder: z.string().optional(),
|
folder: z.string().optional(),
|
||||||
tags: z.array(z.string().min(1)).default([]),
|
tags: z.array(z.string().min(1)).default([]),
|
||||||
pin: z.boolean().default(false),
|
pin: z.boolean().default(false),
|
||||||
authType: z.enum(["password", "key", "credential"]),
|
authType: z.enum(["password", "key", "credential", "none"]),
|
||||||
credentialId: z.number().optional().nullable(),
|
credentialId: z.number().optional().nullable(),
|
||||||
password: z.string().optional(),
|
password: z.string().optional(),
|
||||||
key: z.any().optional().nullable(),
|
key: z.any().optional().nullable(),
|
||||||
@@ -210,6 +210,11 @@ export function HostManagerEditor({
|
|||||||
defaultPath: z.string().optional(),
|
defaultPath: z.string().optional(),
|
||||||
})
|
})
|
||||||
.superRefine((data, ctx) => {
|
.superRefine((data, ctx) => {
|
||||||
|
// Skip authentication validation for "none" type
|
||||||
|
if (data.authType === "none") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (data.authType === "key") {
|
if (data.authType === "key") {
|
||||||
if (
|
if (
|
||||||
!data.key ||
|
!data.key ||
|
||||||
@@ -313,7 +318,9 @@ export function HostManagerEditor({
|
|||||||
? "credential"
|
? "credential"
|
||||||
: cleanedHost.key
|
: cleanedHost.key
|
||||||
? "key"
|
? "key"
|
||||||
: "password";
|
: cleanedHost.password
|
||||||
|
? "password"
|
||||||
|
: "none";
|
||||||
setAuthTab(defaultAuthType);
|
setAuthTab(defaultAuthType);
|
||||||
|
|
||||||
const formData = {
|
const formData = {
|
||||||
@@ -324,7 +331,7 @@ export function HostManagerEditor({
|
|||||||
folder: cleanedHost.folder || "",
|
folder: cleanedHost.folder || "",
|
||||||
tags: cleanedHost.tags || [],
|
tags: cleanedHost.tags || [],
|
||||||
pin: Boolean(cleanedHost.pin),
|
pin: Boolean(cleanedHost.pin),
|
||||||
authType: defaultAuthType as "password" | "key" | "credential",
|
authType: defaultAuthType as "password" | "key" | "credential" | "none",
|
||||||
credentialId: null,
|
credentialId: null,
|
||||||
password: "",
|
password: "",
|
||||||
key: null,
|
key: null,
|
||||||
@@ -863,7 +870,8 @@ export function HostManagerEditor({
|
|||||||
const newAuthType = value as
|
const newAuthType = value as
|
||||||
| "password"
|
| "password"
|
||||||
| "key"
|
| "key"
|
||||||
| "credential";
|
| "credential"
|
||||||
|
| "none";
|
||||||
setAuthTab(newAuthType);
|
setAuthTab(newAuthType);
|
||||||
form.setValue("authType", newAuthType);
|
form.setValue("authType", newAuthType);
|
||||||
|
|
||||||
@@ -880,6 +888,13 @@ export function HostManagerEditor({
|
|||||||
form.setValue("key", null);
|
form.setValue("key", null);
|
||||||
form.setValue("keyPassword", "");
|
form.setValue("keyPassword", "");
|
||||||
form.setValue("keyType", "auto");
|
form.setValue("keyType", "auto");
|
||||||
|
} else if (newAuthType === "none") {
|
||||||
|
// Clear all authentication fields for "none" type
|
||||||
|
form.setValue("password", "");
|
||||||
|
form.setValue("key", null);
|
||||||
|
form.setValue("keyPassword", "");
|
||||||
|
form.setValue("keyType", "auto");
|
||||||
|
form.setValue("credentialId", null);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className="flex-1 flex flex-col h-full min-h-0"
|
className="flex-1 flex flex-col h-full min-h-0"
|
||||||
@@ -892,6 +907,7 @@ export function HostManagerEditor({
|
|||||||
<TabsTrigger value="credential">
|
<TabsTrigger value="credential">
|
||||||
{t("hosts.credential")}
|
{t("hosts.credential")}
|
||||||
</TabsTrigger>
|
</TabsTrigger>
|
||||||
|
<TabsTrigger value="none">{t("hosts.none")}</TabsTrigger>
|
||||||
</TabsList>
|
</TabsList>
|
||||||
<TabsContent value="password">
|
<TabsContent value="password">
|
||||||
<FormField
|
<FormField
|
||||||
@@ -1110,6 +1126,13 @@ export function HostManagerEditor({
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
|
<TabsContent value="none">
|
||||||
|
<FormItem>
|
||||||
|
<FormDescription>
|
||||||
|
{t("hosts.noneDescription")}
|
||||||
|
</FormDescription>
|
||||||
|
</FormItem>
|
||||||
|
</TabsContent>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
</TabsContent>
|
</TabsContent>
|
||||||
<TabsContent value="terminal">
|
<TabsContent value="terminal">
|
||||||
|
|||||||
Reference in New Issue
Block a user