@ -0,0 +1,183 @@ |
|||
```json |
|||
//[doc-seo] |
|||
{ |
|||
"Description": "Define ABP Low-Code dashboard pages, visualizations, filters, layout, permissions, and React runtime data flow." |
|||
} |
|||
``` |
|||
|
|||
# Dashboards |
|||
|
|||
Dashboards are low-code pages that render charts, lists, and number widgets from low-code entity data. A dashboard is still a page, so it uses the normal page name, title, icon, order, group, and permission model, but its page type is `dashboard` and its page definition carries a nested `dashboard` payload. |
|||
|
|||
The runtime below was generated from a low-code dashboard page definition: |
|||
|
|||
 |
|||
|
|||
## Dashboard Pages |
|||
|
|||
Dashboard pages live in the normal page descriptor collection. In source-controlled models, a dashboard page still belongs under `pages/`, not a separate dashboard folder. |
|||
|
|||
Typical page-level fields include: |
|||
|
|||
* `name` |
|||
* `title` |
|||
* `icon` |
|||
* `type: "dashboard"` |
|||
* `group` |
|||
* `order` |
|||
* `permissionConfig` |
|||
* `dashboard` |
|||
|
|||
Runtime routes use the same dynamic page convention: |
|||
|
|||
```text |
|||
/dynamic/<page-name> |
|||
``` |
|||
|
|||
## Layout Model |
|||
|
|||
The stored dashboard descriptor uses a **flat visualization list**. Each visualization defines its own placement: |
|||
|
|||
* `row`: zero-based visual row index |
|||
* `order`: order within the row |
|||
* `width`: current dashboard grid width, typically `1` or `2` |
|||
|
|||
At runtime, the React UI groups those flat visualizations into rendered rows. This is similar to form layouts: storage stays flat, rendering derives the grouped structure. |
|||
|
|||
```json |
|||
{ |
|||
"name": "sales-dashboard", |
|||
"title": "Sales Dashboard", |
|||
"type": "dashboard", |
|||
"group": "analytics", |
|||
"dashboard": { |
|||
"description": "Operational sales view", |
|||
"globalFilters": [ |
|||
{ "type": "dateRange" } |
|||
], |
|||
"visualizations": [ |
|||
{ |
|||
"name": "sales-by-status", |
|||
"type": "chart", |
|||
"title": "Sales by Status", |
|||
"row": 0, |
|||
"order": 0, |
|||
"width": 2, |
|||
"entityName": "Acme.Sales.Order", |
|||
"chart": { |
|||
"chartType": "bar", |
|||
"xAxis": { "property": "Status" }, |
|||
"yAxis": [ |
|||
{ "aggregation": "count", "label": "Orders" } |
|||
] |
|||
} |
|||
}, |
|||
{ |
|||
"name": "totals", |
|||
"type": "numberContainer", |
|||
"title": "Totals", |
|||
"row": 1, |
|||
"order": 0, |
|||
"width": 2, |
|||
"numberContainer": { |
|||
"items": [ |
|||
{ |
|||
"name": "order-count", |
|||
"title": "Order Count", |
|||
"entityName": "Acme.Sales.Order", |
|||
"aggregation": "count", |
|||
"format": "number" |
|||
} |
|||
] |
|||
} |
|||
} |
|||
] |
|||
} |
|||
} |
|||
``` |
|||
|
|||
## Visualization Types |
|||
|
|||
The current dashboard visualization types are: |
|||
|
|||
* `chart` |
|||
* `list` |
|||
* `numberContainer` |
|||
|
|||
### Chart |
|||
|
|||
Chart visualizations define: |
|||
|
|||
* `chartType`: `bar`, `line`, `pie`, or `donut` |
|||
* `xAxis` |
|||
* one or more `yAxis` aggregation series |
|||
* optional `maxItems` |
|||
* optional `showRecordCount` |
|||
* optional bar orientation |
|||
|
|||
### List |
|||
|
|||
List visualizations define: |
|||
|
|||
* `fields` |
|||
* optional `sortBy` |
|||
* `maxRows` |
|||
* `rowHeight` |
|||
* optional `colorBy` |
|||
|
|||
### Number Container |
|||
|
|||
Number containers hold one or more number items. Each item can define: |
|||
|
|||
* `aggregation` |
|||
* `aggregationProperty` |
|||
* `format` |
|||
* `color` |
|||
* entity-specific filters and global date filter linkage |
|||
* click-through behavior |
|||
|
|||
## Filters and Interactivity |
|||
|
|||
Dashboards support three filter layers: |
|||
|
|||
* `globalFilters` for page-level controls such as date range |
|||
* visualization-level `filter` for fixed query constraints |
|||
* visualization `userFilters` for interactive filtering exposed to the runtime user |
|||
|
|||
Other useful dashboard interaction fields include: |
|||
|
|||
* `globalDateFilterProperty` |
|||
* `showDescriptionAsTooltip` |
|||
* `clickToSeeRecords` |
|||
|
|||
These options let a dashboard stay compact while still allowing drill-down behavior in the runtime. |
|||
|
|||
## Runtime Shape |
|||
|
|||
The runtime definition exposed to React is grouped by rows and items, even though the stored descriptor is flat. The React runtime uses: |
|||
|
|||
* `useDashboardDefinition` |
|||
* `useDashboardData` |
|||
* `GET /api/low-code/ui/dashboards/{pageName}` |
|||
* `POST /api/low-code/dashboards/{pageName}/data` |
|||
|
|||
See [React Runtime](react-runtime.md) for hook-level details and route integration. |
|||
|
|||
## Permissions and Menu Placement |
|||
|
|||
Dashboard pages are read-oriented. Generated dashboard page operations are **view only**, so the usual CRUD operation set does not apply. |
|||
|
|||
Dashboard pages can still: |
|||
|
|||
* appear inside a [Page Group](page-groups.md) |
|||
* carry a menu icon and order |
|||
* use explicit or generated page permission configuration |
|||
|
|||
Menu placement is handled at the page level through the normal `group` and `order` fields. |
|||
|
|||
## See Also |
|||
|
|||
* [React Runtime](react-runtime.md) |
|||
* [Low-Code Designer](designer.md) |
|||
* [Page Groups](page-groups.md) |
|||
* [Model Descriptor Files](model-json.md) |
|||
@ -0,0 +1,83 @@ |
|||
```json |
|||
//[doc-seo] |
|||
{ |
|||
"Description": "Review the ABP Low-Code model health snapshot to inspect entities, pages, forms, page groups, permissions, and script assets before publishing runtime changes." |
|||
} |
|||
``` |
|||
|
|||
# Health |
|||
|
|||
The **Health** section in the Low-Code Designer is a selected-layer readiness view. It helps you review the resolved low-code model for the currently selected layer before publishing changes or relying on the generated runtime pages. |
|||
|
|||
Health works on the **resolved view of the selected layer**, not on raw JSON files. In practice, this means it shows the selected layer after lower-layer inheritance and descriptor materialization have been applied. It does not silently merge unrelated edits from another layer. To review runtime-only overrides, switch the Designer to **Runtime JSON** or use the runtime-focused [MCP Integration](mcp.md) workflow. |
|||
|
|||
## What Health Reads |
|||
|
|||
The health snapshot is a combined view of the current low-code model in the selected layer. It includes: |
|||
|
|||
* Entities |
|||
* Enums |
|||
* Page groups |
|||
* Pages |
|||
* Forms |
|||
* Custom permissions |
|||
* Effective page permission configuration |
|||
* Custom endpoints |
|||
* Script event handlers |
|||
* Script background jobs |
|||
* Script background workers |
|||
|
|||
This makes Health the best place to review cross-descriptor relationships instead of checking each designer tab in isolation. |
|||
|
|||
## What It Helps You Catch |
|||
|
|||
Health is most useful for selected-layer consistency problems that often appear only after several descriptors start referencing each other. |
|||
|
|||
Typical problem classes include: |
|||
|
|||
* Page to form mismatches, where a page references a form that does not exist or belongs to another entity |
|||
* Page-type configuration errors, such as a kanban page missing `groupByProperty`, a calendar page using invalid date or time fields, or a gallery page pointing to a non-image property |
|||
* Page-group structure problems such as missing parents, circular references, or nesting deeper than the supported depth |
|||
* Form layout issues where fields exist but valid placements do not |
|||
* Permission and page configuration mismatches that would affect runtime visibility or access |
|||
* Script assets that exist in the model but still need review in the broader context of entities, pages, and permissions |
|||
|
|||
Some of these issues are also enforced by runtime validation and mutation rules. Health gives you a selected-layer review point before users discover the problem in the runtime UI. |
|||
|
|||
## Use It When |
|||
|
|||
Use Health in these moments: |
|||
|
|||
* After changing entities, pages, forms, page groups, or permissions in the Designer |
|||
* After applying MCP-driven runtime mutations |
|||
* Before publishing a set of runtime changes |
|||
* After copying or importing source-controlled descriptors into an application |
|||
|
|||
If you automate low-code changes through [MCP Integration](mcp.md), re-read the health snapshot after apply and treat that review as part of the success criteria. |
|||
|
|||
## Health and Source-Controlled Models |
|||
|
|||
Health is not a replacement for source-controlled file validation. |
|||
|
|||
When you edit `_Dynamic/model/**/*.json` directly: |
|||
|
|||
1. Run the generated model file checker: |
|||
|
|||
```bash |
|||
dotnet run --project <startup-project> -- --check-lowcode-model-files |
|||
``` |
|||
|
|||
2. Run the required migration workflow for schema-affecting entity changes. |
|||
3. Open the Designer and review **Health** after the model has loaded successfully. |
|||
|
|||
The file checker catches JSON and category-level problems. Health complements it by helping you inspect the resolved model after descriptors, references, permissions, pages, and forms are all combined. |
|||
|
|||
A useful example is form layout drift: a descriptor can still pass `--check-lowcode-model-files` while a source-controlled form renders with no visible fields because its layout placements are stale. Health and runtime preview are the places to catch that class of issue. |
|||
|
|||
## See Also |
|||
|
|||
* [Low-Code Designer](designer.md) |
|||
* [MCP Integration](mcp.md) |
|||
* [Model Descriptor Files](model-json.md) |
|||
* [Dashboards](dashboards.md) |
|||
* [Page Groups](page-groups.md) |
|||
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 123 KiB |
@ -0,0 +1,126 @@ |
|||
```json |
|||
//[doc-seo] |
|||
{ |
|||
"Description": "Use the ABP Low-Code Designer MCP integration to inspect, validate, and apply structured runtime mutations to the database-backed low-code model." |
|||
} |
|||
``` |
|||
|
|||
# MCP Integration |
|||
|
|||
> **Preview:** The low-code MCP surface is part of the preview Low-Code System. Tool names, mutation metadata, and validation advice may change before general availability. |
|||
|
|||
The low-code designer exposes a Model Context Protocol (MCP) surface for automation. It is intended for agents and scripted tooling that need to inspect or mutate the same **runtime database-backed** model that the Designer edits in the **Runtime JSON** layer. |
|||
|
|||
## Scope |
|||
|
|||
The MCP surface is **runtime-only**: |
|||
|
|||
* It always works against the database-backed runtime model. |
|||
* It does not choose between layers at call time. |
|||
* It is not the right surface for source-controlled `_Dynamic/model/**/*.json` files. |
|||
|
|||
Use [Model Descriptor Files](model-json.md) when you need source-controlled descriptors. Use MCP when an agent or automation needs safe, structured changes to the runtime model that the Designer can immediately show. |
|||
|
|||
## Mental Model |
|||
|
|||
MCP is not a raw JSON document editor. It is a semantic mutation layer over low-code concepts such as: |
|||
|
|||
* Entities and properties |
|||
* Pages, page groups, and dashboards |
|||
* Forms and form layout |
|||
* Permissions |
|||
* Custom endpoints and script actions |
|||
|
|||
The MCP surface includes read/query capabilities, mutation metadata, dry-run validation, a single mutation apply path, and a health snapshot. The normal workflow is: |
|||
|
|||
1. Read the current runtime model state for the item you want to change. |
|||
2. Fetch the latest mutation metadata and keep its `concurrencyStamp`. |
|||
3. Build a small ordered mutation batch that touches only the changed paths. |
|||
4. Dry-run the batch with validation. |
|||
5. Apply the batch. |
|||
6. Re-read the changed item and review [Health](health.md). |
|||
|
|||
## Concurrency and Validation |
|||
|
|||
Every runtime write depends on the latest `concurrencyStamp`. If another write changes the runtime model first, your apply attempt becomes stale and must be rebuilt from the refreshed model state. |
|||
|
|||
Validation happens before apply and returns structured feedback instead of requiring a client to guess from generic failures. The validation layer checks: |
|||
|
|||
* Stale concurrency stamps |
|||
* Target path syntax |
|||
* Missing required input such as `data` or move destinations |
|||
* Primitive-only `Set` data |
|||
* Final descriptor shape after the batch is simulated |
|||
* Entity property type and foreign key rules |
|||
* Form layout consistency |
|||
* Dashboard layout consistency |
|||
* Runtime override rules for descriptors inherited from lower layers |
|||
|
|||
Treat validation as part of the normal write flow, not as an optional extra. |
|||
|
|||
## Mutation Model |
|||
|
|||
Runtime writes are intentionally narrow: |
|||
|
|||
* `Add` creates a keyed descriptor or collection member. |
|||
* `Set` changes a scalar value or a supported primitive list. |
|||
* `Remove` deletes the semantic target. |
|||
* `Move` relocates an existing node without resending the whole object. |
|||
|
|||
Important behavior: |
|||
|
|||
* `Set` data must stay primitive: string, number, boolean, `null`, or a supported primitive string list. |
|||
* Do not replace whole descriptor trees when only one field changed. |
|||
* Keep batches small and semantic. Send changed paths, not full model payloads. |
|||
* If a mapped entity or property is removed with drop behavior, the runtime model can also remove the physical table or column in the runtime layer. |
|||
|
|||
## Runtime Override and Schema Rules |
|||
|
|||
Runtime MCP writes can extend descriptors that originate from lower layers, but they do not have unlimited control over inherited schema. |
|||
|
|||
For entity properties inherited from a lower layer, runtime edits are intentionally restricted. Typical runtime-safe changes are display labels and runtime-owned validators. Inherited storage details such as type, database mapping, default value, required or unique behavior, foreign key settings, and file or image storage options remain immutable in runtime. |
|||
|
|||
This separation matches the low-code layer model: |
|||
|
|||
* Runtime database-backed changes use **direct** schema mutation. |
|||
* Source-controlled JSON layer changes use the normal **migration** workflow. |
|||
|
|||
If you are working in `_Dynamic/model`, MCP is the wrong tool. Use the source-controlled descriptor flow and migrations instead. |
|||
|
|||
## Layout and Type Conventions |
|||
|
|||
Several conventions matter when MCP clients generate mutations: |
|||
|
|||
* Use canonical lowercase entity property types: `string`, `int`, `long`, `decimal`, `datetime`, `boolean`, `guid`, `enum`, `date`, `time`, `file`, `image`, `money`. |
|||
* Use canonical lowercase form field types: `text`, `textarea`, `number`, `checkbox`, `date`, `datetime`, `select`, `lookup`, `guid`, `computed`, `time`, `file`, `image`, `money`. |
|||
* Form layout is flat and id-keyed under `layout.tabs[].groups[].fields[]`. Each placement carries `row`, `colSpan`, and optional `colStart`. |
|||
* Dashboard layout is flat and name-keyed under `dashboard.visualizations[]`. Each visualization carries `row`, `order`, and `width`. |
|||
* Page and page-group icons are CSS class strings, not URLs or image file paths. |
|||
* For foreign access, `foreignKey.access` values are `none`, `view`, or `edit`. |
|||
|
|||
These rules matter because validation and runtime rendering assume them. For example, a form can define fields correctly but still render an empty group if no valid placements point to those field IDs. |
|||
|
|||
## Designer and MCP Together |
|||
|
|||
Use the Designer when you want: |
|||
|
|||
* Interactive editing |
|||
* Visual context for entities, pages, forms, and permissions |
|||
* Manual review before publishing |
|||
|
|||
Use MCP when you want: |
|||
|
|||
* Agent-driven or scripted changes |
|||
* Repeatable runtime mutation workflows |
|||
* Structured validation before write |
|||
* Safe, incremental edits instead of raw JSON replacement |
|||
|
|||
The two surfaces are complementary. A common workflow is to inspect or prototype in the Designer, automate a repeatable mutation flow through MCP, then reopen the Designer and [Health](health.md) to confirm the result. |
|||
|
|||
## See Also |
|||
|
|||
* [Low-Code Designer](designer.md) |
|||
* [Health](health.md) |
|||
* [Dashboards](dashboards.md) |
|||
* [Page Groups](page-groups.md) |
|||
* [Model Descriptor Files](model-json.md) |
|||
@ -0,0 +1,123 @@ |
|||
```json |
|||
//[doc-seo] |
|||
{ |
|||
"Description": "Define ABP Low-Code page groups to organize runtime pages into dynamic menu folders with ordering, icons, and nesting." |
|||
} |
|||
``` |
|||
|
|||
# Page Groups |
|||
|
|||
Page groups are dynamic menu folders used by low-code pages. They let you organize runtime pages into nested navigation structures without hardcoding menu items in the frontend. |
|||
|
|||
## What a Page Group Stores |
|||
|
|||
A page group descriptor stores: |
|||
|
|||
| Field | Description | |
|||
|-------|-------------| |
|||
| `name` | Stable identifier used by pages in their `group` field | |
|||
| `title` | Display label shown in the runtime menu | |
|||
| `icon` | CSS class string for the menu icon | |
|||
| `order` | Sort order among sibling groups | |
|||
| `parent` | Optional parent group name for nesting | |
|||
|
|||
If a group does not define an icon, the runtime menu uses a folder-style default icon. |
|||
|
|||
## How Pages Use Groups |
|||
|
|||
Pages reference a group by name: |
|||
|
|||
```json |
|||
{ |
|||
"name": "orders", |
|||
"title": "Orders", |
|||
"type": "dataGrid", |
|||
"entityName": "Acme.Sales.Order", |
|||
"group": "sales" |
|||
} |
|||
``` |
|||
|
|||
If `group` is omitted, the page becomes a top-level runtime menu item. |
|||
|
|||
A group is only a container. It does not define page data, routes, or entity behavior by itself. |
|||
|
|||
## Nesting Rules |
|||
|
|||
Groups can nest by pointing `parent` to another page group name. |
|||
|
|||
Important constraints: |
|||
|
|||
* Group nesting cannot be circular. |
|||
* Maximum depth is `3` levels. |
|||
* Root groups are groups whose `parent` is empty. |
|||
|
|||
This keeps runtime navigation predictable and avoids unbounded nesting in the generated menu. |
|||
|
|||
## Visibility and Permissions |
|||
|
|||
Page groups do not replace page permissions. Runtime visibility still depends on the pages inside the group. |
|||
|
|||
In practice: |
|||
|
|||
* Pages are added to the runtime menu only if the current user can access them. |
|||
* Groups are containers for those visible pages. |
|||
* Groups without visible page descendants are omitted from the runtime root menu. |
|||
|
|||
This means page permissions remain the real security boundary, while page groups control menu organization. |
|||
|
|||
## Split Descriptor Example |
|||
|
|||
In split descriptor projects, a page group file in `pageGroups/` stores **one descriptor object**, not a wrapper document: |
|||
|
|||
```json |
|||
{ |
|||
"name": "sales-reports", |
|||
"title": "Reports", |
|||
"icon": "fa-solid fa-folder-tree", |
|||
"order": 20, |
|||
"parent": "sales" |
|||
} |
|||
``` |
|||
|
|||
For example, `pageGroups/sales-reports.json` would use that shape directly. |
|||
|
|||
If you are looking at the logical aggregate model instead of split files, the same data appears under the top-level `pageGroups` array: |
|||
|
|||
```json |
|||
{ |
|||
"pageGroups": [ |
|||
{ |
|||
"name": "sales", |
|||
"title": "Sales", |
|||
"icon": "fa-solid fa-chart-line", |
|||
"order": 10 |
|||
}, |
|||
{ |
|||
"name": "sales-reports", |
|||
"title": "Reports", |
|||
"icon": "fa-solid fa-folder-tree", |
|||
"order": 20, |
|||
"parent": "sales" |
|||
} |
|||
] |
|||
} |
|||
``` |
|||
|
|||
In split descriptor projects, page groups belong to the `pageGroups/` descriptor category. |
|||
|
|||
## Icon Guidance |
|||
|
|||
Use CSS class strings for icons, for example: |
|||
|
|||
* `fa-solid fa-folder` |
|||
* `fa-solid fa-folder-tree` |
|||
* `fa-solid fa-chart-line` |
|||
|
|||
Do not treat `icon` as an image URL or file path. |
|||
|
|||
## See Also |
|||
|
|||
* [Dashboards](dashboards.md) |
|||
* [React Runtime](react-runtime.md) |
|||
* [Low-Code Designer](designer.md) |
|||
* [Model Descriptor Files](model-json.md) |
|||