fix(ui): autocomplete und Formulare für Passwort-Felder
PIN, Backup-Export/Import und API-Key entsprechen Chrome-DOM-Empfehlungen. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -273,6 +273,7 @@ export default function AuthOnboarding({ onAuthenticated, onOpenDemo }: AuthOnbo
|
|||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
|
name="new-pin"
|
||||||
inputMode="numeric"
|
inputMode="numeric"
|
||||||
pattern="[0-9]*"
|
pattern="[0-9]*"
|
||||||
maxLength={8}
|
maxLength={8}
|
||||||
@@ -282,6 +283,7 @@ export default function AuthOnboarding({ onAuthenticated, onOpenDemo }: AuthOnbo
|
|||||||
onChange={(e) => setPinInput(e.target.value.replace(/\D/g, ''))}
|
onChange={(e) => setPinInput(e.target.value.replace(/\D/g, ''))}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
required
|
required
|
||||||
|
autoComplete="new-password"
|
||||||
style={{ width: '100%', padding: '12px', boxSizing: 'border-box' }}
|
style={{ width: '100%', padding: '12px', boxSizing: 'border-box' }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
@@ -322,6 +324,7 @@ export default function AuthOnboarding({ onAuthenticated, onOpenDemo }: AuthOnbo
|
|||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
|
name="pin"
|
||||||
inputMode="numeric"
|
inputMode="numeric"
|
||||||
pattern="[0-9]*"
|
pattern="[0-9]*"
|
||||||
maxLength={8}
|
maxLength={8}
|
||||||
@@ -331,6 +334,7 @@ export default function AuthOnboarding({ onAuthenticated, onOpenDemo }: AuthOnbo
|
|||||||
onChange={(e) => setPinLoginInput(e.target.value.replace(/\D/g, ''))}
|
onChange={(e) => setPinLoginInput(e.target.value.replace(/\D/g, ''))}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
required
|
required
|
||||||
|
autoComplete="current-password"
|
||||||
style={{ width: '100%', padding: '12px', boxSizing: 'border-box' }}
|
style={{ width: '100%', padding: '12px', boxSizing: 'border-box' }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -58,6 +58,16 @@ export default function LogbookBackupPanel({ logbookId, onRestored }: LogbookBac
|
|||||||
const [error, setError] = useState<string | null>(null)
|
const [error, setError] = useState<string | null>(null)
|
||||||
const [success, setSuccess] = useState<string | null>(null)
|
const [success, setSuccess] = useState<string | null>(null)
|
||||||
|
|
||||||
|
const handleExportSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
await handleExport()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleImportSubmit = async (e: React.FormEvent) => {
|
||||||
|
e.preventDefault()
|
||||||
|
await handleRestore()
|
||||||
|
}
|
||||||
|
|
||||||
const handleExport = async () => {
|
const handleExport = async () => {
|
||||||
setError(null)
|
setError(null)
|
||||||
setSuccess(null)
|
setSuccess(null)
|
||||||
@@ -209,10 +219,12 @@ export default function LogbookBackupPanel({ logbookId, onRestored }: LogbookBac
|
|||||||
</h4>
|
</h4>
|
||||||
<p className="text-muted backup-section-desc">{t('settings.backup_export_desc')}</p>
|
<p className="text-muted backup-section-desc">{t('settings.backup_export_desc')}</p>
|
||||||
|
|
||||||
|
<form onSubmit={handleExportSubmit} className="backup-export-form">
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
<label htmlFor="backup-export-passphrase">{t('settings.backup_passphrase')}</label>
|
<label htmlFor="backup-export-passphrase">{t('settings.backup_passphrase')}</label>
|
||||||
<input
|
<input
|
||||||
id="backup-export-passphrase"
|
id="backup-export-passphrase"
|
||||||
|
name="backup-export-passphrase"
|
||||||
type="password"
|
type="password"
|
||||||
className="input-text"
|
className="input-text"
|
||||||
value={exportPassphrase}
|
value={exportPassphrase}
|
||||||
@@ -220,29 +232,32 @@ export default function LogbookBackupPanel({ logbookId, onRestored }: LogbookBac
|
|||||||
placeholder={t('settings.backup_passphrase_placeholder')}
|
placeholder={t('settings.backup_passphrase_placeholder')}
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
disabled={exporting}
|
disabled={exporting}
|
||||||
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
<label htmlFor="backup-export-confirm">{t('settings.backup_passphrase_confirm')}</label>
|
<label htmlFor="backup-export-confirm">{t('settings.backup_passphrase_confirm')}</label>
|
||||||
<input
|
<input
|
||||||
id="backup-export-confirm"
|
id="backup-export-confirm"
|
||||||
|
name="backup-export-confirm"
|
||||||
type="password"
|
type="password"
|
||||||
className="input-text"
|
className="input-text"
|
||||||
value={exportConfirm}
|
value={exportConfirm}
|
||||||
onChange={(e) => setExportConfirm(e.target.value)}
|
onChange={(e) => setExportConfirm(e.target.value)}
|
||||||
autoComplete="new-password"
|
autoComplete="new-password"
|
||||||
disabled={exporting}
|
disabled={exporting}
|
||||||
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="submit"
|
||||||
className="btn primary"
|
className="btn primary"
|
||||||
onClick={handleExport}
|
|
||||||
disabled={exporting || !exportPassphrase || !exportConfirm}
|
disabled={exporting || !exportPassphrase || !exportConfirm}
|
||||||
>
|
>
|
||||||
<Download size={16} />
|
<Download size={16} />
|
||||||
{exporting ? t('settings.backup_exporting') : t('settings.backup_export_btn')}
|
{exporting ? t('settings.backup_exporting') : t('settings.backup_export_btn')}
|
||||||
</button>
|
</button>
|
||||||
|
</form>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section className="backup-section backup-section--import" aria-labelledby="backup-import-heading">
|
<section className="backup-section backup-section--import" aria-labelledby="backup-import-heading">
|
||||||
@@ -252,6 +267,7 @@ export default function LogbookBackupPanel({ logbookId, onRestored }: LogbookBac
|
|||||||
</h4>
|
</h4>
|
||||||
<p className="text-muted backup-section-desc">{t('settings.backup_restore_desc')}</p>
|
<p className="text-muted backup-section-desc">{t('settings.backup_restore_desc')}</p>
|
||||||
|
|
||||||
|
<form onSubmit={handleImportSubmit} className="backup-import-form">
|
||||||
<div className="input-group">
|
<div className="input-group">
|
||||||
<label htmlFor="backup-import-file">{t('settings.backup_file_label')}</label>
|
<label htmlFor="backup-import-file">{t('settings.backup_file_label')}</label>
|
||||||
<input
|
<input
|
||||||
@@ -271,6 +287,7 @@ export default function LogbookBackupPanel({ logbookId, onRestored }: LogbookBac
|
|||||||
<label htmlFor="backup-import-passphrase">{t('settings.backup_passphrase')}</label>
|
<label htmlFor="backup-import-passphrase">{t('settings.backup_passphrase')}</label>
|
||||||
<input
|
<input
|
||||||
id="backup-import-passphrase"
|
id="backup-import-passphrase"
|
||||||
|
name="backup-import-passphrase"
|
||||||
type="password"
|
type="password"
|
||||||
className="input-text"
|
className="input-text"
|
||||||
value={importPassphrase}
|
value={importPassphrase}
|
||||||
@@ -280,6 +297,7 @@ export default function LogbookBackupPanel({ logbookId, onRestored }: LogbookBac
|
|||||||
}}
|
}}
|
||||||
autoComplete="current-password"
|
autoComplete="current-password"
|
||||||
disabled={importing}
|
disabled={importing}
|
||||||
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -293,9 +311,8 @@ export default function LogbookBackupPanel({ logbookId, onRestored }: LogbookBac
|
|||||||
{previewing ? t('settings.backup_previewing') : t('settings.backup_preview_btn')}
|
{previewing ? t('settings.backup_previewing') : t('settings.backup_preview_btn')}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="submit"
|
||||||
className="btn primary"
|
className="btn primary"
|
||||||
onClick={() => handleRestore()}
|
|
||||||
disabled={importing || !importPassphrase}
|
disabled={importing || !importPassphrase}
|
||||||
>
|
>
|
||||||
<Upload size={16} />
|
<Upload size={16} />
|
||||||
@@ -304,6 +321,7 @@ export default function LogbookBackupPanel({ logbookId, onRestored }: LogbookBac
|
|||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
</form>
|
||||||
|
|
||||||
{importPreview && (
|
{importPreview && (
|
||||||
<div className="backup-preview glass">
|
<div className="backup-preview glass">
|
||||||
|
|||||||
@@ -293,12 +293,14 @@ export default function SettingsForm({ logbookId, onLogbookRestored }: SettingsF
|
|||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
id="owm-api-key"
|
id="owm-api-key"
|
||||||
|
name="owm-api-key"
|
||||||
type="password"
|
type="password"
|
||||||
className="input-text"
|
className="input-text"
|
||||||
placeholder="e.g. 8b6a7f...d8"
|
placeholder="e.g. 8b6a7f...d8"
|
||||||
value={apiKey}
|
value={apiKey}
|
||||||
onChange={(e) => setApiKey(e.target.value)}
|
onChange={(e) => setApiKey(e.target.value)}
|
||||||
disabled={saving}
|
disabled={saving}
|
||||||
|
autoComplete="off"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user