diff --git a/apps/client/src/features/base/components/base-toolbar.tsx b/apps/client/src/features/base/components/base-toolbar.tsx
index 953c50bd6..38582b280 100644
--- a/apps/client/src/features/base/components/base-toolbar.tsx
+++ b/apps/client/src/features/base/components/base-toolbar.tsx
@@ -21,6 +21,8 @@ import { ViewTabs } from "@/features/base/components/views/view-tabs";
import { ViewSortConfigPopover } from "@/features/base/components/views/view-sort-config";
import { ViewFilterConfigPopover } from "@/features/base/components/views/view-filter-config";
import { ViewFieldVisibility } from "@/features/base/components/views/view-field-visibility";
+import { KanbanGroupByPicker } from "@/features/base/components/views/kanban/kanban-group-by-picker";
+import { useUpdateViewMutation } from "@/features/base/queries/base-view-query";
import { useTranslation } from "react-i18next";
import classes from "@/features/base/styles/grid.module.css";
@@ -136,6 +138,21 @@ export function BaseToolbar({
return cols.filter((col) => col.getCanHide() && !col.getIsVisible()).length;
}, [table, table.getState().columnVisibility]);
+ const updateViewMutation = useUpdateViewMutation();
+ const isKanban = activeView?.type === "kanban";
+
+ const handleGroupByChange = useCallback(
+ (propertyId: string) => {
+ if (!activeView) return;
+ updateViewMutation.mutate({
+ viewId: activeView.id,
+ pageId: base.id,
+ config: { ...activeView.config, groupByPropertyId: propertyId },
+ });
+ },
+ [activeView, base.id, updateViewMutation],
+ );
+
const handleSortsChange = useCallback(
(newSorts: ViewSortConfig[]) => {
// Normalize empty to undefined so the draft hook can drop the `sorts`
@@ -168,6 +185,15 @@ export function BaseToolbar({
onAddView={onAddView}
/>
+ {isKanban && (
+