mirror of
https://github.com/binaricat/Netcatty.git
synced 2026-10-09 15:58:34 +00:00
4e9e5da13c
Integrates all user-facing strings into the translation system and expands locale files for comprehensive coverage, enabling dynamic i18n across the interface. Replaces hardcoded labels, button texts, and prompts with translation keys, benefiting maintainability and future language support. Improves translation ergonomics in forms, dialogs, wizards, and settings, ensuring consistent user experience in both English and Chinese.
140 lines
5.6 KiB
TypeScript
140 lines
5.6 KiB
TypeScript
/**
|
|
* Generate Key Panel - Standard SSH Key generation form
|
|
*/
|
|
|
|
import { Eye, EyeOff } from 'lucide-react';
|
|
import React from 'react';
|
|
import { useI18n } from '../../application/i18n/I18nProvider';
|
|
import { cn } from '../../lib/utils';
|
|
import { KeyType, SSHKey } from '../../types';
|
|
import { Button } from '../ui/button';
|
|
import { Input } from '../ui/input';
|
|
import { Label } from '../ui/label';
|
|
|
|
interface GenerateStandardPanelProps {
|
|
draftKey: Partial<SSHKey>;
|
|
setDraftKey: (key: Partial<SSHKey>) => void;
|
|
showPassphrase: boolean;
|
|
setShowPassphrase: (show: boolean) => void;
|
|
isGenerating: boolean;
|
|
onGenerate: () => void;
|
|
}
|
|
|
|
export const GenerateStandardPanel: React.FC<GenerateStandardPanelProps> = ({
|
|
draftKey,
|
|
setDraftKey,
|
|
showPassphrase,
|
|
setShowPassphrase,
|
|
isGenerating,
|
|
onGenerate,
|
|
}) => {
|
|
const { t } = useI18n();
|
|
return (
|
|
<>
|
|
<div className="space-y-2">
|
|
<Label>{t('keychain.field.label')}</Label>
|
|
<Input
|
|
value={draftKey.label || ''}
|
|
onChange={e => setDraftKey({ ...draftKey, label: e.target.value })}
|
|
placeholder={t('keychain.generate.labelPlaceholder')}
|
|
/>
|
|
</div>
|
|
|
|
<div className="space-y-2">
|
|
<Label>{t('keychain.generate.keyType')}</Label>
|
|
<div className="flex gap-2">
|
|
{(['ED25519', 'ECDSA', 'RSA'] as KeyType[]).map((t) => (
|
|
<Button
|
|
key={t}
|
|
variant={draftKey.type === t ? 'secondary' : 'ghost'}
|
|
className={cn(
|
|
"flex-1 h-10",
|
|
draftKey.type === t && "bg-primary/15 text-primary"
|
|
)}
|
|
onClick={() => {
|
|
// Set default keySize based on type
|
|
const defaultSize = t === 'ED25519' ? undefined : (t === 'RSA' ? 4096 : 256);
|
|
setDraftKey({ ...draftKey, type: t, keySize: defaultSize });
|
|
}}
|
|
>
|
|
{t}
|
|
</Button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Key Size selector - only for RSA and ECDSA */}
|
|
{(draftKey.type === 'RSA' || draftKey.type === 'ECDSA') && (
|
|
<div className="space-y-2">
|
|
<Label>{t('keychain.generate.keySize')}</Label>
|
|
<div className="flex gap-2">
|
|
{(draftKey.type === 'RSA'
|
|
? [4096, 2048, 1024]
|
|
: [256, 384, 521]
|
|
).map((size) => (
|
|
<Button
|
|
key={size}
|
|
variant={draftKey.keySize === size ? 'secondary' : 'ghost'}
|
|
className={cn(
|
|
"flex-1 h-10",
|
|
draftKey.keySize === size && "bg-primary/15 text-primary"
|
|
)}
|
|
onClick={() => setDraftKey({ ...draftKey, keySize: size })}
|
|
>
|
|
{draftKey.type === 'RSA' ? `${size} bits` : `P-${size}`}
|
|
</Button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<div className="space-y-2">
|
|
<Label>{t('terminal.auth.passphrase')}</Label>
|
|
<div className="relative">
|
|
<Input
|
|
type={showPassphrase ? 'text' : 'password'}
|
|
value={draftKey.passphrase || ''}
|
|
onChange={e => setDraftKey({ ...draftKey, passphrase: e.target.value })}
|
|
placeholder={t('keychain.generate.passphrasePlaceholder')}
|
|
className="pr-10"
|
|
/>
|
|
<Button
|
|
type="button"
|
|
variant="ghost"
|
|
size="icon"
|
|
className="absolute right-1 top-1/2 -translate-y-1/2 h-8 w-8"
|
|
onClick={() => setShowPassphrase(!showPassphrase)}
|
|
>
|
|
{showPassphrase ? <EyeOff size={14} /> : <Eye size={14} />}
|
|
</Button>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-2">
|
|
<input
|
|
type="checkbox"
|
|
id="savePassphrase"
|
|
checked={draftKey.savePassphrase || false}
|
|
onChange={e => setDraftKey({ ...draftKey, savePassphrase: e.target.checked })}
|
|
className="h-4 w-4 rounded border-border"
|
|
/>
|
|
<Label htmlFor="savePassphrase" className="text-sm font-normal cursor-pointer">
|
|
{t('keychain.generate.savePassphrase')}
|
|
</Label>
|
|
</div>
|
|
|
|
<Button
|
|
className="w-full h-11"
|
|
onClick={onGenerate}
|
|
disabled={isGenerating || !draftKey.label?.trim()}
|
|
>
|
|
{isGenerating ? (
|
|
<div className="h-4 w-4 border-2 border-primary-foreground/30 border-t-primary-foreground rounded-full animate-spin" />
|
|
) : (
|
|
t('keychain.generate.generateSave')
|
|
)}
|
|
</Button>
|
|
</>
|
|
);
|
|
};
|