Aufbau eines Werkzeugs
Welche Dateien ein Werkzeug hat, was in tool.json steht und was flow.js mitbringt.
Ein Werkzeug ist ein Verzeichnis tools/<name>/ im Repository deiner Instanz. Es enthält statische Dateien, und die Instanz liefert sie unter /t/<name>/ aus, auf derselben Herkunft wie die Datenschnittstelle. Einen Bauschritt gibt es nicht: Was im Repository steht, läuft.
Die Dateien
tools/<name>/tool.json Titel, Beschreibung, Einstiegsdatei und was das Werkzeug braucht
tools/<name>/index.html die Seite, ohne Inline-Skript
tools/<name>/app.js dein Skript
tools/<name>/style.css deine Stilvorlage
Der Name besteht aus Kleinbuchstaben, Ziffern und Bindestrichen. Als Vorlage dient tools/example/ im Klon. new-tool.py und scaffold_tool kopieren sie für eine Collection.
tool.json
{
"title": "Aufgaben",
"description": "Offene Aufgaben erfassen und abschliessen",
"entry": "index.html",
"uses": {
"collections": ["aufgaben"],
"buckets": [],
"capabilities": []
}
}
uses sagt, was das Werkzeug braucht: Collections, Buckets und Fähigkeiten wie mail.send. Halte die Angabe aktuell, wenn das Werkzeug eine weitere Collection liest, Dateien ablegt oder Mail sendet.
- Alle drei Listen stehen da. Eine leere Liste heisst: nichts davon.
- Was die Listen nennen, muss es geben. Eine Collection, die noch im Übungsraum wartet, zählt.
- Im Entwurf darf
usesfehlen. Veröffentlichen lässt sich ein Werkzeug nur damit. usesist eine Erklärung, keine Grenze. Das Werkzeug erreicht, was die Person erreicht, die es benutzt. Die Liste zeigt der Administration, welche Rechte zum Werkzeug gehören.
Was die Instanz durchsetzt
Die Instanz setzt für jedes Werkzeug eine Inhaltsrichtlinie. Ein Werkzeug kann sie nicht ändern.
- Kein Inline-Skript. Skript steht in einer
.js-Datei. Einen Stand mit Inline-Skript weist die Instanz ab. - Kein Inline-Stil. Stil steht in einer
.css-Datei. - Keine fremden Quellen. Skripte, Schriften, Bilder und Aufrufe kommen nur von der Instanz selbst. Kein CDN, keine fremde Schnittstelle. Ein Formular schickt nichts an einen Server ab; Daten gehen über
fetchan die Schnittstelle der Instanz. - Nur bekannte Dateiarten: html, js, css, json, svg, png, jpg, jpeg, webp, ico, woff2, md, txt.
- Grenzen: höchstens 200 Dateien und 20 MB je Werkzeug, 5 MB je Datei.
So verlassen Daten die Instanz nicht über den Browser.
flow.js einbinden
flow.js ist der Client der Schnittstelle. Er gehört der Instanz, nicht dem Werkzeug. Binde ihn vor deinem Skript ein und kopiere ihn nie in das Werkzeug:
<script src="/flow/v1/flow.js"></script>
<script src="app.js"></script>
Er kommt mit jedem Update der Instanz mit. v1 wächst nur. Was eine Funktion anders machen würde, käme als /flow/v2/flow.js daneben.
Die Funktionen
Jeder Aufruf gibt ein Promise zurück.
| Aufruf | Was er tut |
|---|---|
Flow.schema(c) | Felder der Collection in Schemareihenfolge, mit Typ, Pflicht und Werteliste |
Flow.query(c, body) | liest Zeilen, antwortet {records, hasMore, cursor} |
Flow.count(c, body) | zählt, antwortet {count} |
Flow.stats(c, body) | Kennzahlen zu einem Feld |
Flow.aggregate(c, body) | gruppiert, antwortet {groups, more} |
Flow.create(c, values) | legt eine Zeile an |
Flow.update(c, id, version, values) | ändert eine Zeile |
Flow.remove(c, id, version) | löscht eine Zeile |
Flow.options(c, field) | Auswahl für ein Verweisfeld: {options: [{id, label}], hasMore} |
Flow.fieldInput(field) | ein Formularelement für ein Feld aus Flow.schema |
Flow.view | Ansichtszustand im Fragment der Adresse: read(), write(state), onChange(callback) |
Flow.texts | die Meldungen für Benutzer, zum Ersetzen |
Lesen und anlegen:
Flow.query("aufgaben", {
filter: { field: "status", op: "eq", value: "offen" },
sort: { field: "faellig", direction: "asc" },
limit: 20
}).then(function (page) {
page.records.forEach(show);
});
Flow.create("aufgaben", { titel: "Angebot prüfen", status: "offen" });
Ändern mit der Version, die du gelesen hast, und Fehler behandeln:
Flow.update("aufgaben", row.id, row.version, { status: "erledigt" })
.catch(function (error) {
if (error.status === 409) {
reload(); // jemand war schneller
}
showMessage(error.message);
error.fields.forEach(function (problem) {
markField(problem.field, problem.message);
});
});
Ein fehlgeschlagener Aufruf wirft einen Flow.FlowError mit status, message und fields. show, reload, showMessage und markField sind hier Funktionen deines Werkzeugs.
Den Ansichtszustand hält Flow.view im Fragment der Adresse (#…). Das Fragment erreicht den Server nicht, ein Filterwert steht so in keinem Protokoll:
Flow.view.write({ status: "offen" });
var state = Flow.view.read(); // { status: "offen" }
Fehler im Browser
flow.js meldet der Instanz, was im Browser schiefgeht: nicht gefangene Fehler, abgelehnte Promises und Aufrufe, die der Server abgewiesen hat. Die Meldungen stehen im Adminbereich auf der Seite des Werkzeugs, und der Agent liest sie mit list_tool_errors. Wer den Fehler ausgelöst hat, erfasst die Instanz nicht.
Die Aufrufe im Einzelnen stehen unter Daten lesen und schreiben.