From a7d390932dc73d25d44234639878b163aa2c86fd Mon Sep 17 00:00:00 2001 From: Philipinho <16838612+Philipinho@users.noreply.github.com> Date: Sun, 24 May 2026 15:53:49 +0100 Subject: [PATCH] feat(bases): hide and show kanban columns from header menu --- .../components/views/kanban/base-kanban.tsx | 96 ++++++++++++++++--- .../views/kanban/kanban-column-header.tsx | 22 ++++- .../components/views/kanban/kanban-column.tsx | 3 + 3 files changed, 107 insertions(+), 14 deletions(-) diff --git a/apps/client/src/features/base/components/views/kanban/base-kanban.tsx b/apps/client/src/features/base/components/views/kanban/base-kanban.tsx index 2460d9c87..66de3ec5e 100644 --- a/apps/client/src/features/base/components/views/kanban/base-kanban.tsx +++ b/apps/client/src/features/base/components/views/kanban/base-kanban.tsx @@ -1,4 +1,6 @@ import { useCallback, useMemo } from "react"; +import { Badge } from "@mantine/core"; +import { IconPlus } from "@tabler/icons-react"; import { IBase, IBaseRow, @@ -168,23 +170,91 @@ export function BaseKanban({ [base.id, columns, effectiveView, updateViewMutation], ); + const handleHideColumn = useCallback( + (columnKey: string) => { + if (!effectiveView) return; + const current = effectiveView.config?.hiddenChoiceIds ?? []; + if (current.includes(columnKey)) return; + updateViewMutation.mutate({ + viewId: effectiveView.id, + pageId: base.id, + config: { + ...effectiveView.config, + hiddenChoiceIds: [...current, columnKey], + }, + }); + }, + [base.id, effectiveView, updateViewMutation], + ); + + const handleShowColumn = useCallback( + (columnKey: string) => { + if (!effectiveView) return; + const next = (effectiveView.config?.hiddenChoiceIds ?? []).filter( + (id) => id !== columnKey, + ); + updateViewMutation.mutate({ + viewId: effectiveView.id, + pageId: base.id, + config: { ...effectiveView.config, hiddenChoiceIds: next }, + }); + }, + [base.id, effectiveView, updateViewMutation], + ); + + const hiddenIds = effectiveView?.config?.hiddenChoiceIds ?? []; + const hiddenChoices = useMemo(() => { + if (!isGroupable || hiddenIds.length === 0) return []; + const opts = (property!.typeOptions as { choices?: Array<{ id: string; name: string; color: string }> } | undefined) ?? {}; + const choices = opts.choices ?? []; + const byId = new Map(choices.map((c) => [c.id, c])); + return hiddenIds + .map((id) => + id === NO_VALUE_CHOICE_ID + ? { id, name: "No value", color: null as string | null } + : byId.get(id) + ? { id, name: byId.get(id)!.name, color: byId.get(id)!.color as string | null } + : null, + ) + .filter((c): c is { id: string; name: string; color: string | null } => c !== null); + }, [hiddenIds, isGroupable, property]); + if (!isGroupable) { return ; } return ( -
- {columns.map((column) => ( - - ))} -
+ <> + {hiddenChoices.length > 0 && ( +
+ {hiddenChoices.map((c) => ( + handleShowColumn(c.id)} + rightSection={} + > + {c.name} + + ))} +
+ )} +
+ {columns.map((column) => ( + + ))} +
+ ); } diff --git a/apps/client/src/features/base/components/views/kanban/kanban-column-header.tsx b/apps/client/src/features/base/components/views/kanban/kanban-column-header.tsx index 863581f87..a44708bb7 100644 --- a/apps/client/src/features/base/components/views/kanban/kanban-column-header.tsx +++ b/apps/client/src/features/base/components/views/kanban/kanban-column-header.tsx @@ -1,4 +1,6 @@ -import { Badge, Text } from "@mantine/core"; +import { ActionIcon, Badge, Menu, Text } from "@mantine/core"; +import { IconDots, IconEyeOff } from "@tabler/icons-react"; +import { useTranslation } from "react-i18next"; import { useKanbanColumnReorder, type ColumnReorderPayload, @@ -12,6 +14,7 @@ type KanbanColumnHeaderProps = { color: string | null; count: number; onReorderDrop: (payload: ColumnReorderPayload) => void; + onHide: (columnKey: string) => void; }; export function KanbanColumnHeader({ @@ -20,7 +23,9 @@ export function KanbanColumnHeader({ color, count, onReorderDrop, + onHide, }: KanbanColumnHeaderProps) { + const { t } = useTranslation(); const { ref, isDragging, closestEdge } = useKanbanColumnReorder({ columnKey, onDrop: onReorderDrop, @@ -43,6 +48,21 @@ export function KanbanColumnHeader({ )} {count} + + + + + + + + } + onClick={() => onHide(columnKey)} + > + {t("Hide group")} + + + {closestEdge && } ); diff --git a/apps/client/src/features/base/components/views/kanban/kanban-column.tsx b/apps/client/src/features/base/components/views/kanban/kanban-column.tsx index 52c798282..bc165a550 100644 --- a/apps/client/src/features/base/components/views/kanban/kanban-column.tsx +++ b/apps/client/src/features/base/components/views/kanban/kanban-column.tsx @@ -15,6 +15,7 @@ type KanbanColumnProps = { onAddCard: (columnKey: string) => void; onCardDrop: (payload: CardDropPayload) => void; onColumnReorder: (payload: ColumnReorderPayload) => void; + onHide: (columnKey: string) => void; }; export function KanbanColumn({ @@ -24,6 +25,7 @@ export function KanbanColumn({ onAddCard, onCardDrop, onColumnReorder, + onHide, }: KanbanColumnProps) { const { ref: bodyRef, isOver } = useKanbanColumnDrop({ columnKey: column.key, @@ -38,6 +40,7 @@ export function KanbanColumn({ color={column.color} count={column.rows.length} onReorderDrop={onColumnReorder} + onHide={onHide} />