KEPLIN Docs

Événements et le SDK

Les événements des widgets et de l'écran, l'éditeur de code, les actions prédéfinies et le SDK keplin en TypeScript — données, widgets, navigation, session, modales et workflows.

Il y a beaucoup d'écrans qui se font sans écrire une ligne : relier un datastore, faire glisser des widgets, pointer un bouton vers un autre écran. Mais tôt ou tard arrive le « quand ceci arrive, fais cela » — enregistrer et revenir en arrière, recharger une table après un filtre, confirmer avant de supprimer, ouvrir un modal et utiliser ce qu'il a renvoyé.

C'est à cela que servent les événements : des points de l'écran où s'exécute votre code, écrit en TypeScript, avec un SDK — l'objet keplin — qui donne accès à tout ce que l'écran contient.

Où sont les événements

Dans l'inspecteur, la dernière catégorie d'un widget (et de l'écran lui-même) s'appelle Événements. Elle a une ligne par événement disponible, et sur chaque ligne :

  • un point à gauche : plein quand cet événement a déjà du code, vide quand il n'en a pas ;
  • un bouton à droite, qui ouvre l'éditeur.

La catégorie Événements d'un Bouton : un point plein marque les événements qui ont déjà du code ; le … ouvre l'éditeur.
La catégorie Événements d'un Bouton : un point plein marque les événements qui ont déjà du code ; le … ouvre l'éditeur.

Les noms des événements ne sont pas traduits — ils sont les mêmes dans toutes les langues (onClick, onRowClick, onLoad), parce que ce sont aussi les noms qui apparaissent dans le code et dans les registres du Radar.

Les événements de l'écran

Cliquez sur une zone vide du canvas pour que l'inspecteur montre l'écran. La catégorie Événements en a trois :

Événement Quand il se déclenche Pour quoi
onLoad Une fois, à l'ouverture de l'écran. Préparer l'état, charger des choses que les datastores ne chargent pas, souhaiter la bienvenue.
onParamsChange Chaque fois que les paramètres de la route changent — et pas à la première ouverture. Réagir à un changement d'enregistrement sans rouvrir l'écran.
onUnload Quand l'écran est quitté. Nettoyer l'état, conserver des brouillons.

Les événements de l'écran lui-même — onLoad, onParamsChange et onUnload — dans l'inspecteur sans sélection.
Les événements de l'écran lui-même — onLoad, onParamsChange et onUnload — dans l'inspecteur sans sélection.

Les événements de chaque widget

Chaque type de widget déclare les siens. Au-delà du nom, ce qui compte est le payload — les données que l'événement transporte, et que le code lit dans keplin.event.

Champs de formulaire

Widget Événements keplin.event
Champ de texte, Zone de texte, Nombre, Oui/Non, Liste, Date, Couleur onChange { value }
Fichier onChange, onUpload onUpload: { file, name }

Actions et navigation

Widget Événements keplin.event
Bouton onClick {}
Bouton avec menu onClick, onMenuItem onMenuItem: { id, label }
Lien onClick {}
Exporter onExport, onDataLoaded onExport: { rows, filename }

Structure et contenu

Widget Événements keplin.event
Onglets onTabChange { tab }
Rapport onLoad { report }

Widgets de données

Widget Événements keplin.event
Table onRowClick, onRowDoubleClick, onSelectionChange, onDataLoaded { row, index } · onSelectionChange: { row, rows }
Liste, Cartes onRowClick, onDataLoaded { row, index }
Graphique onClick { name, seriesName, value, dataIndex }
KPI onClick, onDataLoaded { value, indicatorId }

Tableaux et planification

Widget Événements keplin.event
Kanban onCardClick, onCardCreate, onCardMoved, onDataLoaded { row } · { column } · { row, from, to, index }
Calendrier onEventClick, onDayClick, onRangeSelect, onRangeChange, onDataLoaded { row } · { date } · { start, end } · { start, end, view }
Gantt onBarClick, onEmptyClick, onDataLoaded { row } · { date }

Processus

Widget Événements keplin.event
État du processus onDecide { task, outcome }
Mes tâches onOpen, onDecide { task, screenId }

Nota

Les widgets programmés par vous (ceux qui apparaissent dans la palette sous Personnalisé) déclarent leurs propres événements, et apparaissent ici comme tous les autres.

L'éditeur de code

Le bouton d'un événement ouvre l'éditeur dans une fenêtre. Le titre dit où vous êtes : l'id du widget (ou le nom de l'écran) et le nom de l'événement — w_fic_sav1 · onClick.

L'éditeur de l'événement onClick du bouton Enregistrer : le code enregistre le datastore et, si tout s'est bien passé, avertit et revient à la liste.
L'éditeur de l'événement onClick du bouton Enregistrer : le code enregistre le datastore et, si tout s'est bien passé, avertit et revient à la liste.

Bouton Ce qu'il fait
Insérer une action Écrit pour vous le code d'une tâche courante (voir plus bas).
Retirer le handler Supprime le code de cet événement. Le point redevient vide.
Annuler Ferme sans enregistrer.
Enregistrer Vérifie et enregistre.

L'éditeur propose des suggestions pendant que vous écrivez (Ctrl+Espace) : tout le keplin y est déclaré, avec les bons types — et, mieux encore, les ids des widgets de cet écran sont là-dedans. Écrire keplin.widgets.get(" affiche la liste des widgets de l'écran, et un id qui n'existe pas est signalé comme une erreur avant l'enregistrement.

Atenção

À l'enregistrement, le code est compilé. S'il n'est pas exécutable, la plateforme le refuse — L'événement n'a pas été enregistré : le code n'est pas exécutable — et la fenêtre reste ouverte pour que vous corrigiez. Un écran ne se retrouve jamais avec du code cassé à l'intérieur.

Les actions prédéfinies

Insérer une action ouvre une liste des tâches les plus courantes. Vous en choisissez une et le code est écrit à la suite de ce qui s'y trouve déjà, avec les vrais noms de votre écran — le premier datastore d'enregistrement, la première table, le premier champ de texte.

Insérer une action — les actions prédéfinies qui écrivent le code pour vous, des datastores aux workflows.
Insérer une action — les actions prédéfinies qui écrivent le code pour vous, des datastores aux workflows.

Action Ce qu'elle écrit
Enregistrer le datastore Valide et enregistre l'enregistrement, avec un avis de succès.
Recharger le datastore Relit les données d'un datastore.
Filtrer le datastore (par texte) Lit le texte d'un champ et l'applique comme filtre.
Naviguer vers un écran Saute vers une autre route de l'app.
Recharger une table Rafraîchit les données d'un widget de table.
Filtrer une table par le texte d'un champ Le filtre interactif classique.
Afficher/masquer un widget Bascule la visibilité d'un widget.
Confirmer et afficher un toast Demande avant d'agir et avertit à la fin.
Démarrer un workflow Met un processus en marche sur l'enregistrement actuel.
Voir et terminer les tâches Liste les tâches de la personne connectée et en décide une.
Envoyer un signal à un workflow Réveille des processus qui attendaient.
Se déconnecter Quitte l'app.

Le code inséré est un point de départ : il devient le vôtre, et il est fait pour être modifié. Il n'est pas régénéré.

Comment le code s'exécute

Chaque événement est une fonction asynchrone qui reçoit une seule chose : le keplin. Il en découle trois conséquences pratiques :

  • await fonctionne au premier niveau du code. Il n'y a rien à emballer.
  • return sort de l'événement. C'est la façon normale d'abandonner en cours de route (par exemple, quand une confirmation a été refusée).
  • Il n'y a pas de paramètres. Le contexte vient à l'intérieur du keplin lui-même : keplin.event apporte le payload et keplin.ctx dit où vous êtes (ctx.widget est le widget qui a déclenché — null dans les événements d'écran —, ctx.event est le nom de l'événement et ctx.screen l'écran).

Tant que le code d'un bouton n'est pas terminé, le bouton affiche trois points animés : la personne qui l'utilise comprend que l'app travaille. Si le code explose, l'écran ne casse pas : un avertissement apparaît et l'erreur est enregistrée dans le Radar, avec l'écran, le widget et l'événement où c'est arrivé.

Le SDK keplin

Tout ce que le code peut faire est sous keplin. Voici les domaines :

Domaine Pour quoi
keplin.event / keplin.ctx Le payload de l'événement et le contexte dans lequel il s'exécute.
keplin.widgets Parler aux widgets de l'écran.
keplin.data Les datastores : lire, écrire, filtrer, enregistrer.
keplin.nav Naviguer et lire les paramètres de la route.
keplin.ui Avis, confirmations et modales.
keplin.state État partagé entre écrans.
keplin.session Qui utilise l'app, et ce qu'il peut faire.
keplin.auth Connexion, inscription et récupération de mot de passe (écrans système).
keplin.i18n Phrases traduites.
keplin.storage Préférences conservées sur l'appareil.
keplin.api Appeler les APIs de l'app directement.
keplin.reports Ouvrir et télécharger des rapports.
keplin.workflow Démarrer des processus, lister et terminer des tâches.

Les widgets

keplin.widgets.get("id") renvoie le handle d'un widget. Tous les handles ont les mêmes bases :

const w = keplin.widgets.get("w_fic_tel1");
w.show();               // afficher
w.hide();               // masquer
w.setEnabled(false);    // désactiver
w.set("label", "Mobile");   // changer n'importe quelle propriété de l'inspecteur
w.get("label");         // lire la valeur effective
w.reset();              // oublier les modifications faites à l'exécution

Et ensuite chaque famille ajoute ce qui lui est propre :

Famille Ce qu'elle ajoute
Champs de formulaire getValue(), setValue(v), validate(), error
Widgets de données (Table, Liste, Cartes, Graphique, KPI, Kanban, Calendrier, Gantt) rows, total, refresh(), setFilter(where), setSort(sort)
Table selectedRow, selectedRows, clearSelection()
KPI value, values, valueOf(idIndicateur)
Kanban columns, moveCard(id, colonne, index?)
Calendrier view, start, end, goTo(date), setView(vue)
Gantt zoom, setZoom(z)
Onglets activeTab, tab("id") — et, sur l'onglet, activate(), show(), hide(), setEnabled()
Libellé / Bouton / Lien / Fil d'Ariane setText(t) / setLabel(t)
Markdown setContent(md)
Page externe setUrl(url), reload()
Exporter export()
Rapport url, download()

Nota

Les suggestions de l'éditeur proposent tous les verbes de toutes les familles, parce que l'éditeur ne sait pas d'avance quel widget est cet id. À l'exécution, seuls ceux du type réel existent — moveCard sur un Bouton ne fait rien d'utile.

Les données

keplin.data.store("nom") renvoie un datastore de l'écran par son nom (voir Datastores et données).

Dans un datastore d'enregistrement :

const conta = keplin.data.store("conta");
conta.get("nome");                 // lire un champ
conta.set("estado", "ativo");      // écrire un champ (reste non enregistré)
conta.record();                    // l'enregistrement entier
conta.isDirty();                   // y a-t-il des modifications non enregistrées ?
conta.reset();                     // jeter les modifications
const ok = await conta.save();     // valide et enregistre ; true s'il a enregistré

Dans un datastore de liste :

const contas = keplin.data.store("contas");
contas.rows();                     // les lignes chargées
contas.total();                    // le total (quand le serveur le donne)
contas.reload();                   // relire
contas.setWhere({ estado: { eq: "ativo" } });   // filtre supplémentaire ; null l'efface
contas.setSort([{ field: "nome", direction: "ASC" }]);
contas.goToPage(2);

Dans les deux, status() dit où en est le chargement (idle, loading, ready, error).

keplin.nav.go("/ficha-de-conta/17");   // aller vers une route (avec paramètres)
keplin.nav.back();                      // revenir en arrière
keplin.nav.params;                      // les paramètres de l'écran actuel, par nom

Avis, confirmations et modales

keplin.ui.toast("Enregistré.", "success");     // "success" | "error" | "info"
const ok = await keplin.ui.confirm("Supprimer l'enregistrement ?");
if (!ok) return;

La confirmation est une boîte de dialogue au thème de l'app — jamais la boîte grise du navigateur.

État, session et préférences

keplin.state.set("filtroContas", "activas");   // vit tant que l'onglet est ouvert
keplin.state.get("filtroContas");
keplin.state.remove("filtroContas");

keplin.session.user;              // { id, username, name } — null sur les écrans publics
keplin.session.roles;             // les rôles de la personne connectée
keplin.session.can("contas.editar");   // a-t-elle cette action ? (Paramètres ▸ Permissions)
await keplin.session.logout();

keplin.storage.set("colunasContas", ["nome", "cidade"]);   // reste sur l'appareil
keplin.storage.get("colunasContas");

Dica

Pour décider ce que quelqu'un peut faire, demandez keplin.session.can("...") et non hasRole("gestor"). Les actions sont déclarées dans Paramètres ▸ Permissions et survivent aux réorganisations de rôles ; le nom d'un rôle, non.

Les APIs et les rapports

const linhas = await keplin.api.query("contas", { estado: "ativo" }, ["id", "nome"]);
await keplin.api.mutate("criarConta", { nome: "Nova" }, ["id"]);

keplin.reports.open("Contacts du compte", { contaId: 17 });
keplin.reports.download("Contacts du compte", { contaId: 17 }, "xlsx");

Dans une requête, la liste des champs est obligatoire — c'est elle qui dit ce que vous voulez ramener.

Atenção

keplin.reports.open ouvre un nouvel onglet et ne peut donc pas se trouver derrière un await : hors du geste de l'utilisateur, le navigateur bloque la fenêtre. Ouvrez d'abord, faites le reste ensuite.

Workflows

const registo = keplin.data.store("oportunidade").get("id");
await keplin.workflow.start("wf_aprovacao", registo);

const tarefas = await keplin.workflow.tasks();
await keplin.workflow.complete(tarefas[0].id, "aprovar");

const { woken } = await keplin.workflow.signal("documento-recebido", registo);

Phrases traduites

keplin.i18n.t("{n} comptes actifs", { n: linhas.length });
keplin.i18n.locale;

Écrans modaux

Un écran de Keplin n'est pas modal parce qu'il a été ouvert d'une certaine manière — il est modal parce qu'il a été configuré ainsi. La décision est dans l'inspecteur de l'écran, dans la catégorie Présentation :

La section Présentation de l'écran : c'est ici qu'un écran devient Modal (centre) ou Panneau latéral (droite).
La section Présentation de l'écran : c'est ici qu'un écran devient Modal (centre) ou Panneau latéral (droite).

Option Ce qu'elle fait
Mode Écran (une page normale), Modal (centre) ou Panneau latéral (droite).
Largeur (px) / Hauteur (px) La taille du modal. Le panneau latéral utilise toute la hauteur.
Bouton de fermeture Affiche le × dans le coin.
Clic à l'extérieur ferme / Échap ferme Les deux sorties habituelles.
Actualiser l'écran sous-jacent à la fermeture À la fermeture, les datastores de l'écran appelant relisent.

L'aide de la section elle-même résume : S'ouvre PAR-DESSUS l'écran qui l'appelle (Link, événements ou keplin.ui.openModal). Exclu de la navigation directe.

Ouvrir et fermer par code

const resultado = await keplin.ui.openModal("/nova-conta", { setor: "banca" });
if (resultado) {
  keplin.data.store("contas").reload();
}
  • openModal reçoit la route (ou l'id) de l'écran et, éventuellement, les paramètres.
  • La promesse ne se résout que quand le modal se ferme, et apporte la valeur que le modal a renvoyée.
  • À l'intérieur du modal, keplin.ui.closeModal(valeur) ferme et renvoie cette valeur.
  • Les modales s'empilent : un modal peut en ouvrir un autre.

Nota

keplin.nav.go("/route") vers un écran configuré comme Modal (centre) ou Panneau latéral (droite) l'ouvre comme modal au lieu de naviguer. C'est exprès : un écran modal n'a pas d'adresse propre dans la navigation.

Recettes

Enregistrer et revenir (le onClick du bouton Enregistrer de la Fiche de Compte) :

const ok = await keplin.data.store("conta").save();
if (ok) {
  keplin.ui.toast("Compte enregistré");
  keplin.nav.go("/contas");
}

Ouvrir la fiche de la ligne cliquée (onRowClick d'une Table) :

keplin.nav.go(`/ficha-de-conta/${keplin.event.row["id"]}`);

Filtrer une table avec un champ de texte (onChange du champ — remplacez les ids par ceux de votre écran) :

const texto = keplin.widgets.get("w_pesquisa").getValue();
keplin.widgets.get("w_cta_tab1").setFilter(texto ? { nome: { contains: texto } } : null);

Confirmer avant une action destructrice (onClick d'un bouton) :

if (!(await keplin.ui.confirm("Supprimer ce compte ?"))) return;

Masquer un bouton à qui n'y a pas droit (onLoad de l'écran) :

if (!keplin.session.can("contas.eliminar")) {
  keplin.widgets.get("w_apagar").hide();
}

Pourquoi ne… ?

  • Pourquoi cela ne me laisse-t-il pas enregistrer l'événement ? Le code ne compile pas. Le message est L'événement n'a pas été enregistré : le code n'est pas exécutable — corrigez et enregistrez.
  • Pourquoi keplin.widgets.get("...") donne-t-il une erreur ? L'id n'existe pas sur cet écran. Vérifiez-le en haut de l'inspecteur, avec le widget sélectionné ; et souvenez-vous que chaque appareil est une arborescence à part (voir Layouts et design par appareil).
  • Pourquoi onParamsChange ne s'est-il pas déclenché à l'ouverture ? C'est exprès : il ne se déclenche que sur des changements. Pour le démarrage, utilisez onLoad.
  • Pourquoi le modal ne renvoie-t-il rien ? Soit l'écran de destination n'existe pas, soit la personne qui l'utilise n'a pas la permission de l'ouvrir — dans les deux cas, la promesse se résout sans valeur. Vérifiez la route et les permissions.
  • Pourquoi la fenêtre du rapport ne s'ouvre-t-elle pas ? Vous avez mis le open après un await. Ouvrez d'abord.
  • Pourquoi mon événement semble-t-il ne pas s'exécuter ? Regardez le Radar : les erreurs du code des événements y restent, avec écran, widget et événement — et le Radar vous emmène directement à l'éditeur de cet événement.