# useDocyrusKanban URL: /docs/web/hooks/use-docyrus-kanban One-call wiring of a Docyrus data source to a fully configured Kanban board with select/status/radio-group, user, and date columns, drag-to-update persistence, final-zone integration, and a standard Docyrus card layout. ## Installation ```bash pnpm dlx @docyrus/cli add @docyrus/hooks-use-docyrus-kanban ``` **Dependencies:** - [@docyrus/app-utils](https://www.npmjs.com/package/@docyrus/app-utils) - [@docyrus/api-client](https://www.npmjs.com/package/@docyrus/api-client) - [@tanstack/react-query](https://tanstack.com/query/latest) - [@dnd-kit/core](https://www.npmjs.com/package/@dnd-kit/core) - [@dnd-kit/sortable](https://www.npmjs.com/package/@dnd-kit/sortable) - [react-querybuilder](https://react-querybuilder.js.org) This hook is distributed as source. It expects an authenticated `RestApiClient` from `@docyrus/api-client` and a `QueryClientProvider` from `@tanstack/react-query` somewhere above your component tree. ## Overview `useDocyrusKanban` is the kanban-first companion to [`useDocyrusDataGrid`](/docs/web/hooks/use-docyrus-data-grid). It wires a Docyrus data source to a fully configured ` | Option | Type | Default | Description | |--------|------|---------|-------------| | `groupByFieldSlug` | `string` | — | **Required.** Slug of the field whose values become kanban columns. | | `data` | `Array` | — | Pre-resolved rows. When provided, the hook skips its internal items query. | | `collection` | `DocyrusKanbanCollection` | — | TanStack DB collection. Optional `update` and `remove` methods are wired to drag-move and the default delete action. | | `listParams` | `DocyrusKanbanListParams` | — | Extra query params merged on top of the view-derived payload. | | `defaultLimit` | `number` | `200` | Default page size when no `limit` is supplied via `listParams`. | | `enableItemsQuery` | `boolean` | `true` when no `data` | Toggle the internal items query. | | `dateGroupBy` | `'day' \| 'week' \| 'month'` | `'day'` | Initial date bucket granularity. The toolbar switch overrides this at runtime. | | `userGroupBy` | `'user' \| 'team'` | `'user'` | Initial user grouping mode for `field-userSelect`. | | `showAllColumns` | `boolean` | `true` | Initial state of the "Show all" switch (enum group-by only). | | `avatarColumn` | `string` | — | Field slug bound to the card avatar (icon/color/image). | | `titleColumn` | `string` | — | Field slug bound to the card title. | | `descriptionColumn` | `string` | — | Field slug bound to the card description. | | `userColumn` | `string` | — | Field slug bound to the user shown in the card footer. | | `cardContent` | `(ctx) => ReactNode` | — | Free-form card body. Receives `{ row, column }`. | | `cardMenuItems` | `Array>` \| `(row, defaults) => Array<...>` | — | Override the action menu. The function form keeps the default Open/Edit/Delete entries available. | | `cardActions` | `Array<'open' \| 'edit' \| 'delete'>` | `['open', 'edit', 'delete']` | Whitelist of the default actions. | | `onCardOpen` | `(row) => void` | — | Wired to the default **Open** menu item. | | `onCardEdit` | `(row) => void` | — | Wired to the default **Edit** menu item. | | `onCardDelete` | `(row) => Promise \| void` | — | Custom delete handler. When omitted the hook calls `collection.remove(id)` or `DELETE /items/:id` after a confirmation dialog. | | `onCardClick` | `(row) => void` | — | Click handler fired when the card body is clicked. | | `enableViewSelect` | `boolean` | `true` | Show the saved-view picker in the toolbar. | | `enableSearchInput` | `boolean` | `true` | Show the search input. | | `enableDateGroupMenu` | `boolean` | `true` | Show the Day/Week/Month picker when grouping by date. | | `enableUserGroupMenu` | `boolean` | `true` | Show the User/Team picker when grouping by user. | | `enableShowAllColumnsSwitch` | `boolean` | `true` | Show the "Show all" switch when grouping by enum. | | `enableReloadButton` | `boolean` | `true` | Show the reload button. | | `onReload` | `() => void` | — | Called when the reload button is clicked, after the internal `refetch`. | | `searchPlaceholder` | `string` | `'Search…'` | Placeholder for the toolbar search input. | | `searchDebounceMs` | `number` | `300` | Debounce in ms before the search input is sent as `filterKeyword`. | | `toolbarClassName` | `string` | — | Extra className for the toolbar root. | | `toolbarStartContent` | `ReactNode` | — | Extra node prepended to the left side of the toolbar. | | `toolbarEndContent` | `ReactNode` | — | Extra node appended to the right side of the toolbar. | | `onItemMove` | `(params) => void` | — | Fired when a card is dropped into a different column. Runs alongside the built-in mutation. | | `onItemMoveCommit` | `(params) => Promise \| void` | — | Replace the built-in `PATCH` with a custom handler. Throw to abort the move. | ### Return Value | Property | Type | Description | |----------|------|-------------| | `toolbar` | `ReactNode` | Pre-wired toolbar element ready to render above the board. | | `board` | `ReactNode` | Pre-wired kanban board element. Render directly. | | `items` | `Array` | Resolved rows passed to the board. | | `resolvedListParams` | `DocyrusKanbanListParams` | The list params actually sent to the backend. | | `groupByField` | `DataSourceField \| undefined` | The field metadata used to derive columns. | | `columns` | `Array` | Ordered metadata for every rendered column (including counts). | | `columnsItems` | `Record>` | Items grouped by `column.id`. | | `dateGroupBy` | `'day' \| 'week' \| 'month'` | Active date grouping. | | `setDateGroupBy` | `(value) => void` | Programmatically switch date grouping. | | `userGroupBy` | `'user' \| 'team'` | Active user grouping. | | `setUserGroupBy` | `(value) => void` | Programmatically switch user grouping. | | `showAllColumns` | `boolean` | Active state of the "Show all" switch. | | `setShowAllColumns` | `(value) => void` | Programmatically toggle the switch. | | `views` | `Array` | Saved views mapped from the backend shape. | | `fields` | `Array` | Fields mapped for `react-querybuilder`. | | `dataSource` | `DataSource \| undefined` | Raw data source metadata response. | | `activeViewId` | `string` | Id of the currently active view. | | `setActiveViewId` | `(viewId) => void` | Programmatically switch views. | | `reload` | `() => void` | Triggers refetch of the data source, views, and items queries plus the optional `onReload` callback. | | `isLoading` | `boolean` | `true` until all queries have resolved. | | `error` | `Error \| null` | First error from any of the queries. | | `refetch` | `() => void` | Alias for `reload`. | ## Drag-and-drop persistence When a card is dropped into a different column the hook computes a payload based on the field type and either: - calls `collection.update(id, payload)` if the consumer passed a TanStack DB collection with an `update` method, **or** - issues a `PATCH /v1/apps/:appSlug/data-sources/:dataSourceSlug/items/:id` with the `RestApiClient` from `@docyrus/signin`. | Group-by field | Payload sent on drop | |----------------|----------------------| | `field-select`, `field-radioGroup`, `field-status` | `{ [fieldSlug]: }` | | `field-userSelect` (`userGroupBy: 'user'`) | `{ [fieldSlug]: }` | | `field-userSelect` (`userGroupBy: 'team'`) | _(no-op — teams aren't writable on the user reference)_ | | `field-date`, `field-dateTime` | _(no-op — bucketing is derived, not stored)_ | Pass `onItemMoveCommit` to skip the built-in `PATCH` entirely (e.g. for optimistic updates with rollback) and `onItemMove` to mirror the change in local state without replacing the mutation. ## Field type → column derivation matrix | Docyrus `type` | Column id | Column label | Color/icon source | Final-zone integration | |----------------|-----------|--------------|-------------------|-------------------------| | `field-select` | enum option `id` (or `slug`) | enum option `name` | enum option `color` / `icon` | — | | `field-radioGroup` | enum option `id` (or `slug`) | enum option `name` | enum option `color` / `icon` | — | | `field-status` | enum option `id` (or `slug`) | enum option `name` | enum option `color` / `icon` | options where `is_final_option === true` | | `field-userSelect` (user) | user id | full name (or email) | user `photo` | — | | `field-userSelect` (team) | team id | team `name` | — | — | | `field-date`, `field-dateTime` | bucket key (`YYYY-MM-DD` / `YYYY-Www` / `YYYY-MM`) | localized label | — | — | ### Out of scope - `field-relation`, `field-multiSelect`, and `field-tagSelect` are intentionally not surfaced as group-by candidates — relation fields would require additional metadata to render meaningful column headers and multi-value fields don't map cleanly onto a single column. If you need to group by one of these, render your own board with the same `useDocyrusDataViewSelect` wiring.