KEPLIN Docs

Ereignisse und das SDK

Die Ereignisse der Widgets und des Bildschirms, der Code-Editor, die vordefinierten Aktionen und das keplin-SDK in TypeScript — Daten, Widgets, Navigation, Sitzung, Modals und Workflows.

Viele Bildschirme entstehen, ohne eine Zeile zu schreiben: einen Datastore binden, Widgets ziehen, einen Button auf einen anderen Bildschirm richten. Aber früher oder später kommt das „wenn dies passiert, tu jenes" — speichern und zurückgehen, eine Tabelle nach einem Filter neu laden, vor dem Löschen bestätigen, ein Modal öffnen und verwenden, was es zurückgegeben hat.

Genau dafür sind die Ereignisse da: Punkte des Bildschirms, an denen Ihr Code läuft, in TypeScript geschrieben, mit einem SDK — dem Objekt keplin — das Zugang zu allem gibt, was der Bildschirm hat.

Wo die Ereignisse stehen

Im Inspektor heißt die letzte Kategorie eines Widgets (und des Bildschirms selbst) Ereignisse. Sie hat eine Zeile je verfügbarem Ereignis, und in jeder Zeile:

  • einen Punkt links: gefüllt, wenn dieses Ereignis schon Code hat, leer, wenn nicht;
  • einen Button rechts, der den Editor öffnet.

Die Kategorie Ereignisse eines Buttons: ein gefüllter Punkt markiert die Ereignisse, die schon Code haben; das … öffnet den Editor.
Die Kategorie Ereignisse eines Buttons: ein gefüllter Punkt markiert die Ereignisse, die schon Code haben; das … öffnet den Editor.

Die Namen der Ereignisse werden nicht übersetzt — sie sind in jeder Sprache dieselben (onClick, onRowClick, onLoad), denn es sind auch die Namen, die im Code und in den Protokollen des Radar erscheinen.

Die Ereignisse des Bildschirms

Klicken Sie auf eine leere Zone des Canvas, damit der Inspektor den Bildschirm zeigt. Die Kategorie Ereignisse hat drei:

Ereignis Wann es auslöst Wofür
onLoad Einmal, wenn der Bildschirm öffnet. Zustand vorbereiten, Dinge laden, die die Datastores nicht laden, willkommen heißen.
onParamsChange Immer, wenn sich die Parameter der Route ändern — und nicht beim ersten Öffnen. Auf einen Datensatzwechsel reagieren, ohne den Bildschirm neu zu öffnen.
onUnload Wenn der Bildschirm verlassen wird. Zustand aufräumen, Entwürfe sichern.

Die Ereignisse des Bildschirms selbst — onLoad, onParamsChange und onUnload — im Inspektor ohne Auswahl.
Die Ereignisse des Bildschirms selbst — onLoad, onParamsChange und onUnload — im Inspektor ohne Auswahl.

Die Ereignisse jedes Widgets

Jeder Widget-Typ deklariert seine eigenen. Neben dem Namen kommt es auf den Payload an — die Daten, die das Ereignis mitbringt und die der Code in keplin.event liest.

Formularfelder

Widget Ereignisse keplin.event
Textfeld, Textbereich, Zahl, Ja/Nein, Auswahlliste, Datum, Farbe onChange { value }
Datei-Upload onChange, onUpload onUpload: { file, name }

Aktionen und Navigation

Widget Ereignisse keplin.event
Button onClick {}
Menü-Button onClick, onMenuItem onMenuItem: { id, label }
Link onClick {}
Export onExport, onDataLoaded onExport: { rows, filename }

Struktur und Inhalt

Widget Ereignisse keplin.event
Tabs onTabChange { tab }
Bericht onLoad { report }

Daten-Widgets

Widget Ereignisse keplin.event
Tabelle onRowClick, onRowDoubleClick, onSelectionChange, onDataLoaded { row, index } · onSelectionChange: { row, rows }
Liste, Karten onRowClick, onDataLoaded { row, index }
Diagramm onClick { name, seriesName, value, dataIndex }
KPI onClick, onDataLoaded { value, indicatorId }

Boards und Planung

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

Prozesse

Widget Ereignisse keplin.event
Status des Prozesses onDecide { task, outcome }
Meine Aufgaben onOpen, onDecide { task, screenId }

Nota

Von Ihnen programmierte Widgets (die, die in der Palette unter Benutzerdefiniert erscheinen) deklarieren ihre eigenen Ereignisse und erscheinen hier wie alle anderen.

Der Code-Editor

Der Button eines Ereignisses öffnet den Editor in einem Modal. Der Titel sagt, wo Sie sind: die id des Widgets (oder der Name des Bildschirms) und der Name des Ereignisses — w_fic_sav1 · onClick.

Der Editor des Ereignisses onClick des Buttons Speichern: der Code speichert den Datastore und meldet, wenn es gut ging, und geht zur Liste zurück.
Der Editor des Ereignisses onClick des Buttons Speichern: der Code speichert den Datastore und meldet, wenn es gut ging, und geht zur Liste zurück.

Button Was er tut
Aktion einfügen Schreibt für Sie den Code einer gängigen Aufgabe (siehe unten).
Handler entfernen Löscht den Code dieses Ereignisses. Der Punkt wird wieder leer.
Abbrechen Schließt ohne zu speichern.
Speichern Prüft und speichert.

Der Editor hat Vorschläge während des Schreibens (Strg+Leertaste): Das ganze keplin ist deklariert, mit den richtigen Typen — und, noch besser, die ids der Widgets dieses Bildschirms stecken darin. keplin.widgets.get(" zu schreiben zeigt die Liste der Widgets des Bildschirms, und eine id, die nicht existiert, wird als Fehler markiert, bevor Sie speichern.

Atenção

Beim Speichern wird der Code kompiliert. Ist er nicht ausführbar, weist ihn die Plattform zurück — Das Ereignis wurde nicht gespeichert: Der Code ist nicht ausführbar — und das Modal bleibt offen, damit Sie korrigieren. Ein Bildschirm behält niemals kaputten Code in sich.

Die vordefinierten Aktionen

Aktion einfügen öffnet eine Liste der häufigsten Aufgaben. Sie wählen eine aus, und der Code wird an das Ende des bereits Vorhandenen geschrieben, schon mit den echten Namen Ihres Bildschirms — dem ersten Datensatz-Datastore, der ersten Tabelle, dem ersten Textfeld.

Aktion einfügen — die vordefinierten Aktionen, die den Code für Sie schreiben, von den Datastores bis zu den Workflows.
Aktion einfügen — die vordefinierten Aktionen, die den Code für Sie schreiben, von den Datastores bis zu den Workflows.

Aktion Was sie schreibt
Datastore speichern Validiert und speichert den Datensatz, mit Erfolgsmeldung.
Datastore neu laden Liest die Daten eines Datastores erneut.
Datastore filtern (nach Text) Liest den Text eines Feldes und wendet ihn als Filter an.
Zu einem Bildschirm navigieren Springt zu einer anderen Route der App.
Eine Tabelle neu laden Aktualisiert die Daten eines Tabellen-Widgets.
Tabelle nach dem Wert eines Textfelds filtern Der klassische interaktive Filter.
Ein Widget ein-/ausblenden Schaltet die Sichtbarkeit eines Widgets um.
Bestätigen und Toast anzeigen Fragt, bevor es handelt, und meldet am Ende.
Einen Workflow starten Setzt einen Prozess über dem aktuellen Datensatz in Gang.
Aufgaben ansehen und abschließen Listet die Aufgaben des Benutzers auf und entscheidet eine.
Ein Signal an einen Workflow senden Weckt Prozesse, die gewartet haben.
Abmelden Verlässt die App.

Der eingefügte Code ist ein Ausgangspunkt: Er wird Ihrer, und er ist zum Bearbeiten da. Er wird nicht erneut erzeugt.

Wie der Code läuft

Jedes Ereignis ist eine asynchrone Funktion, die nur eines bekommt: das keplin. Daraus folgen drei praktische Konsequenzen:

  • await funktioniert auf der obersten Ebene des Codes. Man muss nichts einwickeln.
  • return verlässt das Ereignis. Das ist die normale Art, auf halbem Weg aufzugeben (zum Beispiel, wenn eine Bestätigung abgelehnt wurde).
  • Es gibt keine Parameter. Der Kontext steckt im keplin selbst: keplin.event bringt den Payload, und keplin.ctx sagt, wo Sie sind (ctx.widget ist das Widget, das ausgelöst hat — null bei den Ereignissen des Bildschirms —, ctx.event ist der Name des Ereignisses und ctx.screen der Bildschirm).

Solange der Code eines Buttons nicht fertig ist, zeigt der Button drei animierte Punkte: Wer die App nutzt, merkt, dass sie arbeitet. Wenn der Code platzt, bricht der Bildschirm nicht: Es erscheint eine Warnung, und der Fehler wird im Radar protokolliert, mit dem Bildschirm, dem Widget und dem Ereignis, in dem er passiert ist.

Das SDK keplin

Alles, was der Code tun kann, steht unter keplin. Das sind die Bereiche:

Bereich Wofür
keplin.event / keplin.ctx Der Payload des Ereignisses und der Kontext, in dem es läuft.
keplin.widgets Mit den Widgets des Bildschirms sprechen.
keplin.data Die Datastores: lesen, schreiben, filtern, speichern.
keplin.nav Navigieren und die Parameter der Route lesen.
keplin.ui Meldungen, Bestätigungen und Modals.
keplin.state Zustand, der zwischen Bildschirmen geteilt wird.
keplin.session Wer die App nutzt, und was er darf.
keplin.auth Login, Registrierung und Passwort-Wiederherstellung (Systembildschirme).
keplin.i18n Übersetzte Sätze.
keplin.storage Einstellungen, die auf dem Gerät gespeichert werden.
keplin.api Die APIs der App direkt aufrufen.
keplin.reports Berichte öffnen und herunterladen.
keplin.workflow Prozesse starten, Aufgaben auflisten und abschließen.

Die Widgets

keplin.widgets.get("id") gibt das Handle eines Widgets zurück. Alle Handles haben dieselben Grundlagen:

const w = keplin.widgets.get("w_fic_tel1");
w.show();               // anzeigen
w.hide();               // ausblenden
w.setEnabled(false);    // deaktivieren
w.set("label", "Mobiltelefon");   // eine beliebige Eigenschaft des Inspektors ändern
w.get("label");         // den wirksamen Wert lesen
w.reset();              // die zur Laufzeit gemachten Änderungen vergessen

Und danach ergänzt jede Familie, was ihr eigen ist:

Familie Was sie ergänzt
Formularfelder getValue(), setValue(v), validate(), error
Daten-Widgets (Tabelle, Liste, Karten, Diagramm, KPI, Kanban, Kalender, Gantt) rows, total, refresh(), setFilter(where), setSort(sort)
Tabelle selectedRow, selectedRows, clearSelection()
KPI value, values, valueOf(indikatorId)
Kanban columns, moveCard(id, spalte, index?)
Kalender view, start, end, goTo(datum), setView(ansicht)
Gantt zoom, setZoom(z)
Tabs activeTab, tab("id") — und, am Tab, activate(), show(), hide(), setEnabled()
Beschriftung / Button / Link / Breadcrumb setText(t) / setLabel(t)
Markdown setContent(md)
Externe Seite setUrl(url), reload()
Export export()
Bericht url, download()

Nota

Die Vorschläge des Editors bieten alle Verben aller Familien an, weil der Editor nicht im Voraus weiß, welches Widget diese id ist. Zur Laufzeit gibt es nur die des echten Typs — moveCard an einem Button tut nichts Nützliches.

Die Daten

keplin.data.store("name") gibt einen Datastore des Bildschirms über seinen Namen zurück (siehe Datastores und Daten).

In einem Datensatz-Datastore:

const conta = keplin.data.store("conta");
conta.get("nome");                 // ein Feld lesen
conta.set("estado", "ativo");      // ein Feld schreiben (bleibt ungespeichert)
conta.record();                    // der ganze Datensatz
conta.isDirty();                   // gibt es ungespeicherte Änderungen?
conta.reset();                     // die Änderungen wegwerfen
const ok = await conta.save();     // validiert und speichert; true, wenn gespeichert

In einem Listen-Datastore:

const contas = keplin.data.store("contas");
contas.rows();                     // die geladenen Zeilen
contas.total();                    // die Gesamtzahl (wenn der Server sie liefert)
contas.reload();                   // erneut lesen
contas.setWhere({ estado: { eq: "ativo" } });   // zusätzlicher Filter; null löscht ihn
contas.setSort([{ field: "nome", direction: "ASC" }]);
contas.goToPage(2);

In beiden sagt status(), wie es um das Laden steht (idle, loading, ready, error).

keplin.nav.go("/ficha-de-conta/17");   // zu einer Route gehen (mit Parametern)
keplin.nav.back();                      // zurückgehen
keplin.nav.params;                      // die Parameter des aktuellen Bildschirms, nach Namen

Meldungen, Bestätigungen und Modals

keplin.ui.toast("Gespeichert.", "success");        // "success" | "error" | "info"
const ok = await keplin.ui.confirm("Den Datensatz löschen?");
if (!ok) return;

Die Bestätigung ist ein Dialog mit dem Theme der App — niemals der graue Kasten des Browsers.

Zustand, Sitzung und Einstellungen

keplin.state.set("filtroContas", "activas");   // lebt, solange der Tab offen ist
keplin.state.get("filtroContas");
keplin.state.remove("filtroContas");

keplin.session.user;              // { id, username, name } — null auf öffentlichen Bildschirmen
keplin.session.roles;             // die Rollen dessen, der die App nutzt
keplin.session.can("contas.editar");   // hat er diese Aktion? (Einstellungen ▸ Berechtigungen)
await keplin.session.logout();

keplin.storage.set("colunasContas", ["nome", "cidade"]);   // bleibt auf dem Gerät
keplin.storage.get("colunasContas");

Dica

Um zu entscheiden, was jemand darf, fragen Sie keplin.session.can("...") und nicht hasRole("gestor"). Die Aktionen werden unter Einstellungen ▸ Berechtigungen deklariert und überleben Umbauten an den Rollen; der Name einer Rolle nicht.

Die APIs und die Berichte

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

keplin.reports.open("Kontakte des Kontos", { contaId: 17 });
keplin.reports.download("Kontakte des Kontos", { contaId: 17 }, "xlsx");

Bei einer Abfrage ist die Feldliste Pflicht — sie ist es, die sagt, was Sie mitbringen wollen.

Atenção

keplin.reports.open öffnet einen neuen Tab und darf deshalb nicht hinter einem await stehen: Außerhalb der Geste des Benutzers blockiert der Browser das Fenster. Öffnen Sie zuerst, machen Sie den Rest danach.

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);

Übersetzte Sätze

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

Modale Bildschirme

Ein Bildschirm von Keplin ist nicht modal, weil er auf eine bestimmte Weise geöffnet wurde — er ist modal, weil er so konfiguriert wurde. Die Entscheidung fällt im Inspektor des Bildschirms, in der Kategorie Darstellung:

Der Abschnitt Darstellung des Bildschirms: hier wird ein Bildschirm zum Modal (zentriert) oder zum Seitenpanel (rechts).
Der Abschnitt Darstellung des Bildschirms: hier wird ein Bildschirm zum Modal (zentriert) oder zum Seitenpanel (rechts).

Option Was sie tut
Modus Bildschirm (eine normale Seite), Modal (zentriert) oder Seitenpanel (rechts).
Breite (px) / Höhe (px) Die Größe des Modals. Das Seitenpanel nutzt die volle Höhe.
Schließen-Button Zeigt das × in der Ecke.
Klick außerhalb schließt / Esc schließt Die beiden üblichen Ausgänge.
Bildschirm dahinter beim Schließen aktualisieren Beim Schließen lesen die Datastores des aufrufenden Bildschirms erneut.

Der Hinweis des Abschnitts selbst fasst es zusammen: Öffnet ÜBER dem aufrufenden Bildschirm (Link, Ereignisse oder keplin.ui.openModal). Aus der direkten Navigation ausgenommen.

Per Code öffnen und schließen

const resultado = await keplin.ui.openModal("/nova-conta", { setor: "banca" });
if (resultado) {
  keplin.data.store("contas").reload();
}
  • openModal bekommt die Route (oder die id) des Bildschirms und, optional, die Parameter.
  • Das Promise löst sich erst auf, wenn das Modal schließt, und bringt den Wert mit, den das Modal zurückgegeben hat.
  • Innerhalb des Modals schließt keplin.ui.closeModal(wert) und gibt diesen Wert zurück.
  • Modals stapeln sich: Ein Modal kann ein weiteres öffnen.

Nota

keplin.nav.go("/route") auf einen Bildschirm, der als Modal (zentriert) oder Seitenpanel (rechts) konfiguriert ist, öffnet ihn als Modal, statt zu navigieren. Das ist Absicht: Ein modaler Bildschirm hat in der Navigation keine eigene Adresse.

Rezepte

Speichern und zurückgehen (das onClick des Speichern-Buttons des Kontodatenblatts):

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

Das Datenblatt der angeklickten Zeile öffnen (onRowClick einer Tabelle):

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

Eine Tabelle über ein Textfeld filtern (onChange des Feldes — ersetzen Sie die ids durch die Ihres Bildschirms):

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

Vor einer zerstörenden Aktion bestätigen (onClick eines Buttons):

if (!(await keplin.ui.confirm("Dieses Konto löschen?"))) return;

Einen Button vor dem verbergen, der nicht darf (onLoad des Bildschirms):

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

Warum nicht…?

  • Warum lässt es mich das Ereignis nicht speichern? Der Code kompiliert nicht. Die Meldung lautet Das Ereignis wurde nicht gespeichert: Der Code ist nicht ausführbar — korrigieren und speichern.
  • Warum gibt keplin.widgets.get("...") einen Fehler? Die id existiert auf diesem Bildschirm nicht. Prüfen Sie sie oben im Inspektor, mit ausgewähltem Widget; und denken Sie daran, dass jedes Gerät ein eigener Baum ist (siehe Layouts und Design je Gerät).
  • Warum hat onParamsChange beim Öffnen nicht ausgelöst? Das ist Absicht: Es löst nur bei Änderungen aus. Für den Start nehmen Sie onLoad.
  • Warum gibt das Modal nichts zurück? Entweder existiert der Zielbildschirm nicht, oder wer die App nutzt, hat keine Berechtigung, ihn zu öffnen — in beiden Fällen löst sich das Promise ohne Wert auf. Prüfen Sie die Route und die Berechtigungen.
  • Warum öffnet sich das Fenster des Berichts nicht? Sie haben das open hinter ein await gesetzt. Öffnen Sie zuerst.
  • Warum scheint mein Ereignis nicht zu laufen? Sehen Sie in den Radar: Die Fehler aus dem Code der Ereignisse landen dort, mit Bildschirm, Widget und Ereignis — und der Radar bringt Sie direkt zum Editor dieses Ereignisses.