KEPLIN Docs

Eventi e SDK

Gli eventi dei widget e della schermata, l'editor di codice, le azioni predefinite e l'SDK keplin in TypeScript — dati, widget, navigazione, sessione, modali e workflow.

C'è tanta schermata che si fa senza scrivere una riga: collegare un datastore, trascinare widget, puntare un pulsante a un'altra schermata. Ma prima o poi arriva il "quando succede questo, fai quello" — salvare e tornare indietro, ricaricare una tabella dopo un filtro, confermare prima di eliminare, aprire un modale e usare ciò che ha restituito.

È a questo che servono gli eventi: punti della schermata dove gira codice tuo, scritto in TypeScript, con un SDK — l'oggetto keplin — che dà accesso a tutto ciò che la schermata ha.

Dove sono gli eventi

Nell'inspector, l'ultima categoria di un widget (e della schermata stessa) si chiama Eventi. Ha una riga per ogni evento disponibile, e in ogni riga:

  • un punto a sinistra: pieno quando quell'evento ha già del codice, vuoto quando non ne ha;
  • un pulsante a destra, che apre l'editor.

La categoria Eventi di un Pulsante: un punto pieno segna gli eventi che hanno già codice; il … apre l'editor.
La categoria Eventi di un Pulsante: un punto pieno segna gli eventi che hanno già codice; il … apre l'editor.

I nomi degli eventi non sono tradotti — sono gli stessi in qualsiasi lingua (onClick, onRowClick, onLoad), perché sono anche i nomi che appaiono nel codice e nei registri del Radar.

Gli eventi della schermata

Clicca su una zona vuota del canvas perché l'inspector mostri la schermata. La categoria Eventi ne ha tre:

Evento Quando scatta Per che cosa
onLoad Una volta, quando la schermata si apre. Preparare lo stato, caricare cose che i datastore non caricano, dare il benvenuto.
onParamsChange Ogni volta che i parametri del percorso cambiano — e non alla prima apertura. Reagire a un cambio di record senza riaprire la schermata.
onUnload Quando la schermata se ne va. Pulire lo stato, salvare bozze.

Gli eventi della schermata stessa — onLoad, onParamsChange e onUnload — nell'inspector senza selezione.
Gli eventi della schermata stessa — onLoad, onParamsChange e onUnload — nell'inspector senza selezione.

Gli eventi di ogni widget

Ogni tipo di widget dichiara i suoi. Oltre al nome, conta il payload — i dati che l'evento porta con sé, e che il codice legge in keplin.event.

Campi di modulo

Widget Eventi keplin.event
Casella di testo, Area di testo, Numero, Sì/No, Dropdown, Data, Colore onChange { value }
File onChange, onUpload onUpload: { file, name }

Azioni e navigazione

Widget Eventi keplin.event
Pulsante onClick {}
Pulsante con menu onClick, onMenuItem onMenuItem: { id, label }
Link onClick {}
Esporta onExport, onDataLoaded onExport: { rows, filename }

Struttura e contenuto

Widget Eventi keplin.event
Schede onTabChange { tab }
Report onLoad { report }

Widget di dati

Widget Eventi keplin.event
Tabella onRowClick, onRowDoubleClick, onSelectionChange, onDataLoaded { row, index } · onSelectionChange: { row, rows }
Elenco, Card onRowClick, onDataLoaded { row, index }
Grafico onClick { name, seriesName, value, dataIndex }
KPI onClick, onDataLoaded { value, indicatorId }

Board e pianificazione

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

Processi

Widget Eventi keplin.event
Stato del processo onDecide { task, outcome }
Le mie attività onOpen, onDecide { task, screenId }

Nota

I widget programmati da te (quelli che appaiono nella palette in Custom) dichiarano i propri eventi, e appaiono qui come tutti gli altri.

L'editor di codice

Il pulsante di un evento apre l'editor in un modale. Il titolo dice dove sei: l'id del widget (o il nome della schermata) e il nome dell'evento — w_fic_sav1 · onClick.

L'editor dell'evento onClick del pulsante Salva: il codice salva il datastore e, se è andato bene, avvisa e torna all'elenco.
L'editor dell'evento onClick del pulsante Salva: il codice salva il datastore e, se è andato bene, avvisa e torna all'elenco.

Pulsante Che cosa fa
Inserisci azione Scrive per te il codice di un'attività comune (qui sotto).
Rimuovi handler Elimina il codice di questo evento. Il punto torna vuoto.
Annulla Chiude senza salvare.
Salva Verifica e salva.

L'editor ha suggerimenti mentre scrivi (Ctrl+Spazio): tutto il keplin è dichiarato, con i tipi giusti — e, meglio ancora, gli id dei widget di questa schermata sono lì dentro. Scrivere keplin.widgets.get(" mostra l' elenco dei widget della schermata, e un id che non esiste viene segnalato come errore prima che tu salvi.

Atenção

Al salvataggio, il codice viene compilato. Se non è eseguibile, la piattaforma lo rifiuta — L'evento non è stato salvato: il codice non è eseguibile — e il modale resta aperto perché tu corregga. Una schermata non resta mai con codice rotto lì dentro.

Le azioni predefinite

Inserisci azione apre un elenco delle attività più comuni. Ne scegli una e il codice viene scritto in fondo a ciò che c'è già, già con i nomi reali della tua schermata — il primo datastore di record, la prima tabella, la prima casella di testo.

Inserisci azione — le azioni predefinite che scrivono il codice per te, dai datastore ai workflow.
Inserisci azione — le azioni predefinite che scrivono il codice per te, dai datastore ai workflow.

Azione Che cosa scrive
Salva datastore Valida e salva il record, con avviso di successo.
Ricarica datastore Rilegge i dati di un datastore.
Filtra datastore (per testo) Legge il testo di una casella e lo applica come filtro.
Naviga verso una schermata Salta a un altro percorso dell'app.
Ricarica una tabella Aggiorna i dati di un widget di tabella.
Filtra la tabella con il testo di un campo Il filtro interattivo classico.
Mostra/nascondi un widget Alterna la visibilità di un widget.
Conferma e mostra un toast Chiede prima di agire e avvisa alla fine.
Avvia un workflow Mette in moto un processo sul record attuale.
Visualizza e completa le attività Elenca le attività di chi sta usando l'app e ne decide una.
Invia un segnale a un workflow Sveglia i processi che erano in attesa.
Esci Esce dall'app.

Il codice inserito è un punto di partenza: diventa tuo, ed è lì per essere modificato. Non viene generato di nuovo.

Come gira il codice

Ogni evento è una funzione asincrona che riceve una cosa sola: il keplin. Da lì escono tre conseguenze pratiche:

  • await funziona in cima al codice. Non serve avvolgere nulla.
  • return esce dall'evento. È il modo normale di rinunciare a metà (per esempio, quando una conferma è stata rifiutata).
  • Non ci sono parametri. Il contesto arriva dentro il keplin stesso: keplin.event porta il payload e keplin.ctx dice dove sei (ctx.widget è il widget che ha fatto scattare l'evento — null negli eventi di schermata —, ctx.event è il nome dell'evento e ctx.screen la schermata).

Finché il codice di un pulsante non finisce, il pulsante mostra tre puntini animati: chi sta usando l'app capisce che sta lavorando. Se il codice esplode, la schermata non si rompe: appare un avviso e l'errore resta registrato nel Radar, con la schermata, il widget e l'evento in cui è successo.

L'SDK keplin

Tutto ciò che il codice può fare sta sotto keplin. Queste sono le aree:

Area Per che cosa
keplin.event / keplin.ctx Il payload dell'evento e il contesto in cui sta girando.
keplin.widgets Parlare con i widget della schermata.
keplin.data I datastore: leggere, scrivere, filtrare, salvare.
keplin.nav Navigare e leggere i parametri del percorso.
keplin.ui Avvisi, conferme e modali.
keplin.state Stato condiviso fra schermate.
keplin.session Chi sta usando l'app, e che cosa può fare.
keplin.auth Login, registrazione e recupero della password (schermate di sistema).
keplin.i18n Frasi tradotte.
keplin.storage Preferenze salvate sul dispositivo.
keplin.api Chiamare le API dell'app direttamente.
keplin.reports Aprire e scaricare report.
keplin.workflow Avviare processi, elencare e completare attività.

I widget

keplin.widgets.get("id") restituisce l'handle di un widget. Tutti gli handle hanno la stessa base:

const w = keplin.widgets.get("w_fic_tel1");
w.show();               // mostrare
w.hide();               // nascondere
w.setEnabled(false);    // disattivare
w.set("label", "Cellulare");   // cambiare qualsiasi proprietà dell'inspector
w.get("label");         // leggere il valore effettivo
w.reset();              // dimenticare le modifiche fatte in esecuzione

E poi ogni famiglia aggiunge ciò che le è proprio:

Famiglia Che cosa aggiunge
Campi di modulo getValue(), setValue(v), validate(), error
Widget di dati (Tabella, Elenco, Card, Grafico, KPI, Kanban, Calendario, Gantt) rows, total, refresh(), setFilter(where), setSort(sort)
Tabella selectedRow, selectedRows, clearSelection()
KPI value, values, valueOf(indicadorId)
Kanban columns, moveCard(id, coluna, índice?)
Calendario view, start, end, goTo(data), setView(vista)
Gantt zoom, setZoom(z)
Schede activeTab, tab("id") — e, sulla scheda, activate(), show(), hide(), setEnabled()
Etichetta / Pulsante / Link / Breadcrumb setText(t) / setLabel(t)
Markdown setContent(md)
Pagina esterna setUrl(url), reload()
Esporta export()
Report url, download()

Nota

I suggerimenti dell'editor offrono tutti i verbi di tutte le famiglie, perché l'editor non sa in anticipo che widget sia quell'id. In esecuzione esistono solo quelli del tipo reale — moveCard su un Pulsante non fa nulla di utile.

I dati

keplin.data.store("nome") restituisce un datastore della schermata per nome (vedi Datastore e dati).

In un datastore di record:

const conta = keplin.data.store("conta");
conta.get("nome");                 // leggere un campo
conta.set("estado", "ativo");      // scrivere un campo (resta da salvare)
conta.record();                    // il record intero
conta.isDirty();                   // ci sono modifiche da salvare?
conta.reset();                     // buttare via le modifiche
const ok = await conta.save();     // valida e salva; true se ha salvato

In un datastore di elenco:

const contas = keplin.data.store("contas");
contas.rows();                     // le righe caricate
contas.total();                    // il totale (quando il server lo dà)
contas.reload();                   // rileggere
contas.setWhere({ estado: { eq: "ativo" } });   // filtro extra; null pulisce
contas.setSort([{ field: "nome", direction: "ASC" }]);
contas.goToPage(2);

In entrambi, status() dice a che punto è il caricamento (idle, loading, ready, error).

keplin.nav.go("/ficha-de-conta/17");   // andare a un percorso (con parametri)
keplin.nav.back();                      // tornare indietro
keplin.nav.params;                      // i parametri della schermata attuale, per nome

Avvisi, conferme e modali

keplin.ui.toast("Salvato.", "success");        // "success" | "error" | "info"
const ok = await keplin.ui.confirm("Eliminare il record?");
if (!ok) return;

La conferma è una finestra di dialogo con il tema dell'app — mai la scatola grigia del browser.

Stato, sessione e preferenze

keplin.state.set("filtroContas", "activas");   // vive finché la scheda resta aperta
keplin.state.get("filtroContas");
keplin.state.remove("filtroContas");

keplin.session.user;              // { id, username, name } — null nelle schermate pubbliche
keplin.session.roles;             // i ruoli di chi sta usando l'app
keplin.session.can("contas.editar");   // ha questa azione? (Impostazioni ▸ Autorizzazioni)
await keplin.session.logout();

keplin.storage.set("colunasContas", ["nome", "cidade"]);   // resta sul dispositivo
keplin.storage.get("colunasContas");

Dica

Per decidere che cosa qualcuno può fare, chiedi keplin.session.can("...") e non hasRole("gestor"). Le azioni si dichiarano in Impostazioni ▸ Autorizzazioni e sopravvivono alle riorganizzazioni dei ruoli; il nome di un ruolo, no.

Le API e i report

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

keplin.reports.open("Contactos da conta", { contaId: 17 });
keplin.reports.download("Contactos da conta", { contaId: 17 }, "xlsx");

In una query, l'elenco dei campi è obbligatorio — è lui a dire che cosa vuoi portare.

Atenção

keplin.reports.open apre una scheda nuova e perciò non può stare dietro a un await: fuori dal gesto dell'utente, il browser blocca la finestra. Apri prima, fai il resto dopo.

Workflow

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

Frasi tradotte

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

Schermate modali

Una schermata di Keplin non è modale perché è stata aperta in un certo modo — è modale perché è stata configurata così. La decisione sta nell'inspector della schermata, nella categoria Presentazione:

La sezione Presentazione della schermata: è qui che una schermata diventa Modale (al centro) o Pannello laterale (a destra).
La sezione Presentazione della schermata: è qui che una schermata diventa Modale (al centro) o Pannello laterale (a destra).

Opzione Che cosa fa
Modalità Schermata (una pagina normale), Modale (al centro) o Pannello laterale (a destra).
Larghezza (px) / Altezza (px) La dimensione del modale. Il pannello laterale usa tutta l'altezza.
Pulsante di chiusura Mostra la × nell'angolo.
Clic fuori chiude / Esc chiude Le due uscite abituali.
Aggiorna la schermata dietro alla chiusura Alla chiusura, i datastore della schermata che l'ha chiamata rileggono.

Il suggerimento della sezione stessa riassume: Si apre SOPRA la schermata che lo chiama (Link, eventi o keplin.ui.openModal). Escluso dalla navigazione diretta.

Aprire e chiudere da codice

const resultado = await keplin.ui.openModal("/nova-conta", { setor: "banca" });
if (resultado) {
  keplin.data.store("contas").reload();
}
  • openModal riceve il percorso (o l'id) della schermata e, facoltativamente, i parametri.
  • La promise si risolve solo quando il modale si chiude, e porta il valore che il modale ha restituito.
  • Dentro il modale, keplin.ui.closeModal(valor) chiude e restituisce quel valore.
  • I modali si impilano: un modale può aprirne un altro.

Nota

keplin.nav.go("/rota") verso una schermata configurata come Modale (al centro) o Pannello laterale (a destra) la apre come modale invece di navigare. È voluto: una schermata modale non ha un indirizzo proprio nella navigazione.

Ricette

Salvare e tornare indietro (l'onClick del pulsante Salva della Scheda Account):

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

Aprire la scheda della riga cliccata (onRowClick di una Tabella):

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

Filtrare una tabella con una casella di testo (onChange della casella — sostituisci gli id con quelli della tua schermata):

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

Confermare prima di un'azione distruttiva (onClick di un pulsante):

if (!(await keplin.ui.confirm("Eliminare questo account?"))) return;

Nascondere un pulsante a chi non può (onLoad della schermata):

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

Perché no…?

  • Perché non mi lascia salvare l'evento? Il codice non compila. Il messaggio è L'evento non è stato salvato: il codice non è eseguibile — correggi e salva.
  • Perché keplin.widgets.get("...") dà errore? L'id non esiste in questa schermata. Verificalo in cima all'inspector, con il widget selezionato; e ricordati che ogni dispositivo è un albero proprio (vedi Layout e design per dispositivo).
  • Perché l'onParamsChange non è scattato all'apertura? È voluto: scatta solo sui cambiamenti. Per l'avvio, usa l'onLoad.
  • Perché il modale non restituisce nulla? O la schermata di destinazione non esiste, oppure chi sta usando l'app non ha il permesso di aprirla — in entrambi i casi la promise si risolve senza valore. Verifica il percorso e i permessi.
  • Perché non apre la finestra del report? Hai messo l'open dopo un await. Apri prima.
  • Perché il mio evento sembra non girare? Guarda il Radar: gli errori del codice degli eventi restano lì, con schermata, widget ed evento — e il Radar ti porta direttamente all'editor di quell'evento.