feat(bases): add per-column '+ New' button to kanban

This commit is contained in:
Philipinho
2026-05-24 13:51:20 +01:00
parent 76ca68bec6
commit a9c6051d12
3 changed files with 52 additions and 0 deletions
@@ -3,9 +3,11 @@ import {
IBase,
IBaseRow,
IBaseView,
NO_VALUE_CHOICE_ID,
} from "@/features/base/types/base.types";
import { useKanbanGroups } from "@/features/base/hooks/use-kanban-groups";
import { useUpdateViewMutation } from "@/features/base/queries/base-view-query";
import { useCreateRowMutation } from "@/features/base/queries/base-row-query";
import { KanbanColumn } from "./kanban-column";
import { KanbanEmptyState } from "./kanban-empty-state";
import classes from "@/features/base/styles/kanban.module.css";
@@ -37,6 +39,7 @@ export function BaseKanban({
);
const isGroupable = property?.type === "select" || property?.type === "status";
const updateViewMutation = useUpdateViewMutation();
const createRowMutation = useCreateRowMutation();
// Rules of Hooks: call useKanbanGroups unconditionally with `undefined`
// when not groupable; switch the render path on isGroupable below.
@@ -56,6 +59,21 @@ export function BaseKanban({
});
};
const handleAddCard = (columnKey: string) => {
if (!groupByPropertyId) return;
const cells =
columnKey === NO_VALUE_CHOICE_ID
? {}
: { [groupByPropertyId]: columnKey };
const column = columns.find((c) => c.key === columnKey);
const afterRowId = column?.rows[column.rows.length - 1]?.id;
createRowMutation.mutate({
pageId: base.id,
cells,
afterRowId,
});
};
if (!isGroupable) {
return <KanbanEmptyState base={base} onPick={handlePickProperty} />;
}
@@ -68,6 +86,7 @@ export function BaseKanban({
column={column}
primaryProperty={primaryProperty}
onCardClick={onCardClick}
onAddCard={handleAddCard}
/>
))}
</div>
@@ -0,0 +1,29 @@
import { Button } from "@mantine/core";
import { IconPlus } from "@tabler/icons-react";
import { useTranslation } from "react-i18next";
import classes from "@/features/base/styles/kanban.module.css";
type KanbanAddCardButtonProps = {
onClick: () => void;
disabled?: boolean;
};
export function KanbanAddCardButton({
onClick,
disabled,
}: KanbanAddCardButtonProps) {
const { t } = useTranslation();
return (
<Button
variant="subtle"
color="gray"
size="xs"
className={classes.addCardButton}
leftSection={<IconPlus size={14} />}
onClick={onClick}
disabled={disabled}
>
{t("New")}
</Button>
);
}
@@ -2,18 +2,21 @@ import { KanbanColumnData } from "@/features/base/hooks/use-kanban-groups";
import { IBaseProperty } from "@/features/base/types/base.types";
import { KanbanCard } from "./kanban-card";
import { KanbanColumnHeader } from "./kanban-column-header";
import { KanbanAddCardButton } from "./kanban-add-card-button";
import classes from "@/features/base/styles/kanban.module.css";
type KanbanColumnProps = {
column: KanbanColumnData;
primaryProperty: IBaseProperty | undefined;
onCardClick: (rowId: string) => void;
onAddCard: (columnKey: string) => void;
};
export function KanbanColumn({
column,
primaryProperty,
onCardClick,
onAddCard,
}: KanbanColumnProps) {
return (
<div className={classes.column} data-column-key={column.key}>
@@ -31,6 +34,7 @@ export function KanbanColumn({
onClick={onCardClick}
/>
))}
<KanbanAddCardButton onClick={() => onAddCard(column.key)} />
</div>
</div>
);