Skip to content
Merged
14 changes: 14 additions & 0 deletions .changeset/27525-report-nav-index-app-shell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
'@object-ui/app-shell': minor
---

feat(console): the sidebar draws the report index only where the app's navigation declares it

Clause-②: yes (widening)
Metadata-protocol: added

The console no longer injects an "All reports" row at the foot of every app's sidebar. The app's report index (`/apps/APP/reports`) is an entry its navigation declares, a `report` item with no `reportName`, drawn and highlighted like any other entry; an app whose navigation declares none shows no index entry. With no `label`, the entry shows the console's own name for the index ("All reports"). The ⌘K palette offers the declared entry, and keeps finding every report the member may open from the reports the app ships, entry or not.

In the Studio, a `report` entry with no report chosen reads as the report index (「报表索引」 / "Report index") instead of an unbound entry, and a save keeps it. The metadata editor's navigation inspector matches it: the report picker leads with a "Report index" row, and picking it removes `reportName` from the entry rather than saving `reportName: ''`.

**Migration.** An app that relied on the injected row adds one entry to its navigation where the index belongs: `{ id: 'nav_reports', type: 'report' }`.
10 changes: 10 additions & 0 deletions .changeset/27525-report-nav-index-cli.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@objectstack/cli': minor
---

docs(cli): `os explain app` says a `report` navigation item may omit `reportName` to open the app's report index

Clause-②: yes (widening)
Metadata-protocol: added

The `navigation` row of `os explain app` now ends its `report -> reportName` target with "(omit it on a report item to open the app's report index)", the widening `@objectstack/spec` ships in this release. Only the help text changes; the command's behaviour and output shape are the same. Graded `minor` because this PR declares `Metadata-protocol: added`, which sets the floor for every package it moves.
10 changes: 10 additions & 0 deletions .changeset/27525-report-nav-index-i18n.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@object-ui/i18n': minor
---

feat(i18n): the Studio's navigation inspector names the report index face

Clause-②: yes (widening)
Metadata-protocol: added

New `studio` strings, en and zh: `engine.inspector.appNav.reportIndex` (the empty face of a `report` entry's report picker) and `engine.inspector.appNav.reportIndexHint`.
10 changes: 10 additions & 0 deletions .changeset/27525-report-nav-index-layout.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@object-ui/layout': minor
---

feat(layout): a `report` navigation entry with no `reportName` resolves to the app's report index

Clause-②: yes (widening)
Metadata-protocol: added

`resolveHref` answers `BASE/reports` for a `report` entry that names no report (it answered `#`), so the entry links, and is the active row, on the report index route. A label-less one asks the host's `NavTargetLabelResolver` for the new `{ kind: 'reportIndex' }` target, else shows its `id`.
10 changes: 10 additions & 0 deletions .changeset/27525-report-nav-index-spec.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@objectstack/spec': minor
---

feat(spec): a `report` navigation item without `reportName` opens the app's report index

Clause-②: yes (widening)
Metadata-protocol: added

`ReportNavItemSchema.reportName` is optional. `{ type: 'report', reportName }` opens that report, as before; `{ type: 'report' }` with no `reportName` opens the app's report index (`/apps/APP/reports`), the list of the reports the app ships that the member may open. Before, an item with no `reportName` was refused (`navigation.N.reportName: expected string, received undefined`). Nothing that parsed before parses differently, and the stack's cross-check of a named `reportName` against `reports` is unchanged.
10 changes: 10 additions & 0 deletions .changeset/27525-report-nav-index-types.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@object-ui/types': minor
---

docs(types): `NavigationItem.reportName` says that an omitted name opens the app's report index

Clause-②: yes (widening)
Metadata-protocol: added

The description of the mirror's optional `reportName` now states what its absence means on a `report` entry. No shape changes.
10 changes: 5 additions & 5 deletions content/docs/references/ui/app.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ const result = ActionNavItemSchema.parse(data);
| **requiresObject** | `string` | optional | Hide/disable this entry unless the named object is registered in the runtime |
| **requiresService** | `string` | optional | Hide/disable this entry unless the named kernel service is registered |
| **type** | `'report'` | ✅ | |
| **reportName** | `string` | ✅ | Target report name |
| **reportName** | `string` | optional | Target report name. Omit it and the entry opens the app's report index (the reports the app ships that the member may open) instead of one report. |

### Nested Shape: `App.navigation[number][type='action']`

Expand Down Expand Up @@ -588,7 +588,7 @@ Documentation entry on the app menu (ADR-0046). Targets a `book` and/or a `doc`
| **requiresObject** | `string` | optional | Hide/disable this entry unless the named object is registered in the runtime |
| **requiresService** | `string` | optional | Hide/disable this entry unless the named kernel service is registered |
| **type** | `'report'` | ✅ | |
| **reportName** | `string` | ✅ | Target report name |
| **reportName** | `string` | optional | Target report name. Omit it and the entry opens the app's report index (the reports the app ships that the member may open) instead of one report. |

### Nested Shape: `NavigationArea.navigation[number][type='action']`

Expand Down Expand Up @@ -787,7 +787,7 @@ A navigation contribution: a package injecting nav items into an app it does not
| **requiresObject** | `string` | optional | Hide/disable this entry unless the named object is registered in the runtime |
| **requiresService** | `string` | optional | Hide/disable this entry unless the named kernel service is registered |
| **type** | `'report'` | ✅ | |
| **reportName** | `string` | ✅ | Target report name |
| **reportName** | `string` | optional | Target report name. Omit it and the entry opens the app's report index (the reports the app ships that the member may open) instead of one report. |

### Nested Shape: `NavigationContribution.items[number][type='action']`

Expand Down Expand Up @@ -1039,7 +1039,7 @@ This schema accepts one of the following structures:
| **requiresObject** | `string` | optional | Hide/disable this entry unless the named object is registered in the runtime |
| **requiresService** | `string` | optional | Hide/disable this entry unless the named kernel service is registered |
| **type** | `'report'` | ✅ | |
| **reportName** | `string` | ✅ | Target report name |
| **reportName** | `string` | optional | Target report name. Omit it and the entry opens the app's report index (the reports the app ships that the member may open) instead of one report. |

### Nested Shape: `NavigationItem[type='report'].dataSource`

Expand Down Expand Up @@ -1294,7 +1294,7 @@ Documentation entry on the app menu (ADR-0046). Targets a `book` and/or a `doc`
| **requiresObject** | `string` | optional | Hide/disable this entry unless the named object is registered in the runtime |
| **requiresService** | `string` | optional | Hide/disable this entry unless the named kernel service is registered |
| **type** | `'report'` | ✅ | |
| **reportName** | `string` | ✅ | Target report name |
| **reportName** | `string` | optional | Target report name. Omit it and the entry opens the app's report index (the reports the app ships that the member may open) instead of one report. |

### Nested Shape: `ReportNavItem.dataSource`

Expand Down
18 changes: 17 additions & 1 deletion content/docs/ui/apps.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,21 @@ Links to a report — a `report` metadata item, named by `reportName`:
{ id: 'nav_pipeline', type: 'report', label: 'Pipeline Report', reportName: 'sales_pipeline', icon: 'file-bar-chart' }
```

Leave `reportName` out and the entry opens the app's **report index** instead
(`/apps/<app>/reports`): one page listing the reports the app ships that the
member may open, each linking to its own report. The console draws no index
entry of its own, so an app that wants one declares it, once, wherever it
belongs in the menu:

```typescript
{ id: 'nav_reports', type: 'report', icon: 'bar-chart-3' }
```

With no `label`, the entry shows the console's own name for the index
("All reports"). The ⌘K palette finds every report the member may open from the
reports the app ships, so an app does not need one entry per report to make
them searchable.

### Action Navigation

Runs an action instead of navigating to a surface. The reference lives in a
Expand Down Expand Up @@ -290,7 +305,8 @@ labelled view, else the object's or dashboard's label, else the target's machine
name. A renamed object, view or dashboard therefore shows its new name on the next
load with no navigation edit. Other entries fall back to their target's name
(`pageName`, `reportName`, the `url`) and a group to its `id`, so give those a
`label`. A `label` you write renders verbatim; never write an empty one, omit the
`label`. A report index entry (a `report` entry with no `reportName`) shows the
console's own name for the index. A `label` you write renders verbatim; never write an empty one, omit the
key instead.

## Designing the navigation
Expand Down
5 changes: 5 additions & 0 deletions content/docs/ui/reports.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,11 @@ stack does not define fails validation with `App '<app>' navigation references r
no reports at all, where the target may come from another package.) The entry resolves to
`/report/<reportName>` in the console.

A `report` entry **without** `reportName` opens the app's report index
(`/apps/<app>/reports`), which lists every report the app ships that the member may
open. The console adds no index entry by itself: declare `{ id: 'nav_reports', type:
'report' }` where the menu should carry it.

## Permissions and protection

The report schema carries exactly **one** access-shaped block, and it is not about
Expand Down
Loading
Loading