En tant que chef de projet dans une société de développement spécialisée dans les fintech (hi CapSens), j'ai vu des tas et des tas de back-offices de plateformes web.
Ces interfaces d'administration sont très communes et similaires surtout pour les index (liste de ressources) : un grand tableau paginé de 50 lignes, une barre latérale qui contient le filtre et un titre. Toujours la même interface. Cet article explore les moyens d'améliorer ces interfaces simples.
Etant dans une entreprise Ruby on Rails, cet article montrera des bouts de code Ruby et se concentrera sur le design d'ActiveAdmin mais il peut être appliqué à n'importe quel autre index Admin.
Voici un index ActiveAdmin de base. Pour l'exemple, j'ai créé un modèle de client et un index affichant les champs montrés à droite. La vue est celle par défaut du générateur d'AA, donc nous avons aussi un tas de filtres inutiles empilés dans une barre latérale sur la droite. Vous avez déjà vu ça, non ?
Le code de ce projet peut être trouvé sur ce dépôt Github. Vous y trouverez une branche git représentant chaque phase de cet article (ici "1_base_admin").
Maintenant que nous sommes configurés, passons à autre chose et explorons les moyens d'améliorer notre index d'administration.
Créer un thème pour votre administration
Il existe plusieurs thèmes open-source disponibles pour ActiveAdmin. Parmi tous les gains rapides que je vais vous montrer dans cet article, celui-ci est peut-être le plus important.
Tout d'abord, nous devons choisir le thème que nous souhaitons afin de personnaliser l'interface de notre administrateur. Ce wiki référence une liste de thèmes d'AA. En choisissant votre thème, vous voudrez qu'il soit fonctionnel, vous avez assez de bugs à gérer, vous ne voulez pas en ajouter de nouveaux grâce à votre thème, non ? Un bon indicateur est de s'assurer qu'il n'y a pas trop de problèmes ouverts et que le thème est toujours maintenu à jour (vérifiez le dernier commit sur la branche master). Enfin, si votre projet contient déjà de nombreuses pages AA, vous devriez opter pour une thématisation légère afin d'éviter les changements de rupture que vous pourriez manquer.
Parmi tous les thèmes disponibles sur ce wiki, mon préféré est Artic Admin mais pour les raisons que je vous ai données ci-dessus, nous allons opter pour un thème plus léger : ActiveMaterial. Pour l'implémenter, il suffit de suivre la doc sur la page Github, vous devriez être prêt en une minute (il ne nécessite que 3 lignes de code à ajouter).
L'interface de l'AA a changé et a maintenant un aspect différent. Avec un peu de configuration, nous pouvons facilement la personnaliser davantage. Le thème est fait en SASS (SCSS) donc nous pouvons rechercher des variables et modifier la configuration par défaut.
Personnalisation du thème
Si nous jetons un coup d'oeil aux variables de couleur disponibles, nous pouvons voir qu'il y en a 14. Pour cela, ajoutez un nouveau fichier app/assets/stylesheets/active_admin/variables/_colors.scss et exigez-le dans le fichier active_admin.scss avant les autres fichiers comme ceci.
// Customization
@import ‘active_admin/variables/variables’;
@import ‘active_admin/variables/fonts’;
// Libraries
@import “active_admin/mixins”;
@import “active_material”;
Un exemple de code admin.scss
Maintenant, allons dans notre nouveau fichier _variables.scss et modifions un peu le thème ! Tout d'abord, nous devons définir notre palette de couleurs. ActiveMaterial étant un modèle de conception matérielle, j'ai utilisé un générateur de palette de couleurs matérielles pour cela. Il y en a plein disponibles sur le web, mais j'aime particulièrement Material.io.
Une fois que vous avez fini de définir votre modèle, il vous suffit de reporter la valeur dans notre fichier _variable.scss en réaffectant la valeur des variables SASS existantes :
$am-theme-primary: #42a5f5;
// A darker primary theme color for contrast when overlaying
// important items containers that are already treated
// with primary color.
$am-theme-primary-700: #0077c2;
// Used for primary action button and components
$am-theme-accent: #673ab7;
// The background color of the document.
$am-theme-backdrop: #eeeeee;
// Background color of “paper” elements such as cards.
$am-theme-paper: #F5F5F6;
// Color used to separate elements such as table's lines
$am-theme-divider: darken($am-theme-backdrop, 2.5%);
Voici mon fichier _variable.scss pour correspondre à la palette de couleurs ci-dessus.
Vous pouvez retrouver le code ici.
Bien sûr, il existe d'autres options pour une personnalisation plus poussée : polices, élévations, tailles, points d'arrêt. Pour ce faire, il suffit de répéter le même processus que pour la couleur.
Bascule de la barre latérale des filtres
Maintenant que nous avons ajouté quelques couleurs, nous pouvons voir que notre barre latérale de filtres occupe 20 % de l'écran. C'est un peu trop pour une fonctionnalité que vous n'utiliserez pas tout le temps, n'est-ce pas ? Trouvons un moyen de la faire apparaître uniquement en cas de besoin.
En cherchant une solution à ce problème, je suis tombé sur cet article d'Emanuele Tozzato qui montre une façon simple de régler le problème. Avec un peu de Jquery et de Css, il permet d'activer et de désactiver la barre latérale des filtres grâce à un élément d'action.
Nous allons juste pousser un peu plus loin son approche car je ne suis pas un grand fan de l'ajout d'un élément d'action. Ceux-ci devraient être utilisés pour les actions CRUD des administrateurs. J'ai donc modifié un peu le code pour déplacer le bouton de basculement des filtres en haut à droite de la table des index.
Si vous êtes intéressé, vous pouvez trouver le code ici.
Ajouter des bandes
Parfois, il peut être complexe pour un administrateur de distinguaer les éléments d'une ligne à l'autre. Une solution consiste à dépouiller le tableau. Pour ce faire, il suffit de créer un nouveau composant scss :
// app/assets/active_admin/components/_tables.scss
$table-striping-color: $am-theme-paper;
.index_content table {
tr.odd {
background: $table-striping-color;
}
tr.even {
background: lighten($table-striping-color, 10%);
}
}
Comment colorer une ligne sur deux d'un tableau en SAS
Pour la couleur des rayures, j'ai utilisé la valeur de notre $am-theme-paper (la couleur de fond des composants tels que les cartes ou les tables) et j'ai juste assombri les colonnes paires. Facile, non ? Vous pouvez trouver le code complet ici.
Décorez vos données
Parfois, vous pouvez trouver dans vos index des colonnes qui n'ont aucun intérêt à être séparées. Par exemple le prénom et le nom ou chaque partie d'une adresse. Vous pouvez alors rapidement les fusionner dans une nouvelle colonne "nom" ou "adresse complète".
Par ailleurs, lorsque vous affichez un montant, vous pouvez ajouter le formatage de la devise et des chiffres pour faciliter la lecture.
Vous pouvez utiliser un décorateur comme Draper pour cela. Cela évite de surcharger la logique d'administration.
__# app/decorators/customer_decorator.rb__
class CustomerDecorator < Draper::Decorator
delegate_all
def name
“#{firstname&.capitalize} #{lastname&.upcase}”
end
def membership_amount_in_dollars
h.number_to_currency(membership_amount, locale: :en)
end
end
Un exemple de décorateur pour un client
Ensuite, pour chaque colonne décorée utilisée, n'oubliez pas de spécifier comment le tri doit se comporter comme ceci :
# app/admin/customers.rb
ActiveAdmin.register Customer do
decorate_with CustomerDecorator
index do
selectable_column
column :id
column :name, sortable: :lastname
column :email
column :phone_number
column :city
column :language
column :membership_amount_in_dollars, sortable: :membership_amount
column :state
column :created_at
column :updated_at
actions
end
end
Exemple d'index AA pour un client
Améliorer l'affichage de l'état
Les ressources affichées dans un index d'administration sont souvent accompagnées d'un état. Dans notre index des clients, il s'agit d'un pipeline de vente de base. En effet, un client est d'abord dans l'état "nouveau" avant d'être contacté, puis il peut entrer dans la phase de négociation et enfin il devient signé. Il peut ensuite passer à la phase de résiliation (lorsqu'il annule le contrat).
Étiquettes d'état
Bien sûr, nous pouvons ajouter un peu de couleur en utilisant la fonction très simple status_tag d'ActiveAdmin.
Tout d'abord, nous ajoutons la logique status_tag dans la vue index de nos clients AA :
# app/admin/customers.rb
ActiveAdmin.register Customer do
decorate_with CustomerDecorator
index do
# [... others columns]
column :state do |customer|
status_tag customer.state
end
# [... others columns]
end
end
Ajouter un label sur un statut client AA
Nous pouvons ensuite utiliser une "map" SASS pour personnaliser la couleur de fond du status_tag :
// app/assets/stylesheets/active_admin/components/_status_tags.scss
$customers_states_colors: (
new: #BBC6C3,
contacted: #70C0C6,
negociating: #9DEA4F,
signed: #329932,
terminated: #FF320E
);
.status_tag {
@each $state, $color in $customers_states_colors {
&.#{$state} {
background: $color;
}
}
}
Convertir les étiquettes en progression
Le résultat est plus visuel mais d'un autre côté les états de nos clients sont linéaires ce qui signifie que pour chaque client, son premier état sera nouveau et enfin il entrera dans la phase terminée.
Notez que j'ai utilisé un enum pour cela car ces états n'ont pas besoin de transitions ou de gardes mais vous pouvez obtenir le même résultat avec une machine à états comme AASM ou Statesman.
Une façon de représenter graphiquement cette linéarité est d'afficher l'état dans une barre de progression. Lorsqu'elle est vide, cela signifie que le client est dans le nouvel état et lorsqu'elle est pleine, cela signifie que le client est soit signé soit terminé. Nous allons également réutiliser les schémas de couleurs définis précédemment pour rendre le tout plus visuel.
Tout d'abord, ajoutons une méthode dans notre décorateur client qui retournera l'état d'achèvement en pourcentage pour notre barre de progression :
class CustomerDecorator < Draper::Decorator
delegate_all
# [ other decorator logic here ... ]
def state_completition_in_percent
customer_state_index = Customer.state.values.index(state).to_f + 1
return 100 if state == :terminated
total_states_count_without_terminated_state = Customer.state.values.length - 1
completion = customer_state_index / total_states_count_without_terminated_state
(completion * 100).round(0)
end
end
Ensuite, nous rendrons un partial .html.erb dans notre colonne customer.state :
ActiveAdmin.register Customer do
decorate_with CustomerDecorator
index do
[ other columns logic here ... ]
column :state do |customer|
render partial: 'admin/customers/material_progress_bar', locals: { customer: customer }
end
actions
end
end
Maintenant nous pouvons créer notre partiel material_progress_bar :
<div class="progress-wrapper <%= customer.state %>">
<span class="state"><%= customer.state %></span>
<div class="progress">
<div class="bar" style="width: <%= customer.state_completition_in_percent %>%"></div>
</div>
</div>
Enfin, un petit peu de style (n'oubliez pas de l'exiger dans votre fichier application.scss) :
@import 'active_admin/variables/colors';
$customers_states_colors: (
new: #BBC6C3,
contacted: #70C0C6,
negociating: #9DEA4F,
signed: #329932,
terminated: #FF320E
);
$progress-bar-bg: #acece6;
$state-text-color: #707675;
$progress-bar-border-color: $state-text-color;
.progress-wrapper {
.progress {
position: relative;
height: 10px;
display: block;
width: 100%;
min-width: 100px;
background-color: $progress-bar-bg;
border-radius: 2px;
background-clip: padding-box;
margin: 0.15rem 0 1rem 0;
overflow: hidden;
.bar {
position: absolute;
top: 0;
bottom: 0;
transition: width 1s expandWidth;
}
}
@each $state, $color in $customers_states_colors {
&.#{$state} {
color: $state-text-color;
.progress {
border: 0.5px solid $progress-bar-border-color;
background-color: transparent;
.bar {
background: $color;
}
}
}
}
}
view raw