Skip to main content

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​

Loading CnObjectKanban playground…

Two rendering modes​

  • Pre-built columns — pass columns, the shape returned by OpenRegister's GET /api/views/{id}/kanban ([{ value, cards, total, limit, offset }]). The host owns pagination: clicking "load more" only emits load-more, and the host re-fetches and passes updated columns.
  • Flat objects — pass objects + groupByField (optionally columnOrder and schema). The component derives and paginates columns itself, using the same precedence as the backend (ViewPresentationService::deriveColumnValues()): explicit columnOrder > the property's schema enum order > distinct values discovered in objects.

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​

NameTypeRequiredDefaultDescription
objectsArray<object>[]Flat objects to derive columns from (ignored when columns is set).
columnsunionnullPre-built columns, e.g. the response of GET /api/views/{id}/kanban.
groupByFieldstring✓—The schema property whose distinct values become columns.
columnOrderarraynullExplicit column order. Takes precedence over the schema's enum order.
cardFieldsarray[]Object fields rendered on each card (in order).
schemaobjectnullSchema definition, used to resolve enum column order and card field types.
loadingbooleanfalseOverall loading state (initial board fetch).
loadingColumnsarray[]Column values currently loading more cards (drives the per-column spinner).
pageSizenumber20Cards shown per column before "load more", in local (objects-driven) mode.
rowKeystring'id'Object property used as each card's identity.
dueRule{field: string, soonDays?: number}&#124;nullnullMarks 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​

NamePayloadDescription
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​

NameBindingsDescription
empty—empty Custom empty state shown when there are no columns to render.
column-headercolumncolumn-header Override a column's header.
cardobject, column, dueStatecard Fully replace the default card rendering.

Methods​

NameDescription
resolveMoveConfirm a pending move succeeded — clears its pending visual state. The card already sits in the destination column (optimistic UI); no further mutation is needed.
rejectMoveRoll 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:

  1. Applies the move optimistically (the card renders in the destination column immediately).
  2. Emits move with { object, groupByField, fromValue, toValue }.
  3. 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 illegal x-openregister-lifecycle transition); the card snaps back to its origin column and move-rejected fires 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 configured cardFields entry via CnCellRenderer). dueState is overdue, soon, ok, or null without a dueRule, so a custom card can mark lateness the same way.