Skip to content

Commit a6a871e

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/project-thread-qf9muq
2 parents 7b3b830 + 504ba51 commit a6a871e

60 files changed

Lines changed: 2888 additions & 360 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: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@objectstack/skills': patch
3+
---
4+
5+
docs(skills): the ADR-0126 §1.3 promise pages and the skills teach what ADR-0146 D2 delivers — customizations in `.custom`, `__c` fields, the flow override and "new similar", no package-less overlay
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
- **Before.** The skills taught the pre-epic paths: `objectstack-data` named no home for a customer's extension of a shipped object and no `__c` rule, and its lock table still called an edit of a shipped item an "overlay"; `objectstack-automation` said nothing about a flow an installed package ships, so an agent cloned it (two copies running) or edited it in place (refused); `objectstack-platform` taught the declared override's read but not who may declare it, how the pair is created, or what the three non-overridable types do. The docs promise pages (`capabilities/integrations`, `build-without-code`) still said views and dashboards are "yours to edit directly" and sent readers to a Setup packaged-automation page to switch off and clone a flow.
11+
- **Now.** `objectstack-data` says an object an installed package ships is extended from the base's paired `.custom` package, every added field ends in `__c`, the suffix is refused anywhere else and an unsuffixed field is refused in the pair, a base field changes only through `fieldPatches`, and Studio's Add field writes the same extension; its lock table reads "Edit", not "Edit (overlay)". `objectstack-automation` says a packaged flow is customized by a same-named declared override in the pair (armed in the base's place, one activation switch, a suspended run finishes on the body it started on), that an undeclared same name is refused at publish, and that the clone door is "new similar": a copy under a new name, switched off, in the pair, never package-less. `objectstack-platform` adds the ensure door and its two manifest facts, the customizations read, the uninstall refusal, the write gate's one rule for dependents (rename), and "new similar" for permission sets, positions and capabilities. One eval per skill asserts the taught shape and refuses the old one.
12+
- Every file stays under its token ceiling: the new text is paid for by deleting restatement in the same file (a layout tree the Template section and the Naming table already state; a search-mirror maintenance table and a formula aside restating the sentence above them; the dates and money legacy → CEL rows `objectstack-formula`'s table holds; the CEL callout restating that skill's pointer; two `runAs` notes and a `readonly` note tightened, no rule removed). The touched ceilings lower to their new measurements; no ceiling rises, no frontmatter, schema or behaviour changes. The docs site's promise pages, install modes, object extensions, metadata lifecycle, permission sets, CLI and metadata API pages gain the same facts.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
---
2+
'@object-ui/plugin-list': patch
3+
'@object-ui/app-shell': patch
4+
'@object-ui/i18n': patch
5+
---
6+
7+
feat(plugin-list, app-shell): one "Personalized" marker beside the list title holds the one reset to the view
8+
9+
Clause-②: yes (widening)
10+
Metadata-protocol: none
11+
12+
- **The marker.** While a reader's list differs from its view, the Console draws a **Personalized** marker beside the list title (in the page header, and beside the phone title as an icon alone). Opening it names what differs (filters, search, sort, grouping, column layout, hidden fields, density, layout, row color, row numbers, inline editing) and holds **Reset to view**, with a sentence saying what it covers and what it leaves alone. It is not configurable: no metadata key or option.
13+
- **The one reset.** It drops the active view's stored entry and the cached search term, removes the reader's whole `uf_*` family from the address bar (Filter panel, search, sort, grouping and every user-filter chip), and opens the list again, so a reload or Back does not bring the old list back. Not list state, so untouched: the record-open preference, pinned views and their order, favorites, and a "View all" link's `filter[...]` scope.
14+
- **Gone.** The header ⋯ entry "Reset view", and, on the Console list, the Display panel's "Reset to view default". The sort popover's reset and the Filter panel's "Clear all" stay: each puts back one control.
15+
- **`ListView` (`@object-ui/plugin-list`)** gains one optional host prop, `onPersonalizationChange(parts)`, reporting which parts of the list on screen differ from the view (`sort`, `filters`, `search`, `grouping`, `hiddenFields`, `density`, `layout`, `rowColor`, `rowNumbers`, `inlineEdit`; `columns` is in the part type for a host to add). With it the Display panel draws no reset of its own; without it nothing changes. `viewDefaults` also accepts `grouping`, the view's own grouping under one the host laid over it; a `viewDefaults` without that key leaves the grouping `schema` opened with as the view's.
16+
- **Copy (`@object-ui/i18n`).** New `console.objectView.personalized`, `personalizedHeading` and `personalizedParts.*` in all ten packs; `console.objectView.resetView` and `resetViewTitle` now label the marker's reset and say everything it covers. No key is removed.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
'@objectstack/spec': minor
3+
---
4+
5+
fix(spec)!: a dashboard that declares two global filters under one name is refused at every door that parses it
6+
7+
Clause-②: no (narrowing)
8+
Metadata-protocol: narrowed
9+
Skills-docs: none — `skills/objectstack-ui/rules/dashboards.md` teaches a filter's `name` as "the stable key `filterBindings` references", defaulting to `field`, and no file under `skills/**` shows two filters under one key; every taught use stays true.
10+
11+
**BREAKING** for a dashboard whose `globalFilters` repeats a filter key.
12+
13+
- **Before.** `DashboardSchema` typed `globalFilters` as a plain array, so two entries under one key parsed and the dashboard save door (`PUT /api/v1/meta/dashboard/X`) answered 200. A filter's key is its `name`, or its `field` when it has no `name`: the key the filter bar draws its control under and the key a widget's `filterBindings` names. The board drew one control, and the value typed into it filtered the field of the other definition, so a tile read a number the author never asked for.
14+
- **Now.** `DashboardSchema.globalFilters` refuses the pair, so every door that parses a dashboard refuses it: `defineStack`, `os validate`, `os build` and the dashboard save door (422 `INVALID_METADATA`). One issue per repeated key, at the second declaration's `name` (or its `field`, when that entry has no `name`), naming the key and every index: `This dashboard declares the global filter 'X' twice in globalFilters: globalFilters[i] and globalFilters[j]. …`. The rule sits on the array, so a mirror that spreads `DashboardSchema.shape` keeps it.
15+
- **Not changed.** Distinct names, two filters with distinct names over the same `field`, and the same name on two different dashboards.
16+
- **Fix.** Rename all but one of the colliding entries (and every widget `filterBindings` key that means a renamed one), or delete the copy.
17+
- **Stored rows.** A stored dashboard that repeats a key still loads, with `_diagnostics` reading `valid: false` and carrying the refusal, and its next save (draft or publish) is refused until it is fixed. Nothing rewrites it: which definition keeps the name only the author knows. The upgrade guide entry is `ui-dashboard-global-filter-duplicate-name-refused`.
18+
19+
<!-- adr-0087: registered ui-dashboard-global-filter-duplicate-name-refused -->
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
---
4+
5+
fix(studio): an Interfaces edit whose save the server refused counts as unsaved, so leaving or reloading asks first
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
When the server refused a report's, dashboard's or page's autosave (a 422, say), the edit stayed on screen but Studio's leave guards did not see it: a reload, a pillar or Home link, or opening another item in the Interfaces rail dropped it with no question. The Interfaces pillar now reports such an edit as unsaved work beside its navigation edits, so the browser's "leave site?" prompt, the Studio header and the shell's link guard ask, and the rail and the New dialog ask before another item replaces it. The same holds for an object item's list-view edit whose save was refused. An edit whose save lands, or the load of another item, clears it; an item you have not edited never asks.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
'create-objectstack': patch
3+
---
4+
5+
fix(create-objectstack)!: a scaffold into the current directory refuses, writing nothing, when a template file would overwrite one already there (#29134)
6+
7+
Clause-②: no (narrowing) — `create-objectstack` with no name (or an empty one) in a current directory holding a file the template writes (`README.md`, `package.json`, …) refuses with exit 1 and leaves the directory untouched, where it overwrote those files and exited 0 before. Nothing is widened.
8+
Metadata-protocol: none
9+
10+
<!-- adr-0087: not-required (no-migration-prescription) No key of any schema, no export of a published entry and no stored shape changes: the scaffolder's command line refuses one more case before it writes, so there is nothing for a migration to rewrite and no tombstone. -->
11+
12+
**BREAKING** for a script that runs `create-objectstack` with no name inside a directory that already holds files the template writes.
13+
14+
- **Before.** A named directory that was not empty was refused (`Directory already exists and is not empty`, exit 1), but the current directory was not checked at all: the template was copied over whatever was there, so an existing project's `README.md` and `package.json` were replaced without a word and the run exited 0.
15+
- **Now.** Before anything is written, the run compares the template's files with what the current directory holds. If any template file would replace an existing file (or a file stands where the template needs a directory), it refuses with exit 1, names each of those paths, and writes nothing.
16+
- **Unchanged.** A current directory that holds only files the template does not write (a `.git/`, a notes file) still scaffolds, and those files are left as they were; the closing summary still says the directory already had contents. An empty current directory and a named directory behave as before.
17+
18+
**The remedy.** Move the named files aside and re-run, or scaffold into a new directory: `create-objectstack my-app`.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
'@objectstack/spec': patch
3+
---
4+
5+
fix(spec): a field's translated help reaches its authored `inlineHelpText`, the line the console draws
6+
7+
Clause-②: no
8+
Metadata-protocol: none
9+
10+
Nothing changes in what a metadata author can write. What changes is the served, translated read of an object: `translateObject` (the resolver behind `GET /api/v1/meta/object/:name` and every other localized object read) now serves a field's `objects.OBJECT.fields.FIELD.help` translation on the field's own `inlineHelpText` when the field authors one.
11+
12+
- **Before.** The translation was served on `description` only. The i18n extractor scaffolds that entry from `help ?? inlineHelpText ?? description`, and the console draws a field's help line from `inlineHelpText || description`, so a field that authored `inlineHelpText` showed its source-language text in every locale and its translation never appeared.
13+
- **Now.** A field that authors a non-empty `inlineHelpText` is served the translation there, and on `description` as before. A field without one (absent, or an empty string, which the console reads as absent) gains no `inlineHelpText` key; its translation stays on `description`, which the console already draws.
14+
- **Unchanged.** A locale with no `help` entry for the field, and the source locale, serve the authored text. Each slot keeps a value that diverged from the packaged declaration (a tenant's own edit), judged per slot by the same rule that already guards `description`. Nothing is ever served on a `help` key.

‎content/docs/api/metadata-api.mdx‎

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,21 @@ unaffected. See [unrecognised type spelling](/docs/api/error-catalog#invalid_req
9696
in the error catalog for the envelope — the same code and status cover both this
9797
refusal and the misspelling one above; the message text tells them apart.
9898

99+
**An item an installed package ships is customized in that package's pair**
100+
([ADR-0146](https://github.com/objectstack-ai/objectstack/blob/main/docs/adr/0146-studio-designs-setup-administers-one-editor-per-item-paired-customize-package.md)
101+
D2, D11). A `PUT` naming no package onto an item one installed read-only package
102+
`hotcrm` ships is refused `403 NOT_OVERRIDABLE`; for a type an override applies to,
103+
the sentence names the route: save it with `?package=hotcrm.custom`, the body
104+
declaring `overrides: { package: 'hotcrm', basedOn: '3.2.0' }` (`basedOn` is the
105+
`manifest.version` of `hotcrm` it was taken from, recorded and never judged). Only the pair declares an override: an item of any other
106+
package that depends on `hotcrm` and bears a `hotcrm` item's name is refused at save
107+
and publish, and its fix is a new name. A permission set, position or capability is
108+
never overridden; it is copied under a new name. What the reads then serve is in
109+
[Metadata lifecycle](/docs/concepts/metadata-lifecycle#customizing-an-installed-package-the-paired-custom-override-adr-0146).
110+
`POST /packages/hotcrm/ensure-customization` creates the pair when absent (Studio calls
111+
it on the first change), and `GET /packages/hotcrm/customizations` lists its overrides,
112+
extensions and switched-off items in one read.
113+
99114
**Body**: `{ type: "object", name: "account", item: { ... } }`
100115
**Response**: `{ success: true }`
101116

‎content/docs/build-without-code.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Two properties make Studio safe to hand to non-developers:
3535

3636
## Setup — where the platform is administered
3737

38-
The **System Settings** app covers platform administration: user management and invitations, permission assignment, datasources (including federated external databases), diagnostics and audit logs, and the **Marketplace** — template apps such as HotCRM install with one click and appear alongside your own apps. What "customize" means depends on the piece: views and dashboards are yours to edit directly; a packaged object grows through your own fields via an extension package, never by reshaping what shipped; a packaged flow stays locked, but a dedicated **packaged automation** page here lets you switch it off and clone your own — the clone is an ordinary flow, yours to edit in Studio.
38+
The **System Settings** app covers platform administration: user management and invitations, permission assignment, datasources (including federated external databases), diagnostics and audit logs, and the **Marketplace** — template apps such as HotCRM install with one click and appear alongside your own apps. Setup holds no metadata editor: its metadata pages open Studio, and an installed app is customized there. Open the app in Studio and every change lands in its paired customization package (`hotcrm.custom` for HotCRM), created on your first change and exported and deployed like any package, while what shipped stays the vendor's. **Customize** on a view, dashboard, report or flow saves your version as an override of the shipped one, marked with the app it overrides, and **Restore package original** removes it. **Add field** on a shipped object adds your own field, named with a `__c` suffix, and a shipped field's label, description, help text, placeholder and option labels can be changed, nothing else. A shipped flow's switch turns it off for this deployment, and **New similar** copies a flow or a permission set under a new name; a flow's copy starts switched off.
3939

4040
## When to reach for code instead
4141

‎content/docs/capabilities/integrations.mdx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ A business system earns its keep by fitting into the systems — and habits —
1515
- **Triggers in** — external systems start platform [flows](/docs/capabilities/automation).
1616
- **Connectors** — ready-made Slack and generic REST connectors drop into flows; an HTTP API, OpenAPI document, or MCP server can be [declared as metadata](/docs/automation/connectors) and goes live at boot, no plugin code.
1717
- **Federated external databases** — point at an existing database and query it in place: no migration, visible in views, usable in flows.
18-
- **Marketplace templates** — install complete apps (HotCRM among them) with one click: objects, views, flows, dashboards, and seed data included. Views and dashboards are yours to edit directly; a packaged flow stays locked, but [Setup](/docs/build-without-code) lets you switch it off and clone your own to edit in Studio; a packaged object grows through your own fields via an extension package, not by editing what shipped.
18+
- **Marketplace templates** — install complete apps (HotCRM among them) with one click: objects, views, flows, dashboards, and seed data included. What shipped stays the vendor's: you customize an installed app in [Studio](/docs/build-without-code), and every change lands in the app's own customization package (`hotcrm.custom` for HotCRM), which exports and deploys to another environment like any package. A view, dashboard, report or flow is customized by overriding it there; a shipped object gains your own fields, named with a `__c` suffix; a shipped flow can be switched off for your deployment, or copied under a new name with **New similar**.
1919
- **Deploy anywhere** — cloud or fully self-hosted; your data and your app definition stay yours.
2020

2121
## Everyday collaboration

0 commit comments

Comments
 (0)