Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions .changeset/6025-declare-plugin-grid-in-gallery-host.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
---
---

Docs-site host and catalog test only: `apps/site/app/components/registerCatalogBlocks.ts`
now declares `@object-ui/plugin-grid` instead of inheriting `object-grid` from
`@object-ui/plugin-view`'s `import { ObjectGrid }` (`ObjectView.tsx:37`). Nothing renders
differently — measured: with exactly the eleven packages the host used to carry,
`object-grid` and every `@object-ui/plugin-form` key already resolved — which is the point.
A component import in another package was the only reason two catalog tiles could draw, and
a refactor of `object-view` that stopped it from drawing a grid itself would have turned
them into OBJUI-001 panels with the cause several files from the symptom.

`catalog-gallery-render.test.tsx` gains the judge that can tell the two apart: every
`plugin-*` category with catalog entries must be loaded BY NAME in the host's import list,
derived from the categories rather than enumerated, and leaning on the existing parity case
that ties `HOST_PACKAGES` to the host file's literal imports. `ComponentRegistry.get()`
cannot judge this — it is truthy in both worlds.
31 changes: 31 additions & 0 deletions .changeset/6167-plugin-form-catalog-entries.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
---
---

Docs and catalog fixtures only, no published package source touched: the two `plugin-form`
catalog entries are now real `object-form` nodes instead of hand-built `form` schemas.
`content/docs/plugins/plugin-form.mdx` mounted `basic-form` and `contact-form` under
`PluginLoader plugins={['form']}` while both authored a root `type: "form"` with `input` /
`select` / `checkbox` / `textarea` fields — every one of those registered by
`@object-ui/components`, none of them by `@object-ui/plugin-form`, whose own keys are
`object-form`, `embeddable-form`, `form-analytics`, `object-master-detail-form`,
`record:line_items` and `view:form`. They are replaced by `object-form-record` (one `users`
record, fields derived from the object's metadata, `fields` / `columns` shaping the grid)
and `object-form-tabbed-sections` (the same record with `formType: 'tabbed'`, so the
declared `sections` become tab panels of one form).

The two hand-built forms are legitimate `@object-ui/components` examples filed under the
wrong plugin, so they are re-seated into `components-form-form` as `basic-form` and
`demo-request-form` rather than deleted — deleting a catalog entry moves corpus-wide
counters (`NODE_CENSUS` in `layout-dom-leak-5574.test.tsx` and in
`form-control-dom-leak-5632.test.tsx`, and the `className`-carrying layout node and `stack`
node floors in `layout-props-conversion.test.tsx`), and a counter that moves because a
fixture was deleted is indistinguishable later from one that moved because coverage
regressed. All of them are unchanged, with no floor edited.

`apps/site/app/components/registerCatalogBlocks.ts` now declares `@object-ui/plugin-form`,
and its header no longer claims the import list is "exactly the packages that census
resolves to". The two `OWN_PLUGIN_DEBT` lines in `catalog-gallery-render.test.tsx` are
deleted, so both entries are held to the pin like every other one, and the pin's
provenance instrument now reads the fixture record out of a form control's value as well as
out of the tile's text — a form puts its record in `input.value`, where `textContent`
cannot see it.
39 changes: 37 additions & 2 deletions apps/site/app/components/registerCatalogBlocks.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -36,10 +36,43 @@
* components-disclosure-toggle-group 1 core-schema-renderer 1
*
* The gallery page's PURPOSE is to render the whole catalog, so its baseline is
* that every type an entry names is registered before the render. The nine
* imports below are exactly the packages that census resolves to — not a
* that every type an entry names is registered before the render. Nine of the
* imports below are exactly the packages that census resolved to — not a
* precautionary sweep of the workspace.
*
* ## The list is no longer ONLY that census (objectui#6167)
*
* `@object-ui/plugin-form` is here for a different reason, and the header has
* to say so rather than let the sentence above keep describing a property this
* file no longer has. The two `plugin-form` catalog entries are real
* `object-form` nodes as of objectui#6167, and `object-form` is registered by
* `@object-ui/plugin-form` — so the gallery depends on that package by name.
*
* What it did NOT do is change what resolves. Measured before adding it, with
* exactly the eleven imports this file used to carry: `object-form`,
* `plugin-form:object-form`, `embeddable-form`, `form-analytics`,
* `object-master-detail-form`, `record:line_items` and `view:form` all resolved
* already, because `@object-ui/plugin-view` — import #11 below — does
* `import { ObjectForm } from '@object-ui/plugin-form'`
* (`packages/plugin-view/src/ObjectView.tsx:38`), and importing that entry runs
* its `ComponentRegistry.register` calls. The package's graph was therefore
* ALREADY in this route's eager closure; the import below adds a declaration,
* not a payload. Registration is idempotent for the same reason: an ES module
* executes once, so naming it here does not re-run anything.
*
* `@object-ui/plugin-grid` joins on the same argument and with the same
* measured non-effect (objectui#6025). The `plugin-grid` entries have been real
* `object-grid` nodes since objectui#5856, and `object-grid` reached this
* registry only because `ObjectView.tsx:37` — the line above the one quoted
* above — imports `ObjectGrid`. That is a COMPONENT import, not a plugin
* dependency: a refactor that stopped `object-view` from drawing a grid itself
* would be entirely reasonable, would say nothing about the gallery, and would
* turn two catalog tiles into OBJUI-001 panels several files from the cause.
*
* So the list below is: the census (nine), plus objectui#4600's original two,
* plus two packages the gallery's own entries depend on BY NAME. What it is not
* is a sweep — nothing is here that the catalog does not render.
*
* ## The cost, measured before deciding (objectui#4616 ruling 1)
*
* Eager registration pulls each package's graph into the `/docs/[[...slug]]`
Expand DownExpand Up@@ -126,3 +159,5 @@ import '@object-ui/plugin-map';
import '@object-ui/plugin-markdown';
import '@object-ui/plugin-timeline';
import '@object-ui/plugin-view';
import '@object-ui/plugin-form';
import '@object-ui/plugin-grid';
23 changes: 21 additions & 2 deletions content/docs/plugins/plugin-form.mdx
Original file line numberDiff line numberDiff line change
Expand Up@@ -17,9 +17,28 @@ npm install @object-ui/plugin-form

## Interactive Examples

<SchemaExample id="plugin-form/basic-form" />
Each preview below **is** an `object-form` node drawn by this plugin — the JSON
in the Code tab is the whole example, and the fields on screen were built from
the `users` object's own metadata rather than written into that JSON. Both the
metadata and the record come from the docs site's demo data source, because
`dataSource` is not a schema key: it is the prop the registered renderer pulls
off `SchemaRendererProvider` context (see
[Registration is a side effect of the import](#registration-is-a-side-effect-of-the-import)
below), so in your own app these same nodes read whatever object your data
source serves.

<SchemaExample id="plugin-form/contact-form" />
A plain `form` node with its fields written out inline is the
`@object-ui/components` renderer, not this plugin — that is what these two
examples used to be, and they now live in the catalog under
`components-form-form`.

### One record, fields from the object

<SchemaExample id="plugin-form/object-form-record" />

### Sections as tabs

<SchemaExample id="plugin-form/object-form-tabbed-sections" />

## Features

Expand Down
2 changes: 2 additions & 0 deletions examples/schema-catalog/package.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -39,7 +39,9 @@
"@object-ui/plugin-chatbot": "workspace:*",
"@object-ui/plugin-dashboard": "workspace:*",
"@object-ui/plugin-editor": "workspace:*",
"@object-ui/plugin-form": "workspace:*",
"@object-ui/plugin-gantt": "workspace:*",
"@object-ui/plugin-grid": "workspace:*",
"@object-ui/plugin-kanban": "workspace:*",
"@object-ui/plugin-map": "workspace:*",
"@object-ui/plugin-markdown": "workspace:*",
Expand Down
40 changes: 40 additions & 0 deletions examples/schema-catalog/src/catalog-meta.json
Original file line numberDiff line numberDiff line change
Expand Up@@ -36,6 +36,26 @@
"verification"
]
},
"components-form-form/basic-form": {
"title": "Basic Form",
"description": "A hand-built `form` node from `@object-ui/components`: name, email, country and newsletter fields declared inline, with no object behind them. For a form generated from an object's own metadata, see the `plugin-form` examples.",
"tags": [
"form",
"input",
"select",
"checkbox"
]
},
"components-form-form/demo-request-form": {
"title": "Demo Request Form",
"description": "A longer hand-built `form`: company details, industry and size selects, a message textarea and a terms checkbox, all declared inline. For a form bound to an object, see the `plugin-form` examples.",
"tags": [
"form",
"select",
"textarea",
"checkbox"
]
},
"components-layout-card/inventory-table-card": {
"title": "Inventory Table Card",
"description": "A card that draws a product inventory table by hand — toolbar buttons, header row, stock-status badges. For a table bound to an object, see the `plugin-grid` examples.",
Expand DownExpand Up@@ -109,6 +129,26 @@
"title": "Filtered Dashboard — Target Widgets Allow-list",
"description": "Legacy targetWidgets allow-list: only listed widgets get the default binding; an explicit filterBindings entry still wins"
},
"plugin-form/object-form-record": {
"title": "Object Form — One Record From Object Metadata",
"description": "object-form editing one `users` record: the fields come from the object's own metadata through `getObjectSchema`, the values from `findOne`, and `fields` / `columns` decide which of them appear and how wide the grid is.",
"tags": [
"object-form",
"objectql",
"edit",
"columns"
]
},
"plugin-form/object-form-tabbed-sections": {
"title": "Object Form — Sections as Tabs",
"description": "The same record with `formType: 'tabbed'`: the declared `sections` become tab panels of ONE form, so a single submit spans them and a tab the user leaves keeps its values.",
"tags": [
"object-form",
"tabbed",
"sections",
"objectql"
]
},
"plugin-grid/object-grid-columns": {
"title": "Object Grid — Column Definitions",
"description": "object-grid rendering the users object: `ListColumn` objects carrying label, width, align, cell `type` and `link`, with `sort`, `searchableFields` and `pagination` shaping the query the host's data source answers.",
Expand Down
48 changes: 36 additions & 12 deletions examples/schema-catalog/src/index.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -210,7 +210,9 @@ import components_form_file_upload_images_only from './schemas/components-form-f
import components_form_file_upload_multiple_files from './schemas/components-form-file-upload/multiple-files.json' with { type: 'json' };
import components_form_file_upload_simple_upload from './schemas/components-form-file-upload/simple-upload.json' with { type: 'json' };
import components_form_file_upload_single_file from './schemas/components-form-file-upload/single-file.json' with { type: 'json' };
import components_form_form_basic_form from './schemas/components-form-form/basic-form.json' with { type: 'json' };
import components_form_form_contact_form from './schemas/components-form-form/contact-form.json' with { type: 'json' };
import components_form_form_demo_request_form from './schemas/components-form-form/demo-request-form.json' with { type: 'json' };
import components_form_form_login_form from './schemas/components-form-form/login-form.json' with { type: 'json' };
import components_form_form_registration_form from './schemas/components-form-form/registration-form.json' with { type: 'json' };
import components_form_input_basic_input from './schemas/components-form-input/basic-input.json' with { type: 'json' };
Expand DownExpand Up@@ -414,8 +416,8 @@ import plugin_dashboard_support_dashboard from './schemas/plugin-dashboard/suppo
import plugin_editor_javascript_editor from './schemas/plugin-editor/javascript-editor.json' with { type: 'json' };
import plugin_editor_python_editor from './schemas/plugin-editor/python-editor.json' with { type: 'json' };
import plugin_editor_read_only_json_viewer from './schemas/plugin-editor/read-only-json-viewer.json' with { type: 'json' };
import plugin_form_basic_form from './schemas/plugin-form/basic-form.json' with { type: 'json' };
import plugin_form_contact_form from './schemas/plugin-form/contact-form.json' with { type: 'json' };
import plugin_form_object_form_record from './schemas/plugin-form/object-form-record.json' with { type: 'json' };
import plugin_form_object_form_tabbed_sections from './schemas/plugin-form/object-form-tabbed-sections.json' with { type: 'json' };
import plugin_gantt_construction_project_phases from './schemas/plugin-gantt/construction-project-phases.json' with { type: 'json' };
import plugin_gantt_project_timeline_with_dependencies from './schemas/plugin-gantt/project-timeline-with-dependencies.json' with { type: 'json' };
import plugin_gantt_sprint_development_timeline from './schemas/plugin-gantt/sprint-development-timeline.json' with { type: 'json' };
Expand DownExpand Up@@ -2238,6 +2240,16 @@ const REGISTRY: Record<string, Example> = {
},
schema: components_form_file_upload_single_file,
},
'components-form-form/basic-form': {
id: 'components-form-form/basic-form',
meta: {
title: "Basic Form",
description: "A hand-built `form` node from `@object-ui/components`: name, email, country and newsletter fields declared inline, with no object behind them. For a form generated from an object's own metadata, see the `plugin-form` examples.",
category: 'components-form-form',
tags: ["form", "input", "select", "checkbox"],
},
schema: components_form_form_basic_form,
},
'components-form-form/contact-form': {
id: 'components-form-form/contact-form',
meta: {
Expand All@@ -2247,6 +2259,16 @@ const REGISTRY: Record<string, Example> = {
},
schema: components_form_form_contact_form,
},
'components-form-form/demo-request-form': {
id: 'components-form-form/demo-request-form',
meta: {
title: "Demo Request Form",
description: "A longer hand-built `form`: company details, industry and size selects, a message textarea and a terms checkbox, all declared inline. For a form bound to an object, see the `plugin-form` examples.",
category: 'components-form-form',
tags: ["form", "select", "textarea", "checkbox"],
},
schema: components_form_form_demo_request_form,
},
'components-form-form/login-form': {
id: 'components-form-form/login-form',
meta: {
Expand DownExpand Up@@ -4079,23 +4101,25 @@ const REGISTRY: Record<string, Example> = {
},
schema: plugin_editor_read_only_json_viewer,
},
'plugin-form/basic-form': {
id: 'plugin-form/basic-form',
'plugin-form/object-form-record': {
id: 'plugin-form/object-form-record',
meta: {
title: "Basic Form",
description: "",
title: "Object Form — One Record From Object Metadata",
description: "object-form editing one `users` record: the fields come from the object's own metadata through `getObjectSchema`, the values from `findOne`, and `fields` / `columns` decide which of them appear and how wide the grid is.",
category: 'plugin-form',
tags: ["object-form", "objectql", "edit", "columns"],
},
schema: plugin_form_basic_form,
schema: plugin_form_object_form_record,
},
'plugin-form/contact-form': {
id: 'plugin-form/contact-form',
'plugin-form/object-form-tabbed-sections': {
id: 'plugin-form/object-form-tabbed-sections',
meta: {
title: "Contact Form",
description: "",
title: "Object Form — Sections as Tabs",
description: "The same record with `formType: 'tabbed'`: the declared `sections` become tab panels of ONE form, so a single submit spans them and a tab the user leaves keeps its values.",
category: 'plugin-form',
tags: ["object-form", "tabbed", "sections", "objectql"],
},
schema: plugin_form_contact_form,
schema: plugin_form_object_form_tabbed_sections,
},
'plugin-gantt/construction-project-phases': {
id: 'plugin-gantt/construction-project-phases',
Expand Down
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
{
"type": "object-form",
"objectName": "users",
"mode": "edit",
"recordId": "1",
"columns": 2,
"fields": ["name", "email", "department"],
"submitText": "Save changes"
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
{
"type": "object-form",
"objectName": "users",
"mode": "edit",
"recordId": "1",
"formType": "tabbed",
"defaultTab": "identity",
"sections": [
{ "name": "identity", "label": "Identity", "columns": 2, "fields": ["name", "email"] },
{ "name": "organisation", "label": "Organisation", "fields": ["department", "created_at"] }
],
"submitText": "Save changes"
}
Loading
Loading