J’ai une table listant les signalements que je reçois. Chaque signalement = 1 ligne. Pour chaque signalement je souhaite voir où j’en suis de son traitement: audition témoins, audition mis en cause, contrôle de l’accueil etc, et pouvoir également renseigner la date de chaque étape faite. Je veux éviter d’alourdir le tableau avec toutes ces colonnes et j’ai compris qu’il valait mieux créer une autre table spécifiquement sur ces étapes. Dans cette table il faut donc que s’affiche les différentes étapes et dates pour un même signalement (et il peut y avoir plusieurs lignes pour un même signalement car plusieurs auditions). Mais je bute sur les liaisons à faire entre les tables, pour que dans ma table Etapes s’affichent tous les signalements et que je puisse renseigner l’avancée au fur et mesure.
Il suffit d’une table des signalements et d’une table qui agrège tous les jalons avec une relation avec le signalement (« référence »).
L’horodatage peut être automatique.
Je vous montre en capsule (désolé pour la musique !)…
Si besoin, vous pouvez aussi ajouter des informations sur l’utilisateur pour avoir un suivi plus détaillé. (Qui a créé la ligne ? Qui a modifié la ligne pour la dernière fois ?). Cela peut se faire avec les colonnes raccourcis :
CREATED_BY (Crée par > Appliquer au nouvelles lignes)
UPDATED_BY (Créé par > Appliquer lors des modifications de l’enregistrement
Under the hood : les formules d’initialisation Grist
Pour comprendre, comment ce mécanisme fonctionne, on constate que la nouvelle colonne créé avec ce raccourci depuis l’interface est une formule d’init Python avec
Dans Grist, les colonnes peuvent être dotées de formules de déclenchement (trigger formulas). La traduction proposée « formule d’init » n’est pas très heureuse, qui contrairement au formule Python classique qui recalcule et écrase la valeur à chaque rafraichissement de la vue, n’agit que sous des conditions précises :
Appliquer sur les nouvelles lignes : La formule s’exécute uniquement lors de la création d’une ligne. Elle sert de valeur par défaut lors de l’initialisation, tout en autorisant une modification manuelle ultérieure si besoin.
Réappliquer en cas de modification : La formule s’exécute dynamiquement dès qu’un champ de l’enregistrement est mis à jour. Il est possible de choisir les colonnes qui doivent être contrôlées.
Under the hood : l’objet user
Le moteur d’exécution Python évalue ces formules dans un espace sécurisé (sandbox) qui injecte dynamiquement l’objet global user. Il est donc possible de récuperer d’autres informations depuis cet objet comme :
user.Name
user.Email
user.Access : le niveau de privilège de l’utilisateur sur le document en cours (OWNER, EDITOR ou VIEWER)
user.UserRef : l’identifiant unique de l’user dans l’instance Grist
user.SessionID : l’identifiant de la session en cours de l’user
On peut par exemple concaténer les champs dans la formule d’init pour afficher le nom et l’email en même temps.
user.Name + "(" + user.Email + ")"
Comment récupérer dans une formule d’initialisation une information sur l’utilisateur définie dans la table d’appairage des permissions avancées (ACL) ?
Imaginez que vous avez construit des permissions avancées (ACL) et que vous souhaitez récupérer des informations depuis la table d’appairage. Par exemple la colonne qui contient le (ou les) profils métier affectés à vos utilisateurs.
Dans ce cas, on utilise la propriété de l’utilisateur définies pour les permissions avancées. Dans la capture ci-dessous, cette propriété est nommé « Team ». Et pour la consommer dans une formule python d’initialisation, il suffit d’écrire : User.Team.COLONNE_DE_LA_TABLE_APPAIRAGE_SOUHAITEE
creator = None
if not user:
creator = "Anonyme"
else:
creator = getattr(user, 'Email', 'Inconnu')
profils = None
if getattr(user, 'Access', '').upper() == "OWNERS":
profils = "SUPER_ADMIN"
else:
raw_p = getattr(getattr(user, 'Team', None), 'PROFILS', None)
p = getattr(raw_p, 'PROFIL', None) if raw_p else None
profils = ", ".join(p) if isinstance(p, list) else (p or "SANS_PROFIL")
return creator + " as ["+profils+"]"
Remarques
On vérifie (test if not user) si l’objet global user existe dans la sandbox, et s’il n’est pas récupérer c’est le cas d’un utilisateur anonyme (ce qui ne devrait pas arriver si vos ACL sont correctement configuré)
On récupère (défensivement) l’email. On est pas sur que la propriété soit présente, et pour éviter que le script ne plante, on utilise getattr. Si la propriété est absente, elle renvoie alors la valeur par défaut "Inconnu"
On a fait le choix de consider les propriétaires comme SUPER_ADMIN. Le script interroge le niveau d’accès Grist (user.Access). S’il correspond à un accès OWNERS, le profil est forcé à "SUPER_ADMIN".
Et pour les autres utilisateurs (qui ne sont pas OWNER) on va chercher l’information dans la colonne PROFILS toujours de manière défensive. On utilise des getattr imbriqués pour explorer de manière sécurisée les métadonnées de l’objet (user.Team.PROFILS.PROFIL) sans risque d’erreur.
Le contenu de profil peut etre une liste (si on a décidé d’autorisation une affectation avec de multiple profiles, d’où le traitement avec ", ".join(p) qui transforme la liste en une chaine séparée par des virgules