docs(tools): document custom tools and add overview screenshot
Deploy tibi-docs / build-and-deploy (push) Failing after 33s

This commit is contained in:
apairon committed 2026-10-20 20:45:24 +00:00
1 parent 7cb57be362
commit c22b324294
7 files changed
+295

No files matched your search

+4
View File
@@ -81,6 +81,7 @@ export default defineConfig({
{ label: 'Navigation und Sprachen', slug: 'projekt/navigation-i18n' }, { label: 'Navigation und Sprachen', slug: 'projekt/navigation-i18n' },
{ label: 'Suche', slug: 'projekt/suche' }, { label: 'Suche', slug: 'projekt/suche' },
{ label: 'Pagebuilder-Anbindung', slug: 'projekt/pagebuilder-dev' }, { label: 'Pagebuilder-Anbindung', slug: 'projekt/pagebuilder-dev' },
{ label: 'Custom Tools', slug: 'projekt/tools-schreiben' },
{ label: 'Website mit SSR', slug: 'projekt/ssr-website' }, { label: 'Website mit SSR', slug: 'projekt/ssr-website' },
{ label: 'Jobs und Aktionen', slug: 'projekt/jobs-actions' }, { label: 'Jobs und Aktionen', slug: 'projekt/jobs-actions' },
{ label: 'LLM nutzen', slug: 'projekt/llm-nutzen' }, { label: 'LLM nutzen', slug: 'projekt/llm-nutzen' },
@@ -101,6 +102,7 @@ export default defineConfig({
{ label: 'Medien', slug: 'admin/medien' }, { label: 'Medien', slug: 'admin/medien' },
{ label: 'Exporte', slug: 'admin/exporte' }, { label: 'Exporte', slug: 'admin/exporte' },
{ label: 'Aktionen', slug: 'admin/aktionen' }, { label: 'Aktionen', slug: 'admin/aktionen' },
{ label: 'Eigene Tools', slug: 'admin/tools' },
{ label: 'Benutzer und Rechte', slug: 'admin/benutzer-rechte' }, { label: 'Benutzer und Rechte', slug: 'admin/benutzer-rechte' },
{ label: 'KI-Funktionen', slug: 'admin/ki-funktionen' }, { label: 'KI-Funktionen', slug: 'admin/ki-funktionen' },
], ],
@@ -134,6 +136,8 @@ export default defineConfig({
{ label: 'Schema-Properties', slug: 'reference/schema-properties' }, { label: 'Schema-Properties', slug: 'reference/schema-properties' },
{ label: 'System-Routen', slug: 'reference/rest-system' }, { label: 'System-Routen', slug: 'reference/rest-system' },
{ label: 'Hook-Kontexte', slug: 'reference/hook-kontexte' }, { label: 'Hook-Kontexte', slug: 'reference/hook-kontexte' },
{ label: 'Custom-Tool-Kontext', slug: 'reference/tool-kontext' },
{ label: 'Custom-Tool-UI', slug: 'reference/tool-ui' },
{ label: 'Hook-Referenz: Daten', slug: 'reference/hooks-daten' }, { label: 'Hook-Referenz: Daten', slug: 'reference/hooks-daten' },
{ label: 'Hook-Referenz: Netze und Nachrichten', slug: 'reference/hooks-netze' }, { label: 'Hook-Referenz: Netze und Nachrichten', slug: 'reference/hooks-netze' },
{ label: 'Hook-Referenz: Sicherheit und Identität', slug: 'reference/hooks-sicherheit' }, { label: 'Hook-Referenz: Sicherheit und Identität', slug: 'reference/hooks-sicherheit' },
Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

+1
View File
@@ -66,6 +66,7 @@ Volle Kontext-Tabelle in der Repo-Doku `custom-export-script.md`; Bedienung unte
- Eigene Eingabeelemente registrierst du am `WidgetDispatcher` (Feldtyp + `meta.widget`-Name) — erst Schema in [Felder und Widgets](/projekt/felder-widgets/) prüfen. - Eigene Eingabeelemente registrierst du am `WidgetDispatcher` (Feldtyp + `meta.widget`-Name) — erst Schema in [Felder und Widgets](/projekt/felder-widgets/) prüfen.
- Neue Admin-Bereiche folgen dem Muster `components/admin/*Tab + *CreateDrawer + *DetailDrawer` mit Suche, Filter, Sortierung und Paginierung. - Neue Admin-Bereiche folgen dem Muster `components/admin/*Tab + *CreateDrawer + *DetailDrawer` mit Suche, Filter, Sortierung und Paginierung.
- **Eigene Tools** für projektspezifische Abläufe liegen unter `meta.tools` und laufen als ES-Module im Admin — siehe [Eigene Tools](/admin/tools/) und [Custom Tools schreiben](/projekt/tools-schreiben/).
- KI-Kontext (`aiController`) bleibt automatisch konsistent, solange du `data-ai-id`-Attribute setzt. - KI-Kontext (`aiController`) bleibt automatisch konsistent, solange du `data-ai-id`-Attribute setzt.
</TabItem> </TabItem>
+55
View File
@@ -0,0 +1,55 @@
---
title: 'Eigene Tools im Admin'
description: 'Projektspezifische Werkzeuge bedienen: Navigation, Rechte, Status, Abbrechen und Grenzen.'
---
Eigene Tools erscheinen im Projekt als eigener Abschnitt **Tools** unterhalb der
Sammlungen. Sie sind keine Sammlungen und keine Actions: Ein Tool ist eine eigene
Seite mit freiem Ablauf, die der Admin aus dem Projekt lädt.
## Wo du Tools findest
![Projekt-Übersicht als Custom Tool im Mock: Kennzahlen zu Seiten, Artikeln und Produkten sowie eine Tabelle mit den letzten Editor-Einträgen](../../../assets/admin/custom-tools-overview.png)
Das Beispiel ist **projektabhängig**: Es zählt die Sammlungen `pages`, `articles` und
`products`. In einem anderen Projekt heißt das Referenz-Tool anders und nutzt dessen
Sammlungen.
- Öffne ein Projekt. Unter den Sammlungen und Aktionen erscheint der Abschnitt
**Tools**.
- Ein Klick öffnet die Tool-Seite. Die Breadcrumb führt zurück zum Projekt.
- Mit `hidden: true` konfigurierte Tools erscheinen nicht in der Liste; die
direkte URL funktioniert weiterhin.
- Fehlende `permissions` blenden das Tool ebenfalls nur aus. Datenrechte bleiben
serverseitig pro Sammlung geschützt.
## Bedienung
| Element | Bedeutung |
|---|---|
| Status-Badge | Bereit, Lädt, Läuft, Abgebrochen oder Fehler |
| **Neu laden** | Startet das Tool neu und räumt den vorherigen Lauf auf |
| **Abbrechen** | Bricht den Lauf zwischen `await`-Schritten ab |
| **Protokoll** | Log-Ausgaben des Tools, inklusive Details |
| **Fortschritt** | Fortschrittsbalken, sofern das Tool `ctx.progress` nutzt |
Ein Tool kann eigene UI mitbringen oder die Admin-Widgets verwenden. Beides sieht
bewusst wie der Admin aus; das Projekt-Theme kann über `meta.ui.css` gescopet
ergänzt werden.
## Grenzen
- Tools laufen im Browser mit der Admin-Session. Es gibt in v1 keine iframe-Sandbox.
- Ein Tool kann den Browser-Tab blockieren, wenn es synchron schwer rechnet.
Abbrechen wirkt nur zwischen `await`-Schritten.
- Gleichzeitige Änderungen sind Last-Write-Wins; das Tool muss selbst neu lesen
oder idempotent arbeiten.
- Nach einem Deployment lädt der Browser das Tool-Modul über einen Config-Hash neu.
## Für Projekt-Entwickler
Wie du Tools konfigurierst und schreibst, steht unter
[Custom Tools schreiben](/projekt/tools-schreiben/). Die UI-Referenz liegt unter
[Custom-Tool-UI](/reference/tool-ui/), der Kontext unter
[Custom-Tool-Kontext](/reference/tool-kontext/).
@@ -0,0 +1,86 @@
---
title: 'Custom Tools schreiben'
description: 'Projektspezifische Werkzeuge als ES-Module im Admin: Config, mount, ctx und Grenzen.'
---
Ein Custom Tool ist ein ES-Modul im Projekt-Repo, das der Admin als eigene Seite
lädt. Es läuft im Browser mit der Admin-Session und demselben `ctx`/`context`.
## Konfiguration
```yaml title="api/config.yml"
meta:
tools:
- name: stock-import
label: { de: Bestandsabgleich, en: Stock reconciliation }
module: _/assets/tools/stock-import/index.js
permissions: [inventory]
capabilities: [db, files, xlsx, ui]
```
`name` ist ein Slug (`[a-z0-9-_]+`). `module` wird projektrelativ aufgelöst;
`.js` ist der Default, `.mjs` optional. `permissions` steuern nur die Sichtbarkeit
in der Navigation – Datenrechte bleiben serverseitig.
## Modul
```js title="api/assets/tools/stock-import/index.js"
export const messages = {
de: { 'stock.title': 'Bestand' },
en: { 'stock.title': 'Stock' },
}
export async function mount(el, ctx) {
el.textContent = ctx.i18n.t('stock.title')
return () => el.replaceChildren()
}
```
- `mount(el, ctx)` ist Pflicht.
- Die Rückgabe ist eine optionale Cleanup-Funktion.
- `ctx === ctx.context`; beide Bindings sind dasselbe Objekt.
- Module laufen same-origin und sind vertrauenswürdig (eigenes Repo/Deploy).
## Kontext
| Feld | Inhalt |
|---|---|
| `ctx.db` | `find`, `count`, `loadAll`, `create`, `update`, `delete`, `updateMany`, `deleteMany` |
| `ctx.files` | Datei/Blob/URL → `{ src, name, type, size }` |
| `ctx.xlsx` | gebündeltes `xlsx-js-style` |
| `ctx.auth` | `{ id, username, role, permissions }` |
| `ctx.state` | `Map` pro Tool-Instanz |
| `ctx.i18n` | `t`, `text`, `has`, `add`, `extend`, `onChange` |
| `ctx.theme` | `{ mode, tokens }` read-only |
| `ctx.log`, `ctx.progress`, `ctx.signal` | Log, Fortschritt, Abbrechen |
| `ctx.project`, `ctx.tool`, `ctx.hostData` | read-only Config/Clone |
`ctx.db.update` ist Last-Write-Wins. Tools mit Read-Modify-Write müssen vor dem
Schreiben neu lesen oder idempotent arbeiten. `updateMany` bricht beim ersten
Fehler ab (`failedIndex`), ohne Rollback.
## UI
`ctx.ui.field` und `ctx.ui.form` rendern die vorhandenen Admin-Widgets. Eigene UI
läuft über DOM/Custom Elements, `ctx.ui.slot`, `ctx.ui.styles` und
`ctx.ui.registerWidget`. Details: [Tool-UI-Referenz](/reference/tool-ui/).
## Auslieferung und Deployment
Tool-Module liegen als Projekt-Assets unter `_/assets/...`. Der Browser lädt sie
per dynamischem `import()`; dabei wird **kein** Admin-Token mitgeschickt. Die
Assets müssen deshalb öffentlich lesbar sein, so wie Pagebuilder-Registries heute.
Das ist eine **Projekt-/Deployment-Eigenschaft**: Wenn ein Projekt Assets schützt,
muss die Server-Konfiguration angepasst werden, bevor Tools dort laden können.
`.js` ist der Default und wird von üblichen Servern als JavaScript ausgeliefert.
`.mjs` ist optional und braucht einen belegten JavaScript-MIME. Der Mock liefert
für beide `text/javascript`; im echten Deployment muss der MIME pro Projekt
geprüft werden.
## Grenzen
- Keine iframe-Sandbox in v1.
- Kein serverseitiges `_tools`-Rechtemodell.
- Kein Worker/Timeout; `ctx.signal` wirkt zwischen `await`-Schritten.
- `meta.ui.css` benötigt `@scope`.
@@ -0,0 +1,64 @@
---
title: 'Custom-Tool-Kontext'
description: 'ctx/context-Referenz für Custom Tools: db, files, xlsx, auth, i18n, theme und Signale.'
---
`ctx` und `context` sind dasselbe Objekt. Die folgende Tabelle beschreibt den
v1-Vertrag; Erweiterungen sind additiv.
| Feld | Signatur / Inhalt |
|---|---|
| `ctx.context` | `ctx` selbst |
| `ctx.apiVersion` | `1` |
| `ctx.uiVersion` | `1` |
| `ctx.host` | `"tool"` (später `"macro"`, `"server"`) |
| `ctx.capabilities` | deklarierte Fähigkeiten |
| `ctx.project` | read-only Projekt-Clone |
| `ctx.tool` | read-only Tool-Config |
| `ctx.auth` | `{ id, username, role, permissions } \| null` |
| `ctx.lang` | aktive Admin-Sprache |
| `ctx.languages` | Inhaltssprachen des Projekts |
| `ctx.state` | `Map<string, unknown>` pro Tool-Instanz |
| `ctx.signal` | `AbortSignal` beim Verlassen/Abbrechen |
| `ctx.hostData` | Host-Daten (ToolView: `projectId`, `toolName`) |
| `ctx.asset(spec)` | Projekt-Asset-Spezifizierer auflösen |
## `ctx.db`
```ts
find(collection, { filter?, sort?, limit?, offset?, select?, lookup? }): Promise<Record<string, any>[]>
count(collection, { filter? }): Promise<number>
loadAll(collection, opts?, onProgress?): Promise<Record<string, any>[]>
create(collection, data): Promise<Record<string, any>>
update(collection, id, data): Promise<Partial<Record<string, any>>>
delete(collection, id): Promise<void>
updateMany(collection, items): Promise<{ ok, failedIndex?, error? }>
deleteMany(collection, ids): Promise<{ ok, failedIndex?, error? }>
```
`loadAll` batcht mit 500 Datensätzen, respektiert `ctx.signal` und ruft
`onProgress(done,total)`.
## `ctx.i18n`
```ts
t(key, vars?): string
text(value, vars?): string
has(key): boolean
add(lang, messages): () => void
extend(messages, lang?): () => void
onChange(cb): () => void
```
Reihenfolge: Laufzeit → Modul → Projekt → Admin-JSON → Key. ICU/Plural wird über
`IntlMessageFormat` formatiert.
## `ctx.files`
`ctx.files.get(fileOrBlobOrUrl)` liefert `{ src, name, type?, size? }`; `src` ist
eine Data-URL. Uploads werden erst beim Speichern des Eintrags persistiert.
## `ctx.xlsx`
Das gebündelte `xlsx-js-style`-Modul. Große Arbeitsmappen blockieren den
Main-Thread; das ist in v1 dokumentiert und nicht durch einen Worker abgefedert.
+85
View File
@@ -0,0 +1,85 @@
---
title: 'Custom-Tool-UI'
description: 'Widget-Katalog, Feld-/Form-Handles, registerWidget und gescoptes Projekt-CSS.'
---
`ctx.ui` bietet Admin-Widgets und eine kleine DOM-API. Alle Widgets laufen auf
denselben Admin-Komponenten; eigene UI ist ein opt-in.
## Feld-Widgets
```js
const field = ctx.ui.field({
collection: 'editor_lab',
field: 'title',
value: 'Hallo',
onChange: (value) => console.log(value),
})
el.appendChild(field.el)
```
Typisierte Helfer: `text`, `number`, `boolean`, `select`, `date`, `richtext`,
`json`, `chips`, `file`, `files`, `foreignKey`, `foreignKeys`, `foreignFile`,
`object`, `objectArray`, `navigationTree`, `pagebuilder`.
`FieldHandle`: `el`, `update`, `destroy`, `getValue`, `setValue`, `validate`,
`flush`.
## Formulare
```js
const form = ctx.ui.form({
collection: 'editor_lab',
fields: ['title', 'score'],
value: { title: 'Formular', score: 7 },
})
```
`FormHandle` ergänzt `getValue`, `setValue`, `validate` und `flush` (wartet auf
laufende Uploads).
## Deskriptoren und Handles
```js
const field = ctx.ui.field({ collection: 'editor_lab', field: 'title' })
const page = ctx.ui.page({ title: 'Bestand', content: field })
ctx.ui.render(el, {
type: 'section',
props: { title: 'Details' },
slots: { content: [{ type: 'badge', props: { content: '3 Unterschiede' } }] },
})
```
Unbekannte Typen rendern einen sichtbaren Platzhalter; Fehler fängt die
`WidgetBoundary`.
## Eigene Deskriptor-Typen
```js
const dispose = ctx.ui.registerWidget('tool.demo.badge', ({ el, props }) => {
el.textContent = props.label
return { update: (p) => (el.textContent = p.label), destroy: () => el.replaceChildren() }
})
```
Built-ins nur mit `{ replace: true }` überschreiben. Die Registrierung endet mit
dem Tool oder über `dispose()`.
## Theme und CSS
`ctx.ui.styles` liefert Admin-Primitives plus rohe Projekt-CSS für Shadow DOM.
`meta.ui.css` wird in `@scope (.tibi-tool-<name>)` geladen; Projekt-CSS ohne
eigenen Tool-Präfix schreiben. Ohne `@scope` wird die Datei nicht geladen.
## Tabellen
```js
const table = ctx.ui.table({
collection: 'editor_lab',
rows,
columns: [{ field: 'title', label: 'Titel' }],
selection: 'multi',
onSelectionChange: (ids) => console.log(ids),
})
```