Definition einer modellgesteuerten App
Schema-ID: model-driven-app@1
Maschinenlesbares Schema: model-driven-app.schema.json
Die maßgebliche Darstellung einer modellgesteuerten App (Abschnitt 6.7) – einer benannten App, die eine ausgewählte Teilmenge der Tabellen, Dashboards und Berichte der Umgebung zu einer Navigation (Sitemap) mit einer Startseite zusammenfasst, so wie es eine modellgesteuerte App in Power Apps tut. Sie wird identisch validiert, ob sie aus dem Designer, einem API-Aufruf, einem KI-Assistenten oder einem Lösungsimport stammt.
Aufbau
| Feld | Typ | Pflicht | Hinweise |
|---|---|---|---|
logicalName | string | ja | Mit Herausgeberpräfix, Snake-Case in Kleinbuchstaben (zum Beispiel par_sales_app). |
displayName | string | ja | Lesbarer App-Name, der auf der Kachel im Startbereich angezeigt wird. |
publisherPrefix | string | ja | Das Präfix des besitzenden Herausgebers; der logische Name muss damit beginnen. |
description | string | nein | Kurzbeschreibung, die auf der Kachel im Startbereich angezeigt wird. |
icon | string | nein | Symbolschlüssel für die Kachel im Startbereich und die Kopfzeile der Navigationsleiste der App. |
supportsTasks | boolean | nein | Ob diese App an Geschäftsprozessen teilnimmt. Ist die Option aktiviert, bietet die Shell bei geöffneter App die Aufgabenliste und die Schaltfläche Entscheiden an; ist sie deaktiviert, zeichnet sie keines von beiden. Deaktiviert ist der Standard, denn die meisten Apps sind nicht Teil eines Prozesses, und ein Posteingang in einer solchen App wäre Beiwerk, in dem nie etwas steht. |
home | destination | ja | Was unter /apps/{id} geöffnet wird; muss in navigation vorkommen. Siehe unten. |
navigation | array | ja | Eine oder mehrere Navigationsgruppen (die Sitemap; siehe unten). |
includes | array | nein | Die Komponenten der App: Dinge, die sie öffnen kann, die aber nicht in ihrer Sitemap stehen. Siehe unten. |
Ziel (Destination)
Ein Ort, an den die App gehen kann – eine einzige Form, verwendet für ein Navigationselement und
für home. Das ist gewollt und kein Zufall: „Die Startseite muss ein Ort sein, zu dem die
Navigation führt“ wird so zum Vergleich zweier Werte desselben Typs statt zu drei fast
identischen Prüfungen, die Art für Art auseinanderdriften könnten.
| Feld | Typ | Pflicht | Hinweise |
|---|---|---|---|
type | Entity | Dashboard | Report | ja | Die drei Dinge, die der Player auf einen Bildschirm bringen kann: ein Raster, einen Dashboard-Host, eine Berichtsanzeige. |
target | string | ja | Der logische Name des Ziels. In welchem Speicher es existieren muss, entscheidet type. |
Navigationsgruppe
| Feld | Typ | Pflicht | Hinweise |
|---|---|---|---|
title | string | ja | Gruppenüberschrift in der linken Navigation der App. |
items | array | ja | Ein oder mehrere Navigationselemente (siehe unten). |
Navigationselement
Ein Ziel plus die Beschriftung, die diese App dafür wünscht. Die Überschreibungen für Beschriftung und Symbol gelten für jede Art – eine App, die die Tabelle „Accounts“ „Kunden“ nennt, hat denselben Grund, ein Dashboard „Heute“ zu nennen.
| Feld | Typ | Pflicht | Hinweise |
|---|---|---|---|
type | Entity | Dashboard | Report | ja | Was dieses Element öffnet. |
target | string | ja | Sein logischer Name (muss in der Umgebung als diese Art von Ding existieren). |
displayName | string | nein | Überschreibt die Beschriftung in der Navigationsleiste dieser App; fehlt sie, wird der eigene Anzeigename der Komponente verwendet. |
icon | string | nein | Symbolschlüssel für das Element in der Navigationsleiste. |
forms | array of string | nein | Nur für Tabellenelemente. Die Formulare dieser Tabelle, die diese App anbietet, per logischem Namen. Siehe unten. |
views | array of string | nein | Nur für Tabellenelemente. Die Ansichten dieser Tabelle, die diese App anbietet, per logischem Namen. |
Jedes referenzierte Ziel – in einem Navigationselement und in home – muss in der Umgebung
in dem Speicher existieren, den seine eigene Art benennt, und home muss mit einem der
Navigationselemente sowohl in type als auch in target übereinstimmen. Beides wird beim
Speichern zusätzlich zur Schemavalidierung durchgesetzt (modelapps.app.unknown_entity,
modelapps.app.unknown_dashboard, modelapps.app.unknown_report,
modelapps.app.home_not_in_navigation).
forms und views auf einem Element vom Typ Dashboard oder Report werden abgewiesen,
nicht ignoriert (modelapps.app.component_selection_not_allowed): Keines von beiden hat
Formulare oder Ansichten, eine Auswahl dort ist also ein Erstellungsfehler, der sonst
stillschweigend verschwände und seinen Urheber im Glauben ließe, er hätte etwas eingeschränkt.
Wer eines öffnen darf
Ein Dashboard zu öffnen und einen Bericht auszuführen, sind Berechtigungen auf dieser
Komponente – Berechtigungen namens <logicalName>.Open und <logicalName>.Run, die wie jede
andere von einer Sicherheitsrolle gehalten werden, mit *.Open / *.Run als Platzhaltern, die
auch alles abdecken, was als Nächstes gebaut wird. Eine Platzierung in einer Sitemap gewährt sie
nicht. Was die Widgets des Dashboards und die Datasets des Berichts dann lesen, wird ohnehin
eigenständig autorisiert; ein Benutzer, der ein Dashboard erreicht, für das er keine Daten hat,
sieht also leere Widgets statt der Zahlen eines anderen.
Komponentenauswahl – forms und views
Eine Tabelle sammelt im Laufe ihres Lebens Formulare und Ansichten an: ein Administratorformular neben dem, das ein Vertriebsmitarbeiter verwendet, eine Ansicht „Meine offenen Elemente“, die für ein Team wichtig ist. Wenn jede App jedes davon anzeigt, wird aus einer aufgeräumten Tabelle eine überladene App; deshalb darf ein Navigationselement diejenigen benennen, die seine App anbietet.
Ein fehlender Schlüssel und ein leeres Array sind nicht dasselbe, und „alles angehakt“ ist auch nicht dasselbe.
| Wert | Bedeutung |
|---|---|
| Schlüssel fehlt | Alle Formulare/Ansichten der Tabelle, einschließlich später hinzugefügter. Der Standard für eine gerade in eine App eingefügte Tabelle und die Bedeutung jeder App, die erstellt wurde, bevor es diese Option gab. |
| eine Liste | Eine abgeschlossene Auswahl. Ein Formular, das der Tabelle danach hinzugefügt wird, erscheint in dieser App nicht, bis es aufgeführt ist. |
[] | Ungültig. Es kann nicht „alle“ bedeuten (das bedeutet das Fehlen) und darf nicht „keine“ bedeuten – eine Tabelle ohne Formular lässt sich nicht öffnen. |
Jeder aufgeführte Name muss ein Formular bzw. eine Ansicht dieser Tabelle sein; das wird beim
Speichern geprüft (modelapps.app.unknown_component). Ein vertippter Name ist es wert, dass die
Speicherung fehlschlägt, statt ignoriert zu werden: Sonst würde er die App stillschweigend auf
weniger Formulare einschränken, als ihr Autor gewählt hat, und die App sähe korrekt aus, bis ein
Benutzer auf eine Tabelle stößt, die er nicht öffnen kann.
Die Liste entscheidet nur über die Zugehörigkeit, niemals über die Reihenfolge – die Laufzeit behält die eigene Reihenfolge der Tabelle und deren eigenen Standard bei, sofern dieser Standard die Auswahl überlebt. Die Ansichten einer Tabelle innerhalb einer App zu ordnen, ist eine eigene Fähigkeit und nicht diese.
Enthaltene Seite – includes
Die Navigation sagt, was eine App zeigt; includes sagt, was sie enthält, und eine App
enthält mehr, als sie zeigt. Ein Prozess öffnet ein Formular einer Tabelle, die niemand
durchsucht; ein gestalteter Befehl öffnet ein Dashboard, das bewusst nicht in der
Navigationsleiste steht; ein Bericht wird von einem Datensatz aus erreicht und nie über die
Navigation. Ohne diese Liste wäre jedes solche Ziel unerreichbar, oder jede App müsste alles
anzeigen, was sie je öffnen könnte.
| Feld | Typ | Pflicht | Hinweise |
|---|---|---|---|
type | Entity | Dashboard | Report | StudioApp | ja | Um welche Art von Ding es sich handelt. |
target | string | ja | Sein logischer Name. |
forms | array | null | nein | Nur für Tabellen. Die Formulare dieser Tabelle, die die App öffnen darf, per logischem Namen – dieselbe Regel wie bei einem Navigationselement. |
views | array | null | nein | Nur für Tabellen. Die Ansichten dieser Tabelle, die die App öffnen darf. Dieselbe Regel wie bei forms. |
forms und views folgen exakt der Regel unter Komponentenauswahl:
Fehlen bedeutet alle, eine Liste ist eine abgeschlossene Auswahl, und ein leeres Array ist
ungültig.
Beispiel
{
"logicalName": "par_sales_app",
"displayName": "Sales",
"publisherPrefix": "par",
"description": "Manage accounts and invoices",
"icon": "briefcase",
"home": { "type": "Dashboard", "target": "par_sales_overview" },
"navigation": [
{
"title": "Sales",
"items": [
{ "type": "Dashboard", "target": "par_sales_overview", "displayName": "Overview", "icon": "gauge" },
{ "type": "Entity", "target": "par_account", "displayName": "Accounts", "icon": "users" },
{
"type": "Entity",
"target": "par_invoice",
"forms": ["par_invoice_main"],
"views": ["par_invoice_active", "par_invoice_overdue"]
},
{ "type": "Entity", "target": "par_contact" },
{ "type": "Report", "target": "par_invoice_print", "displayName": "Print invoices" }
]
}
]
}
Diese App öffnet sich mit ihrem Dashboard statt mit einem Raster aus Zeilen – genau dafür ist
ein home da, das keine Tabelle ist. par_invoice ist kuratiert – die App bietet eines seiner
Formulare und zwei seiner Ansichten an, und eine Ansicht, die der Tabelle morgen hinzugefügt wird,
erscheint hier nicht. par_account und par_contact nennen keine Auswahl, also bietet die App
alles an, was diese Tabellen haben, jetzt und künftig.