CnObjectKanban
Kanban board over a schema property's distinct values — one column per value
of groupByField, cards paginated per column ("load more"), and drag-to-move
wired to the host's own object write (there is deliberately no bespoke "move
card" endpoint).
Wraps: CnCellRenderer, vuedraggable
Try it
Two rendering modes
- Pre-built columns — pass
columns, the shape returned by OpenRegister'sGET /api/views/{id}/kanban([{ value, cards, total, limit, offset }]). The host owns pagination: clicking "load more" only emitsload-more, and the host re-fetches and passes updatedcolumns. - Flat objects — pass
objects+groupByField(optionallycolumnOrderandschema). The component derives and paginates columns itself, using the same precedence as the backend (ViewPresentationService::deriveColumnValues()): explicitcolumnOrder> the property's schemaenumorder > distinct values discovered inobjects.
Props
OpenRegister reliance
medium: this component relies on OpenRegister for part of what it does. 0 direct references, 8 files reached through imports.
Through: CnFkResolveCell, CnIndexPage.
See the reliance overview for the filterable list.
Props
| Name | Type | Required | Default | Description |
|---|---|---|---|---|
objects | Array<object> | [] | Flat objects to derive columns from (ignored when columns is set). | |
columns | union | null | Pre-built columns, e.g. the response of GET /api/views/{id}/kanban. | |
groupByField | string | ✓ | — | The schema property whose distinct values become columns. |
columnOrder | array | null | Explicit column order. Takes precedence over the schema's enum order. | |
cardFields | array | [] | Object fields rendered on each card (in order). | |
schema | object | null | Schema definition, used to resolve enum column order and card field types. | |
loading | boolean | false | Overall loading state (initial board fetch). | |
loadingColumns | array | [] | Column values currently loading more cards (drives the per-column spinner). | |
pageSize | number | 20 | Cards shown per column before "load more", in local (objects-driven) mode. | |
rowKey | string | 'id' | Object property used as each card's identity. | |
dueRule | {field: string, soonDays?: number}|null | null | Marks late cards: { field, soonDays? }. field is the dot-path to a card's due date. A date before today gets an error edge and the label "Overdue"; a date within soonDays (default 3) gets "Due soon" in the warning colour. null (the default) marks nothing. The same rule shape the table's date cell uses, so a list and its board agree on what late means. |
Events
| Name | Payload | Description |
|---|---|---|
card-click | — | Emitted when a card is clicked (not dragged). |
load-more | — | Emitted when a column's "load more" is clicked. |
move | — | Emitted after a card is optimistically moved to another column. The host performs the actual object write through the existing guarded PATCH/PUT endpoint and calls resolveMove/ rejectMove on this component to confirm or roll back. |
move-rejected | — | Emitted after rejectMove() rolls a card back to its origin column. |
Slots
| Name | Bindings | Description |
|---|---|---|
empty | — | empty Custom empty state shown when there are no columns to render. |
column-header | column | column-header Override a column's header. |
card | object, column, dueState | card Fully replace the default card rendering. |
Methods
| Name | Description |
|---|---|
resolveMove | Confirm a pending move succeeded — clears its pending visual state. The card already sits in the destination column (optimistic UI); no further mutation is needed. |
rejectMove | Roll back a rejected move: the card returns to its origin column and move-rejected fires with the server's reason. |
Besides objects/columns/groupByField/columnOrder/cardFields/schema
above: loading shows the board-level loading state; loadingColumns marks
which column values are currently fetching a "load more" page (per-column
spinner); pageSize sets how many cards a locally-derived column shows
before "load more"; rowKey is the object property used as each card's
identity (defaults to id).
dueRule marks late cards: { field, soonDays? }, where field is the
dot-path to a card's due date. A date before today gets an edge in the error
colour and the label "Overdue". A date within soonDays (default 3) gets the
label "Due soon". The label is text, so the state does not depend on colour.
Same rule as CnBoardView. Without it, cards
render as before.
<CnObjectKanban
:objects="objects"
group-by-field="status"
:due-rule="{ field: 'deadline', soonDays: 3 }" />
Drag-to-move contract
Dragging a card to another column does not write anything by itself. The component:
- Applies the move optimistically (the card renders in the destination column immediately).
- Emits
movewith{ object, groupByField, fromValue, toValue }. - Waits for the host to call back:
resolveMove(objectId)— the write succeeded; clears the pending state.rejectMove(objectId, reason)— the write was rejected (e.g. an illegalx-openregister-lifecycletransition); the card snaps back to its origin column andmove-rejectedfires with the reason to surface.
<CnObjectKanban
ref="kanban"
:objects="objects"
group-by-field="status"
:column-order="['todo', 'doing', 'done']"
:card-fields="['title', 'assignee']"
:schema="schema"
@move="onMove"
@move-rejected="onMoveRejected"
@load-more="fetchMoreCards" />
async onMove({ object, groupByField, toValue }) {
try {
await patchObject(object.id, { [groupByField]: toValue })
// Optional — clears the pending style sooner than the next refetch:
this.$refs.kanban.resolveMove(object.id)
} catch (e) {
this.$refs.kanban.rejectMove(object.id, e.message)
}
},
onMoveRejected({ reason }) {
showError(reason)
},
Slots
#empty— custom empty state when there are no columns.#column-header="{ column }"— override a column's header.#card="{ object, column, dueState }"— fully replace the default card rendering (the default renders a title plus each configuredcardFieldsentry viaCnCellRenderer).dueStateisoverdue,soon,ok, ornullwithout adueRule, so a custom card can mark lateness the same way.