Skip to content

Commit f99ecc8

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/objectui-spec-symbol-ci-rule-4r3xlc-batch4
2 parents cbe6d22 + 496825f commit f99ecc8

60 files changed

Lines changed: 1570 additions & 190 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
---
3+
4+
ci: close issues that a merged PR fixes in another repository
5+
6+
Release-nothing: adds `.github/workflows/cross-repo-issue-closer.yml` and no
7+
package code.
8+
9+
Defects are routinely found in objectstack, where verification runs, and fixed
10+
here. But GitHub's closing keywords only act within a repository, so a PR here
11+
saying `Fixes objectstack-ai/objectstack#4475` merges and leaves that framework
12+
issue open — with no reference to the PR on the issue's own page either. v17
13+
verification hit this twice in one day: #3150 fixed objectstack#4475 and #3163
14+
fixed objectstack#4478, and both were closed by hand.
15+
16+
The job has two modes and both are visible. With a cross-repo token it closes
17+
the foreign issue and links the PR. Without one it comments on the merged PR
18+
naming what still needs closing by hand — this repository's secrets are
19+
`GITHUB_TOKEN` (scoped to the repository running the workflow, which is the
20+
whole problem), `NPM_TOKEN` and `CODECOV_TOKEN`, so until an admin provisions
21+
`CROSS_REPO_ISSUE_TOKEN` the job cannot perform the close at all.
22+
23+
That second mode is deliberate, not a fallback. A workflow that quietly does
24+
nothing because a secret was never provisioned is the "declared but never
25+
enforced" shape both repositories keep having to fix. A missing credential has
26+
to announce itself.
27+
28+
Matched references are restricted to the qualified `owner/repo#N` form; the
29+
bare `#N` form already works natively and is left alone. Same-repo qualified
30+
references are filtered out, already-closed targets are skipped, and one
31+
unreachable target cannot swallow the rest or read as success.
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
"@object-ui/app-shell": patch
3+
---
4+
5+
Collapse app-shell's `DecisionOutputDef` to a plain re-export of the spec's
6+
(objectstack#4562).
7+
8+
The local type was `interface DecisionOutputDef extends SpecDecisionOutputDef
9+
{ required?: boolean }` — a structural derivation carrying ONE documented
10+
divergence, because the server enforced `required` (`decide()` rejects a blank
11+
required output before any write) while `@objectstack/spec` did not model it.
12+
The spec adopted `required` in cd6b9f202 and pinned it at the schema level in
13+
objectstack#4561, and this repo now resolves a spec that has it
14+
(`@objectstack/spec@17.0.0-rc.1`, #3178). The addition is therefore redundant
15+
and the type becomes `export type DecisionOutputDef = SpecDecisionOutputDef`.
16+
17+
No behavior change and no API change: the symbol is internal to this package
18+
(it is not re-exported from `src/index.ts`), the resolved shape is identical
19+
key-for-key, and `decisionOutputParams()` still reads `d.required` — now off
20+
the spec's own field.
21+
22+
The module TSDoc still asserted "the spec does not model it yet", which was
23+
stale and actively misleading — an agent reading it would take the divergence
24+
as ground truth and build on it, which is the objectstack#4115 failure class
25+
this file's own tripwires exist to prevent. It now states the current truth.
26+
27+
The parity pin in `__tests__/spec-symbol-parity.test.ts` is inverted
28+
accordingly: `Exclude<keyof DecisionOutputDef, keyof SpecDecisionOutputDef>`
29+
is asserted `never` rather than `'required'`, plus an exact-identity
30+
assertion, so a future local addition to this symbol cannot slip in
31+
undocumented. The `type`-is-the-spec's-closed-enum pin is unchanged — that
32+
narrowing is still what stops a typo'd picker kind from silently degrading to
33+
a raw record-id text box (objectui#2955).
34+
35+
Note that this pin, like every other type-level assertion in that file, is not
36+
yet compiled by any gate — package tsconfigs exclude `**/*.test.ts`, so
37+
nothing type-checks it. It was verified by compiling the file explicitly. See
38+
objectui#3181.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
---
3+
4+
fix(ci): hand the cross-repo token to github-script instead of requiring @actions/github
5+
6+
Release-nothing: touches `.github/workflows/cross-repo-issue-closer.yml` only.
7+
8+
`require('@actions/github')` is not resolvable from a github-script `script:`
9+
block — the action bundles its dependencies, so the call fails at runtime with
10+
`MODULE_NOT_FOUND`. The token is now handed to the action itself
11+
(`github-token:`), which makes the injected `github` client the cross-repo one,
12+
with `secrets.GITHUB_TOKEN` as the fallback so the report path can still
13+
comment on the pull request when no cross-repo credential is configured.
14+
15+
Found on this workflow's first run that got past parsing. The run also
16+
confirmed the credential logging works — `CROSS_REPO_ISSUE_TOKEN: configured`
17+
followed by `Cross-repo targets: objectstack-ai/objectstack#4475` — so the
18+
job now fails at the last step rather than the first.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
"@object-ui/app-shell": minor
3+
---
4+
5+
fix(studio): the form-layout canvas resolves the object's field and section translations (#3134)
6+
7+
`ObjectFormDesigner` bills itself as a preview of the end-user form, but it read
8+
labels straight off the object draft — `entry.def.label` for fields, `group.label`
9+
for section headers. Every other surface for the same object (`ObjectForm`,
10+
`RecordDetailView`, the data grid) resolves those through the project's object
11+
translations first, so a fully translated object rendered `Opportunity Name` /
12+
`Basic Information` on the layout canvas while the very same fields read
13+
`商机名称` / `基本信息` one click away.
14+
15+
The designer now goes through `useSafeFieldLabel()``fieldLabel()` for field
16+
cards (including the drag overlay) and `sectionLabel()` for section headers —
17+
which is the same resolver the runtime form uses, with the authored metadata
18+
label as fallback when no translation exists. The lookup root is the object's
19+
API name; `StudioDesignSurface` now passes it explicitly (`objectName`) so a
20+
draft body that has not been re-named still resolves, falling back to
21+
`draft.name`.
22+
23+
Observable rendering change (translated labels now appear where English source
24+
labels did), hence `minor`.

.changeset/nav-action-dispatch.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
---
2+
"@object-ui/layout": minor
3+
"@object-ui/app-shell": minor
4+
---
5+
6+
Navigation `action` items actually run now (framework#4509).
7+
8+
A `type: 'action'` nav item rendered, gated like any other item, and did
9+
**nothing** when clicked. `NavigationRenderer` dispatches such a click to an
10+
`onAction` prop it expects the host shell to supply — it deliberately never
11+
reads `item.actionDef` itself — and no shipped sidebar supplied that prop. So
12+
`actionDef.actionName` reached no dispatcher: an author could put an action in
13+
the menu, watch it render with its icon and label, and never find out that
14+
clicking it was a no-op. The framework's liveness ledger recorded this as the
15+
single gap in the AppSchema navigation surface.
16+
17+
**New `useNavActionDispatch`** (`@object-ui/app-shell`) resolves the nav item's
18+
`actionName` against `action` metadata at click time — the same source
19+
`DeclaredActionsBar` reads for a record toolbar — and dispatches the resolved
20+
definition through `useAction()`. `UnifiedSidebar` now passes it. No new
21+
provider is involved: the sidebar already renders inside `ConsoleShell`'s
22+
`GlobalActionRuntimeProvider`, so nav actions get the fully-wired console runner
23+
including the confirm, param-collection, result and navigate dialogs. A declared
24+
`params` array becomes the runner's param-dialog input, and the nav item's own
25+
`actionDef.params` is passed as the value bag, so a menu entry can pre-fill the
26+
action it launches.
27+
28+
Nav actions are inherently **global**: `ActionNavItemSchema` is strict with
29+
exactly `{ actionName, params? }` and carries no `objectName`, so resolution is
30+
by name alone and no record context rides along.
31+
32+
**Behaviour change:** a shell that passes no `onAction` no longer renders
33+
`action` items at all, instead of rendering them dead. This mirrors the existing
34+
capability guards — an item the host cannot serve is hidden — and it makes the
35+
omission diagnosable: a missing prop now shows up as "my action item is gone",
36+
which leads to the prop, rather than "clicking does nothing", which for three
37+
releases led nowhere. Every failure at dispatch time (an unnamed item, an
38+
unresolvable action, a throwing action) warns and toasts instead of returning
39+
silently.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
---
2+
"@object-ui/app-shell": minor
3+
"@object-ui/types": minor
4+
"@object-ui/plugin-dashboard": patch
5+
"@object-ui/plugin-report": patch
6+
---
7+
8+
Upgrade to `@objectstack/spec@17.0.0-rc.1`, stop offering the retired `wait` timeout fields (#3101), and route the newly-adopted `combo` chart type.
9+
10+
**Breaking for authoring, and the reason to do it now**: the `wait` panel no longer offers
11+
`waitEventConfig.timeoutMs` or `.onTimeout`. Both are `retiredKey()` tombstones as of spec
12+
17.0.0-rc.1 (framework#4158), which means a value written there is **rejected at load**
13+
so until this lands, Studio can produce flow metadata the author's own runtime refuses.
14+
That hazard opened the moment rc.1 published, independent of when this repo bumps.
15+
16+
`wait` never had a timeout: `onTimeout` had zero readers, so neither `'fail'` nor
17+
`'continue'` ever happened, and `timeoutMs`'s only reader used it as the timer **duration**
18+
when `timerDuration` was absent. Use **Duration** — it accepts a bare number as
19+
milliseconds, making the old `timeoutMs: 60000` and `timerDuration: '60000'` the same wait.
20+
Stored flows are converted by framework's D2 conversion; the designer simply stops offering
21+
the entry. The two `zh` label overrides go with the fields.
22+
23+
#3101 asked for this to ride along with the bump rather than land alone, and that is
24+
load-bearing: the sibling-block assertion is **bidirectional**, so deleting the fields
25+
against a spec that still declares them fails in the other direction.
26+
27+
**`combo` is now a spec chart type** — the sole addition to `ChartTypeSchema` in rc.1 (19
28+
members → 20). It had been a renderer-local family the chart renderer derived from the
29+
series, so nothing classified it on the two surfaces that route a *spec* chart type: a
30+
spec-valid `combo` fell through to the red "Unknown component type" panel on a dashboard
31+
and to the out-of-spec notice on a report. Both now route it
32+
(`widgetDispatch.SERIES_CHART_TYPES`, `planReportChart`). The renderer-local derivation
33+
stays — it is what makes an authored `type: 'combo'` render rather than merely validate.
34+
35+
**Retired spec exports this repo bound to**, all removed upstream in spec 17.0.0:
36+
37+
- `JoinStrategy` / `WindowFunction` (framework#4286 tombstoned `query.joins` and
38+
`query.windowFunctions`: no engine or driver ever read either on the query path). They
39+
were derived off the spec enums under objectstack#4115's "come off the spec enum, not a
40+
restatement" rule; with no enum left, `data-protocol.ts` now restates the members locally
41+
— verbatim from the last spec that published them — as the objectui query-AST vocabulary
42+
they have become. The AST itself is unchanged.
43+
- `PerformanceConfig`, retired with `dashboard.performance` (framework#3896). Nothing bound
44+
to it — `@object-ui/react`'s `usePerformance` declares its own interface and is untouched.
45+
The dashboard form is derived from the spec's own `dashboardForm`, so the field
46+
disappears from the inspector for free; its test now pins the absence.
47+
48+
**Three inverted pins fired, and are recorded rather than resolved.** objectstack#4171's
49+
tripwires asserted that `NavigationItem`, `FormField` and `ConditionalValidation`'s branches
50+
still erased to `any`/`unknown` upstream — the premise that justified objectui keeping local
51+
declarations. rc.1 types them properly, so the assertions are inverted to state the new
52+
fact. The burn-down each one asks for — deriving those types from the spec — touches
53+
widely-used public types and is deliberately **not** bundled into a version bump; it is
54+
tracked in #3177. `JoinNode`'s pin is gone outright: the symbol no longer exists.
55+
56+
**What the bump arms.** The reconciliation ledger's `subflow` and `decision` panels
57+
feature-detect their spec exports and had never actually run — rc.0 predates the exports
58+
(framework#4278). They now execute and pass. The `script` panel's full bidirectional check
59+
stays deliberately skipped: rc.1 predates framework#4343, so the retired dispatch branches
60+
are still contract keys there, and only the "offers nothing the executor ignores" direction
61+
is meaningful. It arms itself on the next rc.
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
---
2+
"@object-ui/plugin-timeline": minor
3+
"@object-ui/plugin-list": minor
4+
---
5+
6+
fix(timeline,list): the timeline honours `timeline.dateField`, not just `timeline.startDateField` (#3129)
7+
8+
`dateField` is the pre-#2231 alias for `startDateField`. `@object-ui/types`
9+
declares it on the nested config (`ListViewTimelineConfig`), and both
10+
`ObjectView` read-sites (app-shell and plugin-view) resolve it — but the two
11+
read-sites that actually drive the axis did not:
12+
13+
- `ObjectTimeline` consulted the alias only on the FLAT prop (`schema.dateField`),
14+
never on the nested `schema.timeline`.
15+
- `ListView` resolved it out of `options.timeline` but not out of the
16+
spec-canonical `schema.timeline` — including in the capability gate, so such a
17+
view could fail to offer the Timeline option at all.
18+
19+
So a view authored as `timeline: { dateField: 'start_date' }` — the spec nesting
20+
with the legacy key — fell through to the caller's default (`created_at` /
21+
`due_date`). That field is normally absent from the `$select` projection, so
22+
every record came back without it and the timeline rendered all of them under
23+
**No date** — while the configured date was sitting in the row untouched. That
24+
also explains why widening the view's projection changed nothing: the projection
25+
already carried the right field; the renderer was reading a different one.
26+
27+
Both read-sites now resolve the alias in the same precedence position they
28+
already use for `options.timeline.dateField`. The spec key still wins wherever
29+
both appear. Observable rendering change (records move out of "No date" into
30+
real date buckets), hence `minor`.

0 commit comments

Comments
 (0)