Blocs personnalisés

Les blocs personnalisés permettent d'étendre le catalogue standard de soixante-dix blocs avec ses propres briques de contenu, écrites en Python. Cette extensibilité est pensée pour les équipes qui ont des besoins spécifiques non couverts par les blocs embarqués : analyses internes récurrentes, mise en forme particulière, intégration avec une API externe de l'organisation. Les blocs personnalisés sont enregistrés au niveau du poste et peuvent être partagés via l'interface de branding.

Accès à l'interface

L'interface de création des blocs personnalisés se trouve dans l'onglet Personnalisation du module Rapports, sous le sous-onglet Blocs. Elle regroupe la liste des blocs déjà créés et l'éditeur pour en créer un nouveau ou modifier un existant.

Rapports > Personnalisation > Blocs > + Nouveau bloc

Une fois créés, les blocs personnalisés apparaissent dans la bibliothèque de l'éditeur principal aux côtés des blocs standards, et peuvent être glissés dans le canvas de la même manière.

Métadonnées d'un bloc personnalisé

Un bloc personnalisé porte les mêmes métadonnées qu'un bloc standard, saisies via un formulaire. La cohérence avec la structure FAIH est maintenue : chaque bloc doit déclarer sa nature.

Champ Contrainte Exemple
Clé unique Minuscules, underscore, 3 à 50 caractères, doit être unique audit_custom_labo
Nom affiché Libre, tel qu'il apparaîtra dans le PDF Audit interne laboratoire
Description courte Une ligne, affichée dans la bibliothèque Synthèse des contrôles internes
Nature FAIH F, A, I ou H A (Analytique)
Icône 2 lettres majuscules, badge visuel AC
La clé unique ne peut pas être modifiée une fois le bloc créé : c'est elle qui sert d'identifiant dans les templates et les rapports déjà générés. Choisir un nom explicite et stable dès la création.

Code Python du bloc

Le cœur d'un bloc personnalisé est un extrait de code Python qui décrit ce que le bloc doit produire dans le PDF. Le code s'exécute dans un contexte restreint avec un ensemble de variables et d'outils mis à disposition.

Variable ou outil Rôle
data Dictionnaire des données du projet (samples, géochimie, isotopes, molécules, etc.)
lang Langue courante du rapport, 'fr' ou 'en'
story Liste ReportLab à laquelle on ajoute les éléments produits par le bloc
_table(headers, rows, col_widths, nature) Helper pour produire une table stylée cohérente avec l'identité IsoFind
_kv_table(items) Helper pour produire une liste clé-valeur alignée
colors, mm Constantes ReportLab pour couleurs et conversion unité
Paragraph, Spacer Classes ReportLab standard pour texte et espacement
api_results Résultats des appels API externes déclarés pour ce bloc

Exemple de bloc personnalisé

L'exemple suivant, fourni dans l'éditeur comme aide à la prise en main, produit un paragraphe de synthèse et une table des concentrations moyennes par élément.

samples = data.get('samples', [])
gc = _geochem_context(data)

story.append(Paragraph(
    f'{len(samples)} échantillon(s) analysé(s)',
    ParagraphStyle('Custom', fontSize=10, fontName='Helvetica-Bold')
))

if gc['has_geochem']:
    rows = [[el, f'{v:.4g}'] for el, v in gc['means'].items()]
    story.extend(_table(['Élément', 'Concentration'], rows,
                        col_widths=[40*mm, 40*mm], nature='I'))

Ce code illustre plusieurs patterns récurrents : récupération d'une section du dictionnaire data, utilisation d'un helper de contexte, ajout d'un paragraphe stylé, puis d'une table avec déclaration explicite de sa nature FAIH. La nature déclarée dans l'appel à _table() influence la mise en forme visuelle (couleur de bordure, badge).

Le passage obligé par les helpers _table() et _kv_table() n'est pas une restriction mais une garantie de cohérence graphique. Un bloc personnalisé qui les utilise produit une sortie visuellement indiscernable d'un bloc standard.

Appels API externes

Un bloc personnalisé peut enrichir son contenu avec des données venues d'une API externe (serveur interne de l'organisation, base métier, service tiers). Les appels sont déclarés dans le formulaire du bloc, exécutés par le backend IsoFind au moment de la génération, et leurs résultats sont injectés dans api_results pour être utilisés dans le code Python.

Paramètre d'un appel API Rôle
Identifiant Clé sous laquelle le résultat sera accessible dans api_results
URL Adresse de l'API externe, peut contenir des placeholders liés au projet
Méthode GET, POST, PUT, etc.
En-têtes et authentification Configurables pour les API qui exigent un token

Dans le code Python du bloc, le résultat d'un appel déclaré avec l'identifiant stock_labo est accessible via api_results['stock_labo']. Les réponses JSON sont désérialisées automatiquement ; les autres types reviennent comme texte brut.

Les appels API sont exécutés à chaque génération de PDF. Un bloc qui fait un appel lent ralentit proportionnellement la génération. Pour les données rarement changeantes, privilégier un cache côté API externe plutôt qu'un appel systématique à chaque rapport.

Stockage et partage

Les blocs personnalisés sont stockés localement sur le poste via l'endpoint /api/reports/custom-blocks. Ils persistent entre les sessions et sont automatiquement chargés à l'ouverture du module Rapports.

Pour partager un bloc personnalisé avec d'autres utilisateurs, deux voies coexistent. La première est l'export manuel du code Python qui peut être recopié dans une autre instance. La seconde, plus intégrée, utilise le système de thèmes qui peut inclure les blocs personnalisés dans un package distribuable à l'échelle de l'organisation.

Sécurité du code Python

L'exécution de code Python arbitraire dans un contexte applicatif est une surface d'attaque à traiter avec soin. IsoFind applique plusieurs protections.

  • Le contexte d'exécution est restreint : seules les variables et classes listées plus haut sont accessibles. Les imports arbitraires sont bloqués.
  • L'accès au système de fichiers, au réseau (hors appels API déclarés) et aux autres processus est impossible depuis le code du bloc.
  • Un timeout d'exécution protège contre les boucles infinies qui bloqueraient la génération.
  • Les erreurs d'exécution sont capturées et affichées dans le rapport comme un bloc d'erreur, sans interrompre le reste de la génération.
  • Dans les environnements contrôlés (déploiements d'entreprise), le gestionnaire peut désactiver totalement la création de blocs personnalisés via la configuration.

Nature FAIH pour un bloc personnalisé

Choisir la nature du bloc n'est pas cosmétique : elle influe sur le comptage global des registres dans le rapport et sur le style visuel appliqué. Le choix doit refléter honnêtement le contenu produit.

Si le bloc... Nature recommandée
Affiche des valeurs brutes telles quelles F (Factuel)
Calcule des moyennes, ratios, statistiques A (Analytique)
Propose une lecture, un diagnostic, une recommandation I (Interprétatif)
Expose clairement les limites du système et de son interprétation H (Honnête)
Un même bloc peut déclarer plusieurs natures pour différentes tables qu'il produit, en passant le paramètre nature à chaque appel de _table(). La nature déclarée dans les métadonnées du bloc est la nature dominante globale utilisée pour le comptage et la bibliothèque.

Limites et bonnes pratiques

  • Un bloc personnalisé ne doit pas dépasser quelques centaines de lignes de Python. Au-delà, il vaut mieux déporter la logique dans une API externe appelée par le bloc.
  • Les blocs personnalisés ne bénéficient pas des mises à jour automatiques du moteur. Une évolution majeure d'IsoFind peut imposer une relecture du code.
  • La documentation du code avec des commentaires est vivement recommandée : un bloc créé il y a deux ans par un collègue parti demande à être relu avant d'être modifié.
  • Tester systématiquement le bloc sur un petit projet avant de l'inclure dans un template critique.

Pour aller plus loin