feat(quick-search): boutons par entree - utilisateur, mot de passe ou note, code 2FA (s'ils existent)
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -2133,6 +2133,9 @@ input[type="range"]::-webkit-slider-thumb {
|
||||
color: var(--text);
|
||||
overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
|
||||
}
|
||||
.quick-search-acts {
|
||||
display: flex; gap: 2px; flex-shrink: 0;
|
||||
}
|
||||
.quick-search-sub {
|
||||
font-size: 12px;
|
||||
color: var(--text-dim);
|
||||
|
||||
@@ -47,6 +47,8 @@
|
||||
<symbol id="i-printer" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 6 2 18 2 18 9"/><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"/><rect x="6" y="14" width="12" height="8"/></symbol>
|
||||
<symbol id="i-pin" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M12 17v5"/><path d="M9 10.76a2 2 0 0 1-1.11 1.79l-1.78.9A2 2 0 0 0 5 15.24V16a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1v-.76a2 2 0 0 0-1.11-1.79l-1.78-.9A2 2 0 0 1 15 10.76V7a1 1 0 0 1 1-1 2 2 0 0 0 0-4H8a2 2 0 0 0 0 4 1 1 0 0 1 1 1z"/></symbol>
|
||||
<symbol id="i-paperclip" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.44 11.05 12.25 20.24a6 6 0 0 1-8.49-8.49l9.19-9.19a4 4 0 0 1 5.66 5.66l-9.2 9.19a2 2 0 0 1-2.83-2.83l8.49-8.48"/></symbol>
|
||||
<symbol id="i-clock" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><polyline points="12 7 12 12 15 14"/></symbol>
|
||||
<symbol id="i-note" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14 3H6a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="14 3 14 9 20 9"/><line x1="8" y1="13" x2="16" y2="13"/><line x1="8" y1="17" x2="13" y2="17"/></symbol>
|
||||
<symbol id="i-qr" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/><path d="M14 14h3v3h-3zM21 14v.01M14 21h.01M17 21h4v-4"/></symbol>
|
||||
<symbol id="i-download" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/></symbol>
|
||||
<symbol id="i-empty-vault" viewBox="0 0 120 120" fill="none">
|
||||
|
||||
@@ -88,6 +88,21 @@ function quickSearchRender() {
|
||||
main.appendChild(el('div', { class: 'quick-search-sub' }, e.username));
|
||||
row.appendChild(avatar);
|
||||
row.appendChild(main);
|
||||
// Un bouton par valeur presente : pas besoin de retenir clic / Ctrl+clic.
|
||||
const verb = quickSearchFillMode ? 'Fill ' : 'Copy ';
|
||||
const acts = el('div', { class: 'quick-search-acts' });
|
||||
const act = (ic, title, mode) => {
|
||||
const b = el('button', { class: 'icon-btn icon-btn-sm', type: 'button', title });
|
||||
b.appendChild(icon(ic));
|
||||
b.addEventListener('click', ev => { ev.stopPropagation(); quickSearchPickEntry(e, mode); });
|
||||
b.addEventListener('contextmenu', ev => ev.stopPropagation());
|
||||
acts.appendChild(b);
|
||||
};
|
||||
if (e.username) act('i-user', verb + 'username', 'user');
|
||||
if (e.kind === 'note') act('i-note', 'Copy note', 'note');
|
||||
else act('i-key', verb + 'password', 'pwd');
|
||||
if (e.totp_secret && e.totp_iv) act('i-clock', verb + '2FA code', 'totp');
|
||||
row.appendChild(acts);
|
||||
// Left click → password only; Ctrl+click → username only
|
||||
// (step-2 forms / unlock screens).
|
||||
row.addEventListener('click', ev =>
|
||||
@@ -106,9 +121,42 @@ function quickSearchRender() {
|
||||
// mode: 'full' (user + Tab + password), 'user' (username only) or 'pwd'
|
||||
// (password only). In fill mode each maps to a SendInput variant; in copy
|
||||
// mode 'full' has no meaning so it falls back to copying the password.
|
||||
// 'totp' = code 2FA courant (tape comme un mot de passe, ou copie) ; 'note' =
|
||||
// corps d'une note, toujours COPIE - le taper enverrait ses retours a la ligne
|
||||
// comme des Entree dans le formulaire cible.
|
||||
async function quickSearchPickEntry(entry, mode) {
|
||||
mode = mode || 'full';
|
||||
|
||||
if (mode === 'totp') {
|
||||
const secret = await decryptTotpSecret(entry.totp_secret, entry.totp_iv);
|
||||
let code = '';
|
||||
try { if (secret && secret !== '[ERROR]') code = (await generateTOTP(secret)).code; }
|
||||
catch (_) { code = ''; }
|
||||
if (!code) { toast('2FA: cannot read the secret', 'error'); return; }
|
||||
if (quickSearchFillMode) {
|
||||
autofillPendingToast = entryDisplayName(entry) + ' · 2FA code sent';
|
||||
if (Bridge.active) Bridge.executeAutofill('', code, quickSearchHideAfter);
|
||||
quickSearchFillMode = false;
|
||||
quickSearchHideAfter = false;
|
||||
closeQuickSearchModal();
|
||||
return;
|
||||
}
|
||||
if (Bridge.active) Bridge.copySecure(code, 30000);
|
||||
else { try { await navigator.clipboard.writeText(code); } catch (_) {} }
|
||||
toast(entryDisplayName(entry) + ' · 2FA code copied');
|
||||
closeQuickSearchModal(true);
|
||||
return;
|
||||
}
|
||||
if (mode === 'note') {
|
||||
const body = await decryptPwd(entry.encrypted_password, entry.iv);
|
||||
if (body === '[ERROR]') { toast('Decryption error', 'error'); return; }
|
||||
if (Bridge.active) Bridge.copySecure(body, 30000);
|
||||
else { try { await navigator.clipboard.writeText(body); } catch (_) {} }
|
||||
toast(entryDisplayName(entry) + ' · note copied');
|
||||
closeQuickSearchModal(true);
|
||||
return;
|
||||
}
|
||||
|
||||
// Fill mode (Ctrl+Shift+Q hotkey): SendInput directly into the HWND
|
||||
// Delphi saved when the hotkey fired. No clipboard touch.
|
||||
if (quickSearchFillMode) {
|
||||
|
||||
Reference in New Issue
Block a user