SettingsDialog et contrôle Switch
SettingsDialog et contrôle Switch
Dodock met à disposition deux primitives réutilisables côté client pour construire des interfaces de configuration soignées : frappe.ui.SettingsDialog pour les boîtes de dialogue à onglets et ControlSwitch pour les interrupteurs à bascule.
SettingsDialog
frappe.ui.SettingsDialog génère une boîte de dialogue modale composée de deux zones :
- Un rail vertical d'onglets (sidebar à gauche) avec regroupement par catégorie.
- Un panneau de contenu (droite) chargé à la demande à chaque activation d'onglet.
Elle hérite de frappe.ui.Dialog, ce qui lui donne la gestion du cycle de vie modal (fond semi-transparent, ouverture/fermeture, touche Échap, pile des dialogues ouverts).
Exemple minimal
new frappe.ui.SettingsDialog({
title: __("Paramètres"),
default_tab: "preferences",
tabs: [
{
group: __("Configuration"),
items: [
{
id: "preferences",
label: __("Préférences"),
icon: "sliders-vertical",
title: __("Préférences"),
description: __("Gérez vos préférences"),
fields: [
{
fieldname: "theme",
fieldtype: "Select",
label: __("Thème"),
options: "Clair\nSombre",
},
],
actions: [
{
label: __("Enregistrer"),
variant: "solid",
click(panel) {
const values = panel.get_values(); // null si un champ requis est vide
if (!values) return;
// traiter values.theme …
},
},
],
},
],
},
],
}).show();
Structure de configuration
| Clé (racine) | Type | Description |
|---|---|---|
title | string | Titre affiché en haut de la boîte de dialogue |
default_tab | string | id de l'onglet actif à l'ouverture |
tabs | Array | Liste des groupes d'onglets (voir ci-dessous) |
Groupe d'onglets (tabs[].group) : libellé de section dans la sidebar.
Élément d'onglet (tabs[].items[]) :
| Clé | Type | Description |
|---|---|---|
id | string | Identifiant unique de l'onglet |
label | string | Libellé affiché dans la sidebar |
icon | string | Nom d'icône du sprite, rendu par frappe.utils.icon (ex. "sliders-vertical") |
icon_html | string | HTML d'icône brut, prioritaire sur icon. Réservé à du HTML écrit par le développeur : ne le remplissez jamais avec une réponse serveur ou une saisie utilisateur |
title | string | Titre affiché en en-tête du panneau |
description | string | Sous-titre affiché sous le titre |
fields | Array | Champs FieldGroup (même format que frappe.ui.Dialog) |
actions | Array | Boutons d'action (voir ci-dessous) |
render(panel) | function | Rendu personnalisé dans panel.body |
on_activate(panel) | function | Appelée à chaque activation de l'onglet |
Action (actions[]) :
| Clé | Type | Description |
|---|---|---|
label | string | Libellé du bouton |
icon | string | Icône du bouton |
variant | string | Variante du bouton frappe.ui.button, par exemple "solid" pour l'action principale |
theme | string | Thème du bouton, par exemple "red" pour une action destructive |
class | string | Classes CSS supplémentaires |
click(panel) | function | Appelée au clic. Elle reçoit le contrôleur SettingsDialogPanel, aussi disponible dans this |
API du panneau (SettingsDialogPanel)
Chaque onglet est piloté par un contrôleur SettingsDialogPanel transmis aux fonctions render et actions[].click. Il expose :
| Méthode | Description |
|---|---|
panel.get_values() | Retourne les valeurs du formulaire, ou null si un champ requis est vide. Sans champs, retourne {} |
panel.get_value(fieldname) | Retourne la valeur d'un champ |
panel.set_values(values) | Injecte des valeurs dans le formulaire. Retourne une promesse |
panel.get_field(fieldname) | Retourne le contrôle d'un champ |
panel.set_view(spec) | Remplace en une fois l'en-tête, les actions et le formulaire |
panel.refresh() | Réinitialise le panneau à la vue définie dans la config de l'onglet |
panel.set_header({ title, description, actions }) | Met à jour uniquement l'en-tête et ses actions |
panel.add_fields(fields) | Ajoute des champs au FieldGroup existant |
panel.body | Élément jQuery du corps du panneau (disponible dans render) |
panel.fieldgroup | Le FieldGroup sous-jacent, ou null |
panel.dialog | L'instance SettingsDialog |
Méthodes de la boîte de dialogue
| Méthode | Description |
|---|---|
dialog.activate(id) | Active l'onglet id. Le panneau est créé à la première activation, puis conservé avec son état |
dialog.get_panel(id) | Retourne le panneau d'un onglet déjà activé |
dialog.reset(tabs, default_tab) | Remplace les onglets sans recréer la fenêtre. L'état des panneaux est effacé |
Sans default_tab, le premier onglet du premier groupe est activé. La boîte de dialogue a la taille extra-large par défaut. Elle n'affiche pas la barre de titre standard : chaque panneau a son propre en-tête.
Navigation stateful au sein d'un panneau
panel.set_view(spec) permet d'implémenter une navigation à plusieurs niveaux (liste → formulaire → confirmation) sans coordination externe. Chaque appel remplace l'ensemble de la vue (en-tête + actions + formulaire) et les actions de la nouvelle vue lisent toujours le formulaire qui leur est colocalisé.
render(panel) {
// Vue « liste »
panel.set_view({
title: __("Choisir un profil"),
description: "",
actions: [
{
label: __("Nouveau profil"),
variant: "solid",
click(p) {
p.set_view({
title: __("Nouveau profil"),
fields: [{ fieldname: "nom", fieldtype: "Data", label: __("Nom"), reqd: 1 }],
actions: [
{
label: __("Enregistrer"),
variant: "solid",
click(p2) {
const v = p2.get_values();
if (!v) return;
// sauvegarder v.nom …
p2.refresh(); // retour à la vue initiale
},
},
],
});
},
},
],
render(p) {
p.body.append("<p>Aucun profil enregistré.</p>");
},
});
},
Flux d'instanciation
Contrôle Switch (fieldtype: "Switch")
Le contrôle Switch est un interrupteur à bascule (toggle) visuel qui remplace un simple bouton à cocher. Il peut être utilisé partout où un contrôle est instancié : FieldGroup, Dialog, formulaire de script client.
Caractéristiques
- Héritage : sous-classe de
ControlCheck— conserve un vrai<input type="checkbox">et toute la sémantique 0/1 (get_values()retourne1ou0). - Sémantique : validation, état lecture seule,
reqdfonctionnent identiquement àControlCheck. - Accessibilité :
role="switch"sur la case à cocher. La case à cocher est masquée visuellement (motif « sr-only » :clip,clip-path,overflow) mais reste focalisable. Le libellé reste visible. - Interaction : toute la ligne est une
<label>— cliquer n'importe où sur la ligne bascule l'état. - Style : la piste est rendue en CSS pur via
:has(input:checked)pour les états cochés, survolés, ciblés et désactivés.
Utilisation dans un Dialog ou FieldGroup
const d = new frappe.ui.Dialog({
title: __("Options"),
fields: [
{
fieldname: "notifications_actives",
fieldtype: "Switch",
label: __("Activer les notifications"),
},
{
fieldname: "mode_sombre",
fieldtype: "Switch",
label: __("Mode sombre"),
default: 1,
},
],
primary_action_label: __("Enregistrer"),
primary_action(values) {
// values.notifications_actives → 1 ou 0
// values.mode_sombre → 1 ou 0
d.hide();
},
});
d.show();
Utilisation dans une SettingsDialog
new frappe.ui.SettingsDialog({
title: __("Préférences"),
default_tab: "affichage",
tabs: [
{
group: __("Interface"),
items: [
{
id: "affichage",
label: __("Affichage"),
icon: "eye",
title: __("Affichage"),
fields: [
{
fieldname: "compact",
fieldtype: "Switch",
label: __("Vue compacte"),
},
],
actions: [
{
label: __("Appliquer"),
variant: "solid",
click(panel) {
const v = panel.get_values();
if (!v) return;
frappe.show_alert(v.compact ? __("Vue compacte activée") : __("Vue standard"));
},
},
],
},
],
},
],
}).show();
Comparaison Check / Switch
| Critère | Check | Switch |
|---|---|---|
| Valeur retournée | 1 / 0 | 1 / 0 |
| Rendu | Case à cocher native | Piste coulissante |
| Accessibilité | type="checkbox" | type="checkbox" + role="switch" |
| Cible de clic | Case uniquement | Toute la ligne |
| Interchangeable | Oui | Oui (même API) |