@object-ui/layout 17.2.0 → 17.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +197 -0
- package/dist/AppSchemaRenderer.d.ts +3 -1
- package/dist/NavigationRenderer.d.ts +40 -0
- package/dist/index.js +289 -271
- package/dist/index.umd.cjs +1 -1
- package/package.json +10 -10
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,202 @@
|
|
|
1
1
|
# @object-ui/layout
|
|
2
2
|
|
|
3
|
+
## 17.3.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 608669e: `AppSchemaRenderer` now derives area visibility from the items inside the
|
|
8
|
+
area, closing the visible-but-empty regression the spec 17.0.0 area-key
|
|
9
|
+
retirement left behind (objectui#3311, option C of the recorded ruling).
|
|
10
|
+
|
|
11
|
+
Spec 17.0.0 retired the authorable area-level `visible` /
|
|
12
|
+
`requiredPermissions` (`AREA_VISIBLE_RETIRED` /
|
|
13
|
+
`AREA_REQUIRED_PERMISSIONS_RETIRED`) — an area is a layout grouping, not an
|
|
14
|
+
access boundary — and objectui followed in #3315 by deleting the area
|
|
15
|
+
switcher's filter. Correct on the contract, but it changed the navigation
|
|
16
|
+
surface: an area whose items are **all** gated away used to disappear from
|
|
17
|
+
the switcher and instead rendered as a selectable, empty area.
|
|
18
|
+
|
|
19
|
+
## What changed
|
|
20
|
+
- **Area visibility is now derived, not authored.** An area appears in the
|
|
21
|
+
switcher iff at least one of its navigation items survives the exact
|
|
22
|
+
item-level guards `NavigationRenderer` applies: the `visible` expression,
|
|
23
|
+
`requiredPermissions`, the `requiresObject` / `requiresService` runtime
|
|
24
|
+
capability gates, and — for `action` items — the presence of an `onAction`
|
|
25
|
+
dispatcher (framework#4509: without one they are not rendered, so they
|
|
26
|
+
cannot carry an area either). Separators never count; a `group` counts only
|
|
27
|
+
through its children.
|
|
28
|
+
- **The active area is elected among visible areas only.** A fully gated
|
|
29
|
+
first area is no longer auto-activated, and when a gating change hides the
|
|
30
|
+
currently active area the shell re-elects the first visible one. A gating
|
|
31
|
+
change that merely _reveals_ an area never yanks the user away from where
|
|
32
|
+
they are.
|
|
33
|
+
- **An area with no items at all derives the same way**: no visible item →
|
|
34
|
+
hidden. (Boundary recorded in objectui#3311.)
|
|
35
|
+
- New export `hasVisibleNavigationItems(items, options)` from
|
|
36
|
+
`@object-ui/layout` — the predicate behind the derivation, usable by other
|
|
37
|
+
shells that render their own area switchers.
|
|
38
|
+
|
|
39
|
+
No authorable key is involved anywhere: the platform's `.strict()` area
|
|
40
|
+
object still rejects the retired keys, and the derivation — computed from the
|
|
41
|
+
same guards that decide what renders — cannot disagree with the rendered
|
|
42
|
+
navigation, so there is nothing for a metadata author to get wrong.
|
|
43
|
+
|
|
44
|
+
- d22ae31: Track `@objectstack/spec` 17.0.0-rc.2 (objectui#3235, #3208, #3287, #3264).
|
|
45
|
+
|
|
46
|
+
The pin moves from `^17.0.0-rc.1` to `^17.0.0-rc.2` across the workspace, and
|
|
47
|
+
the sibling `@objectstack/*` packages (`client` / `core` / `formula` / `lint`)
|
|
48
|
+
move with it — they pin `@objectstack/spec` **exactly**, so leaving them behind
|
|
49
|
+
kept a second copy of the spec in the tree and would have had `@objectstack/lint`
|
|
50
|
+
validating against rc.1 schemas that still accept keys rc.2 retires.
|
|
51
|
+
|
|
52
|
+
Breaking semantics, in FROM → TO form:
|
|
53
|
+
|
|
54
|
+
- **`app.homePageId` is retired — an app's landing page is now its first
|
|
55
|
+
navigation item.** An app that pinned a landing page with `homePageId` will
|
|
56
|
+
open on the first reachable navigation entry (by `order`) instead; the root
|
|
57
|
+
landing still follows `isDefault`. To restore a specific landing page, reorder
|
|
58
|
+
`navigation` so the intended entry comes first. Stored metadata is migrated by
|
|
59
|
+
`os migrate meta --from 16`. The key is a hard error now, not a stripped one:
|
|
60
|
+
the spec ships a tombstone that names the migration.
|
|
61
|
+
Upstream retired it because of its SHAPE, not its usage — it was an ID
|
|
62
|
+
cross-reference with no referential integrity, so a `homePageId` that pointed
|
|
63
|
+
at nothing silently fell back to the first navigation item anyway
|
|
64
|
+
(objectstack#4667, premise corrected in #4709). If the capability returns, it
|
|
65
|
+
returns as a flag on the navigation item itself, which cannot dangle.
|
|
66
|
+
- **`@object-ui/types`' `HttpMethod` now resolves to the spec's
|
|
67
|
+
`HttpMethodType`.** Shape is verbatim identical — the same 5-value UI subset —
|
|
68
|
+
and `@object-ui/types` still exports it as `HttpMethod`, so no consumer
|
|
69
|
+
changes. The spec renamed its `./ui` export because `HttpMethod` named two
|
|
70
|
+
different types depending on the import path (`./shared` / `./api` carry a
|
|
71
|
+
7-value enum including `HEAD` / `OPTIONS`); objectui deliberately keeps the
|
|
72
|
+
5-value one (objectstack#4691).
|
|
73
|
+
- **`AppContextSelector.includeAll` / `placement` are gone.** Neither ever did
|
|
74
|
+
anything in this renderer: context selectors are mandatory-scope, so no "All"
|
|
75
|
+
row was ever rendered, and `placement: 'topbar'` put nothing in the topbar.
|
|
76
|
+
Both carried schema defaults, which is why the liveness lint structurally
|
|
77
|
+
could not flag them — removal was the only channel that reaches an author
|
|
78
|
+
(framework#4509).
|
|
79
|
+
- **`NavigationArea.visible` / `order` / `requiredPermissions` are gone.** An
|
|
80
|
+
area is a layout grouping, not an access boundary. Gating moved down to the
|
|
81
|
+
navigation ITEM, where `visible` and `requiredPermissions` are unchanged and
|
|
82
|
+
still enforced. `AppSchemaRenderer`'s area switcher no longer hides an area, so
|
|
83
|
+
an area whose items are all gated away renders as visible-but-empty rather
|
|
84
|
+
than disappearing.
|
|
85
|
+
- **`@object-ui/core` no longer exports `NotificationProtocol`**
|
|
86
|
+
(`resolveNotificationConfig`, `specNotificationToToast`, `mapSeverityToVariant`,
|
|
87
|
+
`mapPosition`, `ToastNotification`). It bridged `@objectstack/spec/ui`'s
|
|
88
|
+
`Notification` / `NotificationConfig`, which objectstack#4610 deleted with no
|
|
89
|
+
successor. Use `resolveNotificationConfig` from `@object-ui/react`
|
|
90
|
+
(`NotificationContext`), which owns the live `NotificationSystemConfig` and is
|
|
91
|
+
what every notification surface already read. Note that the spec's _other_
|
|
92
|
+
`Notification` — `@objectstack/spec/api` — is the REST inbox row, a different
|
|
93
|
+
contract, and is deliberately NOT aliased in as a replacement.
|
|
94
|
+
- **The `email_template` client-side validator now uses
|
|
95
|
+
`EmailTemplateDefinitionSchema`.** It was pointing at the removed
|
|
96
|
+
`EmailTemplateSchema`, so authored templates were being checked against the
|
|
97
|
+
wrong contract: the live one is keyed `name` + `locale` (not `id`) and splits
|
|
98
|
+
the body into `bodyHtml` / `bodyText` (not `body` + `bodyType`)
|
|
99
|
+
(objectstack#4616 / #4807).
|
|
100
|
+
|
|
101
|
+
Fixes that are not breaking, but were only found because rc.2 stopped being
|
|
102
|
+
lenient — each had been passing vacuously:
|
|
103
|
+
|
|
104
|
+
- **`view` drafts are actually validated now.** The client validator named the
|
|
105
|
+
aggregated container schema while this admin authors first-class `ViewItem`s,
|
|
106
|
+
and the container used to strip `viewKind` / `config` in silence — so no view
|
|
107
|
+
draft ever had one of its own keys checked. It now validates each shape
|
|
108
|
+
against its own schema (objectui#3312).
|
|
109
|
+
- **The console's worked examples were wrong**, and being stripped rather than
|
|
110
|
+
refused: `view.list.object` (the container root already declares it),
|
|
111
|
+
`job.concurrency` / `job.timeoutMs` (no such keys; the spelling is `timeout`,
|
|
112
|
+
already in ms), `email_template.from` / `.to` (a template is not a send —
|
|
113
|
+
the sender override is `fromOverride`, an object), and
|
|
114
|
+
`datasource.capabilities` / `.healthCheck` (objectstack#4583 removed the
|
|
115
|
+
former; the latter was never a datasource key). These are the drafts an
|
|
116
|
+
author — or a model generating metadata — copies.
|
|
117
|
+
- Action key inventory re-derived: `ActionSchema` gained the package-lock
|
|
118
|
+
envelope (`_lock*` / `_package*` / `_provenance`), so a packaged action no
|
|
119
|
+
longer reports them as unknown keys.
|
|
120
|
+
- The schema-diff panel labels the new `default_mismatch` finding.
|
|
121
|
+
- Test fixtures pinning the retired `managedBy: 'system'` bucket now use
|
|
122
|
+
`engine-owned`. Protocol 17 split that value (objectstack#3355), so it
|
|
123
|
+
resolved to the default-writable fallback and a batch of "stays locked"
|
|
124
|
+
assertions had quietly stopped asserting anything.
|
|
125
|
+
|
|
126
|
+
### Patch Changes
|
|
127
|
+
|
|
128
|
+
- d2363e7: The legacy `page-header` alias stops advertising `description` as an authorable
|
|
129
|
+
key (objectui#3226).
|
|
130
|
+
|
|
131
|
+
FROM: `registerLayout()` declared `inputs: [title, description]`. TO:
|
|
132
|
+
`inputs: [title, subtitle]` — the key `@objectstack/spec/ui`'s `PageHeaderProps`
|
|
133
|
+
declares, and the one the canonical `page:header` renderer in
|
|
134
|
+
`@object-ui/components` already declares.
|
|
135
|
+
|
|
136
|
+
`inputs` is a DECLARATION surface, not documentation: the designer builds its
|
|
137
|
+
property palette from it, and the framework's `check:react-declaration-parity`
|
|
138
|
+
diffs it against the spec schemas. Declaring `description` therefore did not
|
|
139
|
+
merely tolerate a legacy spelling — it published a second dialect for the one
|
|
140
|
+
concept the protocol calls `subtitle`, and told authors (an AI author most
|
|
141
|
+
readily, since the registry is what it reads to learn the shape) that the
|
|
142
|
+
non-spec key was legal. Metadata that took the offer renders a subtitle under
|
|
143
|
+
`page-header` and silently loses it under `page:header`: same JSON, two results,
|
|
144
|
+
which is the outcome a single contract exists to prevent.
|
|
145
|
+
|
|
146
|
+
No runtime behaviour changes. `PageHeader` still reads `subtitle ?? description`,
|
|
147
|
+
deliberately: this alias exists for out-of-repo consumer schemas, so "no in-repo
|
|
148
|
+
author writes `description`" (verified — zero hits) is not evidence that nobody
|
|
149
|
+
does, and dropping the read today would delete an external page's second line
|
|
150
|
+
while its title kept rendering, the least reportable failure mode there is. That
|
|
151
|
+
read is retired together with an ADR-0087 D2 conversion entry
|
|
152
|
+
(`page-header-subtitle-alias`, `description` → `subtitle` rewritten at load
|
|
153
|
+
time), which lives in the framework repo and is tracked separately. Narrowing the
|
|
154
|
+
declaration did not need to wait on it and breaks no consumer; leaving the
|
|
155
|
+
declaration wrong in the meantime keeps minting the metadata the conversion would
|
|
156
|
+
then have to absorb.
|
|
157
|
+
|
|
158
|
+
New tests pin both halves so neither can drift back: the registration may not
|
|
159
|
+
declare `description`, must declare `subtitle`, and — checked against the spec's
|
|
160
|
+
own shape rather than a hand-written allowlist — may declare nothing
|
|
161
|
+
`@objectstack/spec` does not; while the runtime fallback is pinned as a sequencing
|
|
162
|
+
guard, to be deleted in the same change that lands the conversion entry.
|
|
163
|
+
|
|
164
|
+
- Updated dependencies [18cd432]
|
|
165
|
+
- Updated dependencies [532cf8b]
|
|
166
|
+
- Updated dependencies [680080a]
|
|
167
|
+
- Updated dependencies [a7651e6]
|
|
168
|
+
- Updated dependencies [d915c47]
|
|
169
|
+
- Updated dependencies [b71fc92]
|
|
170
|
+
- Updated dependencies [34595eb]
|
|
171
|
+
- Updated dependencies [3889ffb]
|
|
172
|
+
- Updated dependencies [5781fb1]
|
|
173
|
+
- Updated dependencies [9e9e9a9]
|
|
174
|
+
- Updated dependencies [56409c2]
|
|
175
|
+
- Updated dependencies [042e09d]
|
|
176
|
+
- Updated dependencies [9cbcbf4]
|
|
177
|
+
- Updated dependencies [85c4c9c]
|
|
178
|
+
- Updated dependencies [fd54c3e]
|
|
179
|
+
- Updated dependencies [4eeb932]
|
|
180
|
+
- Updated dependencies [23018cc]
|
|
181
|
+
- Updated dependencies [53811d1]
|
|
182
|
+
- Updated dependencies [d915c47]
|
|
183
|
+
- Updated dependencies [f44d872]
|
|
184
|
+
- Updated dependencies [509104a]
|
|
185
|
+
- Updated dependencies [825bbe3]
|
|
186
|
+
- Updated dependencies [5dd0127]
|
|
187
|
+
- Updated dependencies [06632e9]
|
|
188
|
+
- Updated dependencies [a4cff5b]
|
|
189
|
+
- Updated dependencies [175bd79]
|
|
190
|
+
- Updated dependencies [f833d3a]
|
|
191
|
+
- Updated dependencies [2a9513d]
|
|
192
|
+
- Updated dependencies [71be406]
|
|
193
|
+
- Updated dependencies [d22ae31]
|
|
194
|
+
- Updated dependencies [8d8094a]
|
|
195
|
+
- @object-ui/core@17.3.0
|
|
196
|
+
- @object-ui/components@17.3.0
|
|
197
|
+
- @object-ui/types@17.3.0
|
|
198
|
+
- @object-ui/react@17.3.0
|
|
199
|
+
|
|
3
200
|
## 17.2.0
|
|
4
201
|
|
|
5
202
|
### Minor Changes
|
|
@@ -49,7 +49,9 @@ export interface AppSchemaRendererProps {
|
|
|
49
49
|
* Responsibilities:
|
|
50
50
|
* - Reads `name`, `title`, `description`, `logo`, `favicon` for branding
|
|
51
51
|
* - Renders sidebar navigation from `navigation` or `areas[].navigation`
|
|
52
|
-
* - Area switcher when multiple
|
|
52
|
+
* - Area switcher when multiple areas are VISIBLE — area visibility is
|
|
53
|
+
* derived from the items inside, not authored (objectui#3311): an area
|
|
54
|
+
* whose items are all gated away is hidden and never auto-activated
|
|
53
55
|
* - Mobile modes: `drawer` (sheet overlay, default), `bottom_nav` (fixed
|
|
54
56
|
* bottom bar), `hamburger` (collapsed sidebar)
|
|
55
57
|
* - Evaluates `visible` expressions and `requiredPermissions` on every item
|
|
@@ -149,6 +149,46 @@ export declare function resolveLabel(label: string | {
|
|
|
149
149
|
defaultValue?: string;
|
|
150
150
|
params?: Record<string, any>;
|
|
151
151
|
}, t?: (key: string, options?: any) => string): string;
|
|
152
|
+
/** Guard callbacks for {@link hasVisibleNavigationItems}. */
|
|
153
|
+
export interface NavigationVisibilityOptions {
|
|
154
|
+
/** Evaluator for item `visible` expressions. Defaults to always-visible. */
|
|
155
|
+
evaluateVisibility?: VisibilityEvaluator;
|
|
156
|
+
/** Checker for item `requiredPermissions`. Defaults to always-permitted. */
|
|
157
|
+
checkPermission?: PermissionChecker;
|
|
158
|
+
/** Checker for `requiresObject` / `requiresService`. Defaults to pass. */
|
|
159
|
+
checkCapability?: CapabilityChecker;
|
|
160
|
+
/**
|
|
161
|
+
* Whether the host wires an `onAction` dispatcher. Without one, `action`
|
|
162
|
+
* items are not rendered at all (framework#4509 — a nav entry that looks
|
|
163
|
+
* clickable and silently does nothing is worse than an absent one), so
|
|
164
|
+
* they cannot carry an area's visibility either. Defaults to `false`,
|
|
165
|
+
* matching a renderer with no `onAction` prop.
|
|
166
|
+
*/
|
|
167
|
+
hasActionHandler?: boolean;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Whether a navigation tree contains at least one item that would actually
|
|
171
|
+
* render under the given guards — the exact guards `NavigationItemRenderer`
|
|
172
|
+
* applies per item: the `visible` expression, `requiredPermissions`, the
|
|
173
|
+
* `requiresObject` / `requiresService` runtime-capability gates, and (for
|
|
174
|
+
* `action` items) the presence of an action dispatcher.
|
|
175
|
+
*
|
|
176
|
+
* Non-content nodes never count: a `separator` is a visual divider, and a
|
|
177
|
+
* `group` counts only through its children — a group whose children are all
|
|
178
|
+
* gated away contributes nothing a user can navigate to.
|
|
179
|
+
*
|
|
180
|
+
* This is the predicate behind DERIVED area visibility (objectui#3311).
|
|
181
|
+
* `@objectstack/spec` 17.0.0 retired the authorable area-level `visible` /
|
|
182
|
+
* `requiredPermissions` (`AREA_VISIBLE_RETIRED` /
|
|
183
|
+
* `AREA_REQUIRED_PERMISSIONS_RETIRED`): an area is a layout grouping, not an
|
|
184
|
+
* access boundary. What replaces those keys is not a new key but this
|
|
185
|
+
* derivation: an area is visible iff something inside it is. Because it is
|
|
186
|
+
* computed from the same guards that decide what renders, it can never
|
|
187
|
+
* disagree with the rendered navigation — and there is nothing for a
|
|
188
|
+
* metadata author to get wrong. An area with no items at all derives the
|
|
189
|
+
* same way (no visible item → hidden).
|
|
190
|
+
*/
|
|
191
|
+
export declare function hasVisibleNavigationItems(items: NavigationItem[], options?: NavigationVisibilityOptions): boolean;
|
|
152
192
|
/**
|
|
153
193
|
* Lightweight template-variable context for nav items that target a
|
|
154
194
|
* specific record / org. The shell injects the signed-in user id and
|