Skip to content

Upgrading 0.18 to 0.21

0.21.0 is released. These are the ### Breaking entries of its changelog section, one at a time, with what each one asks you to change. 0.19 and 0.20 declare no breaking change, so this is one hop from 0.18 — read it before you move to 0.21, not after.

Both are compile errors rather than silent changes of behaviour: the build points at every line that needs editing, and the grep under each section finds them before the build does.


31. context.client.data no longer compiles in a collection callback

Section titled “31. context.client.data no longer compiles in a collection callback”

RebaseCallContext["client"] is RebaseCallbackClient now: RebaseClient without data. Server-side that client is the rebase singleton, which has had no data since 0.18, so context.client.data.collection(…) compiled and then threw Cannot read properties of undefined (reading 'collection') on every call. It is a compile error instead.

What to change: query through context.data, the accessor a callback’s queries were always meant to use. It runs with the privilege of whatever triggered the callback, on the write’s own transaction. The callbacks guide covers what each accessor on the context can reach.

afterSave: async ({ context }) => {
await context.client.data.audit_logs.create({ action: "approved" });
await context.data.audit_logs.create({ action: "approved" });
}
grep -rn "client\.data\b" config

context.client.dataAsAdmin is still there for a callback that must see what an admin may see. admin.browserCallbacks changes too: the old spelling ran there, because the panel’s client carries data, and it stops compiling all the same. useRebaseContext().client in a React component keeps its data.

32. selectedEntities is gone: a selection is rows or a query

Section titled “32. selectedEntities is gone: a selection is rows or a query”

A collection view can now select every row that matches its filter, not only the rows it has loaded, so SelectionController no longer hands out an Entity[]. selectionController.selection is an EntitySelection union: { type: "entities", entities } for rows ticked by hand, or { type: "query", query, excluded, count? } for every row matching a query, most of which nobody has read.

What to change: a custom action that reads the selection turns it into rows with resolveSelection from @rebasepro/cms. It returns the ticked rows at once, and reads a query selection a page at a time — with an optional progress callback — throwing rather than returning a prefix when the query matches more than 20,000 rows.

const handlePublish = async () => {
for (const entity of selectionController.selectedEntities) {
const selected = await resolveSelection({
selection: selectionController.selection,
accessor: data.collection(path)
});
for (const entity of selected) {
await data.collection(entity.path).update(entity.id, { status: "published" });
}
};
grep -rn "selectedEntities" config frontend

Three smaller moves come with it:

  • selectionController.selectedEntities.lengthselectionController.selectedCount. It is undefined, never 0, when every row matching a query is selected and the collection cannot be counted — render that case, do not default it.
  • setSelectedEntities(prev => …)setSelection(prev => …), which receives and returns an EntitySelection. setSelectedEntities(rows) with an array still works.
  • A check for “is anything selected” is selectionController.hasSelection.

isEntitySelected and toggleEntitySelection are unchanged, and are what a per-row checkbox should keep using. The collection actions example shows the whole pattern.