feat(notes): commandes masquees avec l'oeil des notes
Partage d'ecran : premier mot et 3 derniers caracteres visibles (ssh ••••.11), dans le panneau et la recherche rapide. Filtre, copie et remplissage gardent le vrai texte. Aide de la recherche rapide adaptee aux commandes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1582,6 +1582,11 @@ après chaque `DELETE /attachments/{id}`. Un petit vault sain ne paie rien.
|
|||||||
liste (`qsCommands`), la saisie filtre, Entree **tape sans Entree** et
|
liste (`qsCommands`), la saisie filtre, Entree **tape sans Entree** et
|
||||||
**sans Ctrl+A + Suppr** (`executeAutofill(..., noClear)` : dans un terminal
|
**sans Ctrl+A + Suppr** (`executeAutofill(..., noClear)` : dans un terminal
|
||||||
Ctrl+A ramene en debut de ligne), Ctrl+Entree copie, Esc revient aux entrees.
|
Ctrl+A ramene en debut de ligne), Ctrl+Entree copie, Esc revient aux entrees.
|
||||||
|
**Masquage** (partage d'ecran) sur l'oeil existant des notes (`maskNotes`) :
|
||||||
|
`maskCommand` garde le premier mot et les 3 derniers caracteres
|
||||||
|
(`ssh ••••••••••••.11`), une fin de 6 caracteres ou moins est masquee en
|
||||||
|
entier. Affichage seulement : filtre, copie et remplissage voient le vrai
|
||||||
|
texte. L'oeil re-declenche `input` sur le textarea pour redessiner la liste.
|
||||||
- **Settings search** : `#settingsSearch` filtre les `.setting-row` par
|
- **Settings search** : `#settingsSearch` filtre les `.setting-row` par
|
||||||
texte ; match sur le label de section garde toute la section. Esc dans
|
texte ; match sur le label de section garde toute la section. Esc dans
|
||||||
la search avec query = clear ; Esc vide = ferme Settings.
|
la search avec query = clear ; Esc vide = ferme Settings.
|
||||||
|
|||||||
@@ -4050,6 +4050,20 @@ function parseCommandNote(text) {
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AFFICHAGE MASQUE d'une commande (partage d'ecran), sur l'oeil "mask notes" :
|
||||||
|
// le premier mot reste, puis le milieu masque, puis les 3 derniers caracteres.
|
||||||
|
// "ssh admin@10.0.0.11" -> "ssh ••••••••••••.11". Une fin trop courte pour
|
||||||
|
// en garder 3 sans tout montrer est masquee en entier. Affichage seulement :
|
||||||
|
// filtre, copie et remplissage travaillent sur le vrai texte.
|
||||||
|
function maskCommand(cmd) {
|
||||||
|
const s = String(cmd || '');
|
||||||
|
const sp = s.indexOf(' ');
|
||||||
|
const head = sp < 0 ? '' : s.slice(0, sp + 1);
|
||||||
|
const rest = sp < 0 ? s : s.slice(sp + 1);
|
||||||
|
if (rest.length <= 6) return head + '•'.repeat(rest.length);
|
||||||
|
return head + '•'.repeat(rest.length - 3) + rest.slice(-3);
|
||||||
|
}
|
||||||
|
|
||||||
// HISTORIQUE DES ENTREES OUVERTES, comme celui d'un navigateur. Fonctions
|
// HISTORIQUE DES ENTREES OUVERTES, comme celui d'un navigateur. Fonctions
|
||||||
// pures sur {ids, pos} : testables sans DOM (tests/history.test.js).
|
// pures sur {ids, pos} : testables sans DOM (tests/history.test.js).
|
||||||
const ENTRY_HISTORY_MAX = 50;
|
const ENTRY_HISTORY_MAX = 50;
|
||||||
@@ -4671,7 +4685,8 @@ function soCommandsField() {
|
|||||||
if (c.group) list.appendChild(el('div', { class: 'so-cmds-group' }, c.group));
|
if (c.group) list.appendChild(el('div', { class: 'so-cmds-group' }, c.group));
|
||||||
}
|
}
|
||||||
const row = el('div', { class: 'so-cmds-row' });
|
const row = el('div', { class: 'so-cmds-row' });
|
||||||
row.appendChild(el('code', { class: 'so-cmds-cmd' }, c.cmd));
|
row.appendChild(el('code', { class: 'so-cmds-cmd' },
|
||||||
|
state.maskNotes ? maskCommand(c.cmd) : c.cmd));
|
||||||
const b = el('button', { class: 'icon-btn icon-btn-sm', type: 'button', title: 'Copy command' });
|
const b = el('button', { class: 'icon-btn icon-btn-sm', type: 'button', title: 'Copy command' });
|
||||||
b.appendChild(icon('i-copy'));
|
b.appendChild(icon('i-copy'));
|
||||||
b.addEventListener('click', async ev => {
|
b.addEventListener('click', async ev => {
|
||||||
@@ -4721,6 +4736,8 @@ function soNoteBodyField(value) {
|
|||||||
state.maskNotes = !state.maskNotes;
|
state.maskNotes = !state.maskNotes;
|
||||||
localStorage.setItem('maskNotes', state.maskNotes ? '1' : '0');
|
localStorage.setItem('maskNotes', state.maskNotes ? '1' : '0');
|
||||||
ta.classList.toggle('is-masked', state.maskNotes);
|
ta.classList.toggle('is-masked', state.maskNotes);
|
||||||
|
// La liste des commandes suit l'oeil (elle ecoute 'input').
|
||||||
|
ta.dispatchEvent(new Event('input'));
|
||||||
saveServerSettings();
|
saveServerSettings();
|
||||||
});
|
});
|
||||||
wrap.appendChild(ta);
|
wrap.appendChild(ta);
|
||||||
|
|||||||
+2
-1
@@ -99,7 +99,8 @@ function qsRenderCommands(box, q) {
|
|||||||
'data-cmd': String(x.i),
|
'data-cmd': String(x.i),
|
||||||
});
|
});
|
||||||
const main = el('div', { class: 'quick-search-main' });
|
const main = el('div', { class: 'quick-search-main' });
|
||||||
main.appendChild(el('div', { class: 'quick-search-name qs-cmd' }, x.c.cmd));
|
main.appendChild(el('div', { class: 'quick-search-name qs-cmd' },
|
||||||
|
state.maskNotes ? maskCommand(x.c.cmd) : x.c.cmd));
|
||||||
if (x.c.group) main.appendChild(el('div', { class: 'quick-search-sub' }, x.c.group));
|
if (x.c.group) main.appendChild(el('div', { class: 'quick-search-sub' }, x.c.group));
|
||||||
row.appendChild(main);
|
row.appendChild(main);
|
||||||
const acts = el('div', { class: 'quick-search-acts' });
|
const acts = el('div', { class: 'quick-search-acts' });
|
||||||
|
|||||||
@@ -25,6 +25,17 @@ test('"## titre" et "#" seul', () => {
|
|||||||
assert.equal(r[1].group, '');
|
assert.equal(r[1].group, '');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('masque : premier mot, milieu masque, 3 derniers caracteres', () => {
|
||||||
|
assert.equal(T.maskCommand('ssh admin@10.0.0.11'), 'ssh ' + '•'.repeat(12) + '.11');
|
||||||
|
assert.equal(T.maskCommand('psql -h 10.0.0.20'), 'psql ' + '•'.repeat(9) + '.20');
|
||||||
|
});
|
||||||
|
|
||||||
|
test('masque : fin courte masquee en entier, pas d\'espace', () => {
|
||||||
|
assert.equal(T.maskCommand('ls -la'), 'ls •••');
|
||||||
|
assert.equal(T.maskCommand('hostname'), '•••••ame');
|
||||||
|
assert.equal(T.maskCommand(''), '');
|
||||||
|
});
|
||||||
|
|
||||||
test('texte vide ou absent', () => {
|
test('texte vide ou absent', () => {
|
||||||
assert.equal(T.parseCommandNote('').length, 0);
|
assert.equal(T.parseCommandNote('').length, 0);
|
||||||
assert.equal(T.parseCommandNote(null).length, 0);
|
assert.equal(T.parseCommandNote(null).length, 0);
|
||||||
|
|||||||
+1
-1
@@ -159,7 +159,7 @@ function loadApp(overrides = {}) {
|
|||||||
// historique des entrees ouvertes
|
// historique des entrees ouvertes
|
||||||
entryHistoryPush, entryHistoryTarget, ENTRY_HISTORY_MAX,
|
entryHistoryPush, entryHistoryTarget, ENTRY_HISTORY_MAX,
|
||||||
// note de commandes
|
// note de commandes
|
||||||
parseCommandNote,
|
parseCommandNote, maskCommand,
|
||||||
};
|
};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user