docs(tools): document custom tools and add overview screenshot
Deploy tibi-docs / build-and-deploy (push) Failing after 33s
Deploy tibi-docs / build-and-deploy (push) Failing after 33s
This commit is contained in:
1 parent
7cb57be362
commit
c22b324294
7 files changed
+295
No files matched your search
@@ -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 |
@@ -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>
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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.
|
||||||
@@ -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),
|
||||||
|
})
|
||||||
|
```
|
||||||
Reference in new issue
Block a user