From cd8c0b4a63588bd7f7c5ab506cbe6c1552200e93 Mon Sep 17 00:00:00 2001
From: Philipinho <16838612+Philipinho@users.noreply.github.com>
Date: Thu, 2 Jul 2026 14:28:51 +0100
Subject: [PATCH] feat: edit group-by property from kanban column menu
---
.../kanban/kanban-column-header.tsx | 18 +--
.../components/kanban/kanban-column-menu.tsx | 119 ++++++++++++++++++
2 files changed, 125 insertions(+), 12 deletions(-)
create mode 100644 apps/client/src/ee/base/components/kanban/kanban-column-menu.tsx
diff --git a/apps/client/src/ee/base/components/kanban/kanban-column-header.tsx b/apps/client/src/ee/base/components/kanban/kanban-column-header.tsx
index 99248e7e9..830a00a16 100644
--- a/apps/client/src/ee/base/components/kanban/kanban-column-header.tsx
+++ b/apps/client/src/ee/base/components/kanban/kanban-column-header.tsx
@@ -1,13 +1,14 @@
import { useRef } from "react";
import { useTranslation } from "react-i18next";
-import { ActionIcon, Menu, Text } from "@mantine/core";
-import { IconDots, IconPlus, IconGripVertical } from "@tabler/icons-react";
+import { ActionIcon, Text } from "@mantine/core";
+import { IconPlus, IconGripVertical } from "@tabler/icons-react";
import clsx from "clsx";
import { IBaseProperty, KanbanColumn } from "@/ee/base/types/base.types";
import { choiceColor } from "@/ee/base/components/cells/choice-color";
import { useKanbanColumnDnd } from "@/ee/base/hooks/use-kanban-column-dnd";
import { BaseDropEdgeIndicator } from "@/ee/base/components/grid/base-drop-edge-indicator";
import { KanbanColumnTitle } from "@/ee/base/components/kanban/kanban-column-title";
+import { KanbanColumnMenu } from "@/ee/base/components/kanban/kanban-column-menu";
import classes from "@/ee/base/styles/kanban.module.css";
type KanbanColumnHeaderProps = {
@@ -55,16 +56,9 @@ export function KanbanColumnHeader({ column, pageId, property, count, canEdit, o
{count !== undefined && {count}}
{canEdit && (
<>
-
+ {property && (
+
+ )}
diff --git a/apps/client/src/ee/base/components/kanban/kanban-column-menu.tsx b/apps/client/src/ee/base/components/kanban/kanban-column-menu.tsx
new file mode 100644
index 000000000..be2e88f76
--- /dev/null
+++ b/apps/client/src/ee/base/components/kanban/kanban-column-menu.tsx
@@ -0,0 +1,119 @@
+import { useCallback, useEffect, useRef, useState } from "react";
+import { useTranslation } from "react-i18next";
+import { ActionIcon, Popover, Stack } from "@mantine/core";
+import { IconDots, IconEyeOff, IconSettings } from "@tabler/icons-react";
+import { useAtom } from "jotai";
+import {
+ propertyMenuCloseRequestAtomFamily,
+ propertyMenuDirtyAtomFamily,
+} from "@/ee/base/atoms/base-atoms";
+import { IBaseProperty } from "@/ee/base/types/base.types";
+import {
+ MenuItem,
+ PropertyMenuContent,
+} from "@/ee/base/components/property/property-menu";
+
+type KanbanColumnMenuProps = {
+ property: IBaseProperty;
+ pageId: string;
+ onHide: () => void;
+};
+
+export function KanbanColumnMenu({ property, pageId, onHide }: KanbanColumnMenuProps) {
+ const { t } = useTranslation();
+ const [opened, setOpened] = useState(false);
+ const [view, setView] = useState<"menu" | "property">("menu");
+ const [dirty, setDirty] = useAtom(propertyMenuDirtyAtomFamily(pageId)) as unknown as [boolean, (val: boolean) => void];
+ const [closeRequest, setCloseRequest] = useAtom(propertyMenuCloseRequestAtomFamily(pageId)) as unknown as [number, (val: number) => void];
+
+ const handleClose = useCallback(() => {
+ setOpened(false);
+ setView("menu");
+ }, []);
+
+ const wasOpenedRef = useRef(opened);
+ useEffect(() => {
+ if (wasOpenedRef.current && !opened) setDirty(false);
+ wasOpenedRef.current = opened;
+ }, [opened, setDirty]);
+
+ const handleOpenChange = useCallback(
+ (next: boolean) => {
+ if (next) return;
+ if (dirty) {
+ setCloseRequest(closeRequest + 1);
+ } else {
+ handleClose();
+ }
+ },
+ [dirty, closeRequest, setCloseRequest, handleClose],
+ );
+
+ const toggle = useCallback(() => {
+ if (opened) {
+ handleOpenChange(false);
+ } else if (!dirty) {
+ setOpened(true);
+ }
+ }, [opened, dirty, handleOpenChange]);
+
+ return (
+
+
+
+
+
+
+ e.stopPropagation()}
+ onKeyDown={(e) => e.stopPropagation()}
+ >
+ {view === "menu" ? (
+
+ }
+ label={t("Edit property")}
+ onClick={() => setView("property")}
+ />
+ }
+ label={t("Hide group")}
+ onClick={() => {
+ handleClose();
+ onHide();
+ }}
+ />
+
+ ) : (
+
+ )}
+
+
+ );
+}