Skip to content

Commit 2fa6d1e

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/project-thread-jf62r6
2 parents 19d3f2a + c17719d commit 2fa6d1e

169 files changed

Lines changed: 12288 additions & 824 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: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
---
2+
'@object-ui/components': patch
3+
---
4+
5+
refactor(components)!: retire forty-four more zero-consumer exports — menubar, navigation-menu, input-otp and carousel parts, filter and notification helpers — and delete the item parts, `NativeSelect`, `ResizableHandleProps` and `useRelatedCount` nothing reads
6+
7+
Clause-②: no (narrowing)
8+
Metadata-protocol: none
9+
10+
<!-- adr-0087: not-required (runtime-export-retired @object-ui/components#MenubarMenu, @object-ui/components#MenubarItem, @object-ui/components#NavigationMenuItem, @object-ui/components#InputOTPGroup, @object-ui/components#InputOTPSeparator, @object-ui/components#CarouselItem, @object-ui/components#ItemMedia, @object-ui/components#ItemContent, @object-ui/components#ItemActions, @object-ui/components#ItemGroup, @object-ui/components#ItemSeparator, @object-ui/components#ItemTitle, @object-ui/components#ItemDescription, @object-ui/components#ItemHeader, @object-ui/components#ItemFooter, @object-ui/components#NativeSelect, @object-ui/components#NativeSelectProps, @object-ui/components#ResizableHandleProps, @object-ui/components#useRelatedCount, @object-ui/components#mountedOperatorValue, @object-ui/components#retypeFilterValue, @object-ui/components#narrowFilterValueToOptions, @object-ui/components#CURRENCY_COMPANION_SUFFIX, @object-ui/components#currencyCompanionId, @object-ui/components#currencyCompanionOf, @object-ui/components#pairedCurrencyField, @object-ui/components#KbdGroup, @object-ui/components#isInsidePopperLayer, @object-ui/components#usePopperAwareInteractOutside, @object-ui/components#SIDEBAR_WIDTH_FALLBACK, @object-ui/components#SIDEBAR_WIDTH_ICON_FALLBACK, @object-ui/components#useIsActiveListRecord, @object-ui/components#useScrollActiveListRecordIntoView, @object-ui/components#ActiveListRow, @object-ui/components#listRecordIdOf, @object-ui/components#DataLoadingState, @object-ui/components#DataLoadingStateProps, @object-ui/components#NOTIFICATION_ACTION_BUTTON_VARIANTS, @object-ui/components#NOTIFICATION_POSITION_CLASSES, @object-ui/components#NOTIFICATION_SEVERITY_STYLES, @object-ui/components#notificationActionVariant, @object-ui/components#notificationIcon, @object-ui/components#notificationSeverityStyle, @object-ui/components#NotificationSeverityStyle) the retired operands are React components, hooks, helpers, constants and their types on the components package entry; nothing in the workspace or in hotcrm imports any of them from the package entry, and no packages/spec schema, registered node type, conversion surface or stored shape names them (the schema renderers, the filter builder and the notification surfaces keep reading them inside the package), so there is nothing for `objectstack migrate meta` to rewrite -->
11+
12+
**BREAKING** for a host that imports any of these forty-four names from `@object-ui/components`. None had an importer anywhere in the workspace or in hotcrm, so the Console and every `@object-ui/*` package are unaffected, and every schema node type (`menubar`, `navigation-menu`, `input-otp`, `carousel` and the rest), the filter builder and the five notification surfaces render exactly as before.
13+
14+
The six shadcn parts below (`MenubarMenu`, `MenubarItem`, `NavigationMenuItem`, `InputOTPGroup`, `InputOTPSeparator`, `CarouselItem`) were named as staying on the entry by the previous `@object-ui/components` retirement in this series; they leave now. Every reference to them outside the package was a same-named declaration of another package (the `@object-ui/types` interfaces `MenubarMenu`, `NavigationMenuItem`, `CarouselItem`), an example title or test prose, never an import of these components.
15+
16+
Thirteen of them are **gone from the package, not only from the entry**, because nothing inside the package read them either:
17+
18+
- `src/custom/item.tsx` keeps only `Item`; `ItemMedia`, `ItemContent`, `ItemActions`, `ItemGroup`, `ItemSeparator`, `ItemTitle`, `ItemDescription`, `ItemHeader` and `ItemFooter` are deleted.
19+
- `src/custom/native-select.tsx` is deleted with `NativeSelect` and `NativeSelectProps`.
20+
- The type alias `ResizableHandleProps` is deleted.
21+
- The hook `useRelatedCount` is deleted; `useRelatedCountVersion` and `RelatedCountStore` stay.
22+
23+
The other thirty-one stay in their modules, which this package's own renderers, components and tests read, and only leave the entry (the shadcn registry files under `src/ui/` are untouched, so `pnpm shadcn:update` stays a clean re-fetch):
24+
25+
- `menubar`: `MenubarMenu`, `MenubarItem`
26+
- `navigation-menu`: `NavigationMenuItem`
27+
- `input-otp`: `InputOTPGroup`, `InputOTPSeparator`
28+
- `carousel`: `CarouselItem`
29+
- `filter-builder`: `mountedOperatorValue`, `retypeFilterValue`, `narrowFilterValueToOptions`
30+
- `filterRecordCurrency`: `CURRENCY_COMPANION_SUFFIX`, `currencyCompanionId`, `currencyCompanionOf`, `pairedCurrencyField`
31+
- `kbd`: `KbdGroup`
32+
- `mobile-dialog-content`: `isInsidePopperLayer`, `usePopperAwareInteractOutside`
33+
- `navigation-overlay`: `SIDEBAR_WIDTH_FALLBACK`, `SIDEBAR_WIDTH_ICON_FALLBACK`
34+
- `record-list-face`: `useIsActiveListRecord`, `useScrollActiveListRecordIntoView`, `ActiveListRow`, `listRecordIdOf`
35+
- `view-states`: `DataLoadingState`, `DataLoadingStateProps`
36+
- `notifications/severity`: `NOTIFICATION_ACTION_BUTTON_VARIANTS`, `NOTIFICATION_POSITION_CLASSES`, `NOTIFICATION_SEVERITY_STYLES`, `notificationActionVariant`, `notificationIcon`, `notificationSeverityStyle`, `NotificationSeverityStyle`
37+
38+
Every other name the entry exported stays exported unchanged, among them `Menubar`, `Carousel` with the type `CarouselApi`, `Item`, `Kbd`, `Pagination`, `FilterBuilder` with `filterValueArity`, `reshapeFilterValue`, `operatorsForFieldType` and the type `FilterValueArity`, `isCurrencyCompanion`, `syncRecordCurrencyRows` and the type `RecordCurrencyFilterField`, `MobileDialogContent`, `NavigationOverlay`, `ActiveListRecordProvider`, `DataEmptyState`, `EmptyState`, `DataErrorState`, the four notification surfaces with their props types, `ResizableHandle`, `ResizablePanel`, `ResizablePanelGroup`, and `GridSkeleton`, `KanbanSkeleton`, `FormSkeleton`, `ListSkeleton`, `ChartSkeleton` with their props types.
39+
40+
What leaves, and what to write instead:
41+
42+
- FROM `MenubarMenu`, `MenubarItem` TO the same parts in the host's own tree (`npx shadcn@latest add menubar`), or a `menubar` schema node.
43+
- FROM `NavigationMenuItem` TO the same part in the host's own tree (`npx shadcn@latest add navigation-menu`), or a `navigation-menu` schema node.
44+
- FROM `InputOTPGroup`, `InputOTPSeparator` TO the same parts in the host's own tree (`npx shadcn@latest add input-otp`), or an `input-otp` schema node.
45+
- FROM `CarouselItem` TO the same parts in the host's own tree (`npx shadcn@latest add carousel`), or a `carousel` schema node.
46+
- FROM `ItemMedia`, `ItemContent`, `ItemActions`, `ItemGroup`, `ItemSeparator`, `ItemTitle`, `ItemDescription`, `ItemHeader`, `ItemFooter` TO plain `div` / `p` elements with the classes you want inside `Item`, or the same parts in the host's own tree (`npx shadcn@latest add item`).
47+
- FROM `NativeSelect` TO a plain `select` element, or `Select`.
48+
- FROM `NativeSelectProps` TO `React.SelectHTMLAttributes<HTMLSelectElement>`, which it extended without adding a key.
49+
- FROM `ResizableHandleProps` TO `React.ComponentProps<typeof ResizableHandle>`, which it aliased.
50+
- FROM `useRelatedCount` TO `RelatedCountStore.get` with the same four arguments (object, relationship field, parent id, filter), guarding an absent object name yourself as the hook did (`objectName ? RelatedCountStore.get(objectName, relField, parentId, filter) : undefined`, since `get` takes `objectName: string`), read in a component that calls `useRelatedCountVersion()`, which re-renders it when the store changes.
51+
- FROM `mountedOperatorValue`, `retypeFilterValue`, `narrowFilterValueToOptions` TO `FilterBuilder`, which applies them to its rows, or `reshapeFilterValue` for the operator half.
52+
- FROM `CURRENCY_COMPANION_SUFFIX`, `currencyCompanionId`, `currencyCompanionOf`, `pairedCurrencyField` TO `isCurrencyCompanion` and `syncRecordCurrencyRows`, which pair and keep the currency rows.
53+
- FROM `KbdGroup` TO a `kbd` element with the classes `inline-flex items-center gap-1` around the `Kbd` elements.
54+
- FROM `isInsidePopperLayer`, `usePopperAwareInteractOutside` TO `MobileDialogContent`, which already keeps a dialog open when a click lands in a popover, menu or select layer.
55+
- FROM `SIDEBAR_WIDTH_FALLBACK`, `SIDEBAR_WIDTH_ICON_FALLBACK` TO the values they held, `16rem` and `3rem` (the fallbacks of the `--sidebar-width` and `--sidebar-width-icon` CSS variables).
56+
- FROM `useIsActiveListRecord`, `useScrollActiveListRecordIntoView`, `ActiveListRow`, `listRecordIdOf` TO `ActiveListRecordProvider` around a list this package draws: its data table marks and scrolls the active row itself.
57+
- FROM `DataLoadingState` TO `Spinner` or `Skeleton`, or `GridSkeleton` / `ListSkeleton` for a view.
58+
- FROM `DataLoadingStateProps` TO `React.ComponentProps<"div">` plus your own `message` prop.
59+
- FROM `NOTIFICATION_ACTION_BUTTON_VARIANTS`, `NOTIFICATION_POSITION_CLASSES`, `NOTIFICATION_SEVERITY_STYLES`, `notificationActionVariant`, `notificationIcon`, `notificationSeverityStyle`, `NotificationSeverityStyle` TO `NotificationBanners`, `NotificationSnackbar`, `NotificationAlerts` or `NotificationInline`, which style a notification by its severity and action variant themselves.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
'@objectstack/rest': patch
3+
'@objectstack/runtime': patch
4+
'@objectstack/metadata-protocol': patch
5+
'@objectstack/client': patch
6+
'@objectstack/spec': patch
7+
---
8+
9+
feat(rest)!: the metadata list reads several items by name in one request (`?names=a,b,c`), and refuses a query parameter it does not read
10+
11+
Clause-②: yes (narrowing) — `GET /api/v1/meta/:type` (and its environment-scoped twin, on both the REST server and the runtime dispatcher) declares its closed query-parameter set, `package`, `preview`, `object`, `include`, `id`, `names` and `locale`, and refuses any other name with `400 VALIDATION_ERROR`, where it ignored it and answered the whole list with `200`. The widening half: `?names=a,b,c` narrows every type's list but `package`'s to the items of those names, `@objectstack/client`'s `meta.getItems(type, { names })` sends it, and `@objectstack/rest` exports three new names, the list's query decision that both transports ask: `META_LIST_QUERY_PARAMS`, `metaListQueryRefusal` and `metaListNames`. Ruling 6580261740 assigns both halves to this one server change.
12+
Metadata-protocol: none
13+
14+
<!-- adr-0087: not-required (no-migration-prescription) No key of any schema is added, removed, renamed or re-shaped: `GetMetaItemsRequestSchema.names` was already declared, and only its description loses the planned marker. What moves is the list route's answer to a query-string name it never read, and nothing at rest records that answer, so there is nothing for a migration to rewrite. -->
15+
16+
**The batch by-names read.** `GET /api/v1/meta/:type?names=a,b,c` answers only the items of those names, among the items the list would answer without it, on every metadata type except `package`, whose items are keyed by id and carry no `name`: the `package` list refuses `?names=` with `400 VALIDATION_ERROR`. One comma-separated value, as the data routes spell `fields`; each name is trimmed and repeats count once. A name that matches no item is simply absent from the answer (no `404`). The names are handed to the store read (`GetMetaItemsRequest.names`), so `@objectstack/metadata-protocol`'s `getMetaItems` filters before it computes locks, governance and diagnostics, and the list's per-caller gate, object field mask and translation run on the named items only. A value that names no item (`?names=`, `?names=,`) is refused with `400 VALIDATION_ERROR` rather than read as every item; leave the key out to list every item. A repeated `?names=` is refused like the list's other single-valued parameters. Before, `?names=` was ignored, so a client that needed several objects paid one by-name request for each.
17+
18+
**BREAKING** accept-set narrowing at the metadata list (`@objectstack/rest`, `@objectstack/runtime`): a query parameter the list does not read is refused instead of ignored.
19+
20+
- **Before.** `GET /meta/object?name=account`, `?ids=a,b` or `?filter=x` answered `200` with every object, which reads the same as a filter that matched everything.
21+
- **Now.** A name outside `package`, `preview`, `object`, `include`, `id`, `names`, `locale` is refused with `400` and the nested `{ "error": { "code": "VALIDATION_ERROR", "message" } }` body; the message names the parameter and lists the supported ones, and nothing is read. A bracketed `?package[]=`, and `?id[]=` on the app list or `?object[]=` on the view list, keep their own located refusal; any other bracketed key (`?names[]=`) is refused as a name the list does not read.
22+
- **Who moves.** The Console and the client SDK send only declared names. A script that sends another name gets the 400.
23+
24+
**The remedy.** Drop the parameter, or spell it as one of the supported names: `?names=a,b` for several items by name, `?id=APP` for one app, `?object=OBJECT` for one object's views, `?package=ID` for one package.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
---
2+
'@object-ui/app-shell': patch
3+
'@object-ui/data-objectstack': patch
4+
---
5+
6+
fix(app-shell,data-objectstack): Studio's and Setup's object editors edit the object as its author wrote it, not as the console is served it
7+
8+
Clause-②: yes (widening)
9+
Metadata-protocol: none
10+
11+
- **`@object-ui/app-shell`:** the object editor in Studio's Data pillar and the one in Setup's metadata editor (`MetadataResourceEditPage` for `object`) now take their editable copy from the layered read's author-owned layers: the pending draft as stored (`draft`) when one is pending, otherwise `overlay ?? code`. Before, the copy was the `?state=draft` read (or `effective`), which arrives translated into the console's language and governed with the platform's injected columns (`owner_id`, `queue`, the audit and scope columns), so in a Chinese console one field edit saved the Chinese labels as the author's labels and sent the platform's columns back as the author's fields. What the editor shows of the served object stays as it was: the header's system-field count still counts the platform's columns, and the records grid still shows the served `owner_id` column. When a draft is pending but the layered read does not carry it, the editor installs nothing, shows the existing "draft unreadable" refusal, and sends nothing.
12+
- **`@object-ui/data-objectstack`:** `MetadataClient.layered()` passes through the `draft` layer the server serves (`MetadataLayered.draft`, optional). It used to drop it.
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
'@objectstack/spec': minor
3+
'@objectstack/objectql': minor
4+
'@objectstack/plugin-sharing': minor
5+
'@objectstack/cli': minor
6+
'@objectstack/platform-objects': minor
7+
---
8+
9+
feat(objectql,plugin-sharing): an organization authors its own assignment rules in Setup, as `sys_assignment_rule` records
10+
11+
Clause-②: yes (widening)
12+
Metadata-protocol: added
13+
Skills-docs: follow-up owed — content/docs/automation/queues-and-assignment-rules.mdx, skills/objectstack-automation/SKILL.md
14+
15+
Until now only a package could declare an assignment rule, so routing new records differently meant a package release. An organization can now write its own rules in Setup (Access Control → Assignment Rules), on the same two-source model sharing rules and queues already follow: the rules packages declare keep working, and the organization's own rules sit beside them.
16+
17+
- **`@objectstack/plugin-sharing`**: a new object, `sys_assignment_rule`. One row is one rule: when a new record of the chosen object matches the condition (a CEL expression over `record`, empty for every record), it goes to a queue or to one person, and a queue target may pick a member by `round_robin` or `least_loaded` (which needs its open-work expression, `load`). Each row belongs to one organization (`organization_id` is required). The table's save guard refuses, naming each field at fault: a name that is not snake_case or that a package rule already holds (one name means one rule); an object that does not exist or whose records have no owner; an entry shape the stack schema refuses for a declared rule; a condition or open-work expression the engine cannot compile; a person who is not an active member of the organization; a rule that would land in no organization. A boot report logs, at `error`, an organization's rule whose name a later-installed package now declares. Setup gains an "Assignment Rules" entry beside Queues.
18+
- **`@objectstack/objectql`**: the engine evaluates an object's organization rules first, ascending by `sort_order` and then by name, and the rules packages declare as the fallback; the first match decides. A user target, from either source, now owns the record only while the user is an active member of the record's organization and is not banned. One that no longer resolves leaves the record ownerless, the way a queue that no longer resolves does, and is logged once; the insert is never refused. When an organization's rules cannot be read, its new records are written as they stood rather than routed by the package rules its own would have overtaken. New exports for the save guard: `ASSIGNMENT_RULE_OBJECT`, `assignmentExpressionRefusals`, `organizationMemberStanding`.
19+
- **`@objectstack/spec`**: `PLATFORM_PROVIDED_OBJECT_NAMES` lists `sys_assignment_rule` under `plugin-sharing`, and the `AssignmentRuleSchema` documentation says how the two sources combine. No key, shape or validation changes.
20+
- **`@objectstack/platform-objects`**: the Setup app labels the new "Assignment Rules" navigation entry in English, Chinese, Japanese and Spanish.
21+
- **`@objectstack/cli`**: the organization-ownership inventory lists `sys_assignment_rule`, so `os migrate organization-ownership` plans it instead of refusing it as an uninventoried platform table.
22+
23+
Upgrading: a package rule whose entry names a user id (the `assignment-rule-user-target` lint warning) stops assigning in an organization where that user is not a member; the engine logs the lapse once per rule, user and organization. Route such a rule to a queue whose members are positions.

0 commit comments

Comments
 (0)