Files
2025-12-07 16:53:36 +01:00

179 lines
5.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// uiComponents.js
// UI du mini gestionnaire de mots de passe.
import St from 'gi://St';
import Gio from 'gi://Gio';
import GLib from 'gi://GLib';
import * as Main from 'resource:///org/gnome/shell/ui/main.js';
import * as PanelMenu from 'resource:///org/gnome/shell/ui/panelMenu.js';
import * as PopupMenu from 'resource:///org/gnome/shell/ui/popupMenu.js';
import * as ExtensionUtils from 'resource:///org/gnome/shell/misc/extensionUtils.js';
const Clutter = imports.gi.Clutter;
const Clipboard = St.Clipboard.get_default();
const ClipboardType = St.ClipboardType.CLIPBOARD;
function copyToClipboard(text) {
if (text)
Clipboard.set_text(ClipboardType, text);
}
export class PasswordEntryRow extends PopupMenu.PopupBaseMenuItem {
constructor(entry) {
super({ reactive: true });
const box = new St.BoxLayout({ vertical: false, x_expand: true });
let labelWidget;
if (entry.url) {
labelWidget = new St.Label({
text: entry.label,
style_class: 'password-applet-label-link',
x_expand: true
});
labelWidget.clutter_text.underline = true;
labelWidget.connect('button-press-event', () => {
Gio.AppInfo.launch_default_for_uri(entry.url, null);
});
} else {
labelWidget = new St.Label({ text: entry.label, x_expand: true });
}
box.add_child(labelWidget);
box.add_child(new St.Label({ text: entry.username, x_expand: true }));
box.add_child(new St.Label({ text: '••••••••' }));
const uBtn = new St.Button({ label: 'U' });
uBtn.connect('clicked', () => copyToClipboard(entry.username));
box.add_child(uBtn);
const pBtn = new St.Button({ label: 'P' });
pBtn.connect('clicked', () => copyToClipboard(entry.password_enc));
box.add_child(pBtn);
this.actor.add_child(box);
}
}
export class PasswordListSection extends PopupMenu.PopupMenuSection {
setEntries(entries) {
this.removeAll();
if (!entries.length) {
this.addMenuItem(new PopupMenu.PopupMenuItem(
'Aucune entrée', { reactive: false }
));
return;
}
for (const e of entries)
this.addMenuItem(new PasswordEntryRow(e));
}
}
export class AddEntrySection extends PopupMenu.PopupMenuSection {
constructor(repo, refreshCb) {
super();
this._repo = repo;
this._refreshCb = refreshCb;
this._showAddButton();
}
_showAddButton() {
this.removeAll();
const item = new PopupMenu.PopupMenuItem(' Ajouter une entrée');
item.connect('activate', () => this._showForm());
this.addMenuItem(item);
}
_showForm() {
this.removeAll();
const wrapper = new PopupMenu.PopupBaseMenuItem({ reactive: false });
const box = new St.BoxLayout({ vertical: true });
const mkEntry = hint =>
new St.Entry({ hint_text: hint, style_class: 'password-applet-entry' });
const label = mkEntry("Label");
const user = mkEntry("User");
const pwd = mkEntry("Password");
const url = mkEntry("URL");
const notes = mkEntry("Notes");
const mkRow = (name, widget) => {
const row = new St.BoxLayout();
row.add_child(new St.Label({ text: name + " : " }));
row.add_child(widget);
return row;
};
box.add_child(mkRow("Label", label));
box.add_child(mkRow("User", user));
box.add_child(mkRow("Password", pwd));
box.add_child(mkRow("URL", url));
box.add_child(mkRow("Notes", notes));
const btnRow = new St.BoxLayout();
const save = new St.Button({ label: "Enregistrer" });
save.connect('clicked', () => {
const entry = {
label: label.get_text().trim(),
username: user.get_text().trim(),
password: pwd.get_text().trim(),
url: url.get_text().trim(),
notes: notes.get_text().trim()
};
if (!entry.label || !entry.username || !entry.password) {
Main.notify("Password Applet", "Champs obligatoires manquants");
return;
}
this._repo.addEntry(entry);
this._refreshCb();
this._showAddButton();
});
const cancel = new St.Button({ label: "Annuler" });
cancel.connect('clicked', () => this._showAddButton());
btnRow.add_child(save);
btnRow.add_child(cancel);
box.add_child(btnRow);
wrapper.actor.add_child(box);
this.addMenuItem(wrapper);
}
}
export class PasswordApplet extends PanelMenu.Button {
constructor(repo) {
super(0.0, 'PasswordApplet', false);
this._repo = repo;
this.add_child(new St.Icon({
icon_name: 'dialog-password-symbolic',
style_class: 'system-status-icon'
}));
this._list = new PasswordListSection();
this.menu.addMenuItem(this._list);
this.menu.addMenuItem(new PopupMenu.PopupSeparatorMenuItem());
this._add = new AddEntrySection(repo, () => this._reload());
this.menu.addMenuItem(this._add);
this._reload();
}
_reload() {
const entries = this._repo.listEntries();
this._list.setEntries(entries);
}
}