From e13eb343c870bc54de9c21a2d9aae83ba9f1d468 Mon Sep 17 00:00:00 2001 From: Josh Rimes - Desktop Date: Wed, 2 Sep 2026 22:24:27 +0100 Subject: [PATCH 1/6] add button to expand column to width of view --- .../issue-layouts/kanban/base-kanban-root.tsx | 27 ++++++++++--- .../issues/issue-layouts/kanban/default.tsx | 14 ++++++- .../kanban/headers/group-by-card.tsx | 38 +++++++++++++------ 3 files changed, 60 insertions(+), 19 deletions(-) diff --git a/apps/web/core/components/issues/issue-layouts/kanban/base-kanban-root.tsx b/apps/web/core/components/issues/issue-layouts/kanban/base-kanban-root.tsx index 89715732c1f..f03212bef7d 100644 --- a/apps/web/core/components/issues/issue-layouts/kanban/base-kanban-root.tsx +++ b/apps/web/core/components/issues/issue-layouts/kanban/base-kanban-root.tsx @@ -105,7 +105,7 @@ export const BaseKanBanRoot = observer(function BaseKanBanRoot(props: IBaseKanBa fetchNextIssues(groupId, subgroupId); } }, - [fetchNextIssues] + [fetchNextIssues, issues] ); const groupedIssueIds = issues?.groupedIssueIds; @@ -130,9 +130,11 @@ export const BaseKanBanRoot = observer(function BaseKanBanRoot(props: IBaseKanBa const handleOnDrop = useGroupIssuesDragNDrop(storeType, orderBy, group_by, sub_group_by); const canEditProperties = useCallback( - (projectId: string | undefined) => { + (targetProjectId: string | undefined) => { const isEditingAllowedBasedOnProject = - canEditPropertiesBasedOnProject && projectId ? canEditPropertiesBasedOnProject(projectId) : isEditingAllowed; + canEditPropertiesBasedOnProject && targetProjectId + ? canEditPropertiesBasedOnProject(targetProjectId) + : isEditingAllowed; return enableInlineEditing && isEditingAllowedBasedOnProject; }, @@ -161,7 +163,11 @@ export const BaseKanBanRoot = observer(function BaseKanBanRoot(props: IBaseKanBa return combine( dropTargetForElements({ element, - getData: () => ({ columnId: "issue-trash-box", groupId: "issue-trash-box", type: "DELETE" }), + getData: () => ({ + columnId: "issue-trash-box", + groupId: "issue-trash-box", + type: "DELETE", + }), onDragEnter: () => { setIsDragOverDelete(true); }, @@ -231,7 +237,14 @@ export const BaseKanBanRoot = observer(function BaseKanBanRoot(props: IBaseKanBa [workspaceSlug, issuesFilter, projectId, updateFilters] ); - const collapsedGroups = issuesFilter?.issueFilters?.kanbanFilters || { group_by: [], sub_group_by: [] }; + const collapsedGroups = issuesFilter?.issueFilters?.kanbanFilters || { + group_by: [], + sub_group_by: [], + }; + const [expandedGroupId, setExpandedGroupId] = useState(); + const handleExpandedGroups = useCallback((_toggle: "group_by" | "sub_group_by", value: string) => { + setExpandedGroupId((currentGroupId) => (currentGroupId === value ? undefined : value)); + }, []); return ( <> @@ -265,7 +278,7 @@ export const BaseKanBanRoot = observer(function BaseKanBanRoot(props: IBaseKanBa ref={scrollableContainerRef} >
-
+
void; + expandedGroupId?: string; + handleExpandedGroups?: (toggle: "group_by" | "sub_group_by", value: string) => void; loadMoreIssues: (groupId?: string, subGroupId?: string) => void; enableQuickIssueCreate?: boolean; quickAddCallback?: (projectId: string | null | undefined, data: TIssue) => Promise; @@ -82,6 +84,8 @@ export const KanBan = observer(function KanBan(props: IKanBan) { quickActions, collapsedGroups, handleCollapsedGroups, + expandedGroupId, + handleExpandedGroups, enableQuickIssueCreate, quickAddCallback, loadMoreIssues, @@ -161,8 +165,12 @@ export const KanBan = observer(function KanBan(props: IKanBan) { return (
{sub_group_by === null && ( @@ -183,6 +191,8 @@ export const KanBan = observer(function KanBan(props: IKanBan) { addIssuesToView={addIssuesToView} collapsedGroups={collapsedGroups} handleCollapsedGroups={handleCollapsedGroups} + expandedGroupId={expandedGroupId} + handleExpandedGroups={handleExpandedGroups} isEpic={isEpic} />
diff --git a/apps/web/core/components/issues/issue-layouts/kanban/headers/group-by-card.tsx b/apps/web/core/components/issues/issue-layouts/kanban/headers/group-by-card.tsx index 044ba461405..b529b6f3e50 100644 --- a/apps/web/core/components/issues/issue-layouts/kanban/headers/group-by-card.tsx +++ b/apps/web/core/components/issues/issue-layouts/kanban/headers/group-by-card.tsx @@ -8,7 +8,7 @@ import React from "react"; import { observer } from "mobx-react"; import { useParams } from "next/navigation"; // lucide icons -import { Minimize2, Maximize2, Circle } from "lucide-react"; +import { Minimize2, Maximize2, Circle, UnfoldHorizontal, FoldHorizontal } from "lucide-react"; import { PlusIcon } from "@plane/propel/icons"; import { TOAST_TYPE, setToast } from "@plane/propel/toast"; import type { TIssue, ISearchIssueResponse, TIssueKanbanFilters, TIssueGroupByOptions } from "@plane/types"; @@ -30,6 +30,8 @@ interface IHeaderGroupByCard { count: number; collapsedGroups: TIssueKanbanFilters; handleCollapsedGroups: (toggle: "group_by" | "sub_group_by", value: string) => void; + handleExpandedGroups?: (toggle: "group_by" | "sub_group_by", value: string) => void; + expandedGroupId?: string; issuePayload: Partial; disableIssueCreation?: boolean; addIssuesToView?: (issueIds: string[]) => Promise; @@ -45,6 +47,8 @@ export const HeaderGroupByCard = observer(function HeaderGroupByCard(props: IHea count, collapsedGroups, handleCollapsedGroups, + handleExpandedGroups, + expandedGroupId, issuePayload, disableIssueCreation, addIssuesToView, @@ -136,16 +140,28 @@ export const HeaderGroupByCard = observer(function HeaderGroupByCard(props: IHea
{sub_group_by === null && ( - +
+ + +
)} {!disableIssueCreation && From b4a33fe6ae0c1daf96de8efa32f923b5fb1e517c Mon Sep 17 00:00:00 2001 From: Josh Rimes - Desktop Date: Wed, 2 Sep 2026 22:41:15 +0100 Subject: [PATCH 2/6] allow multi-column resizing --- .../issue-layouts/kanban/base-kanban-root.tsx | 17 ++++++++++++----- .../issues/issue-layouts/kanban/default.tsx | 8 ++++---- .../kanban/headers/group-by-card.tsx | 6 +++--- 3 files changed, 19 insertions(+), 12 deletions(-) diff --git a/apps/web/core/components/issues/issue-layouts/kanban/base-kanban-root.tsx b/apps/web/core/components/issues/issue-layouts/kanban/base-kanban-root.tsx index f03212bef7d..12e7330f08f 100644 --- a/apps/web/core/components/issues/issue-layouts/kanban/base-kanban-root.tsx +++ b/apps/web/core/components/issues/issue-layouts/kanban/base-kanban-root.tsx @@ -241,9 +241,16 @@ export const BaseKanBanRoot = observer(function BaseKanBanRoot(props: IBaseKanBa group_by: [], sub_group_by: [], }; - const [expandedGroupId, setExpandedGroupId] = useState(); + const [expandedGroupIds, setExpandedGroupIds] = useState>(new Set()); const handleExpandedGroups = useCallback((_toggle: "group_by" | "sub_group_by", value: string) => { - setExpandedGroupId((currentGroupId) => (currentGroupId === value ? undefined : value)); + setExpandedGroupIds((currentGroupIds) => { + const nextGroupIds = new Set(currentGroupIds); + + if (nextGroupIds.has(value)) nextGroupIds.delete(value); + else nextGroupIds.add(value); + + return nextGroupIds; + }); }, []); return ( @@ -277,8 +284,8 @@ export const BaseKanBanRoot = observer(function BaseKanBanRoot(props: IBaseKanBa className={`horizontal-scrollbar relative flex scrollbar-lg h-full w-full bg-surface-2 ${sub_group_by ? "vertical-scrollbar overflow-y-auto" : "overflow-x-auto overflow-y-hidden"}`} ref={scrollableContainerRef} > -
-
+
+
void; - expandedGroupId?: string; + expandedGroupIds?: ReadonlySet; handleExpandedGroups?: (toggle: "group_by" | "sub_group_by", value: string) => void; loadMoreIssues: (groupId?: string, subGroupId?: string) => void; enableQuickIssueCreate?: boolean; @@ -84,7 +84,7 @@ export const KanBan = observer(function KanBan(props: IKanBan) { quickActions, collapsedGroups, handleCollapsedGroups, - expandedGroupId, + expandedGroupIds, handleExpandedGroups, enableQuickIssueCreate, quickAddCallback, @@ -167,7 +167,7 @@ export const KanBan = observer(function KanBan(props: IKanBan) { key={subList.id} className={`group relative flex flex-col ${ groupByVisibilityToggle.showIssues - ? expandedGroupId === subList.id + ? expandedGroupIds?.has(subList.id) ? `min-w-[350px] flex-1` : `w-[350px] flex-shrink-0` : `` @@ -191,7 +191,7 @@ export const KanBan = observer(function KanBan(props: IKanBan) { addIssuesToView={addIssuesToView} collapsedGroups={collapsedGroups} handleCollapsedGroups={handleCollapsedGroups} - expandedGroupId={expandedGroupId} + expandedGroupIds={expandedGroupIds} handleExpandedGroups={handleExpandedGroups} isEpic={isEpic} /> diff --git a/apps/web/core/components/issues/issue-layouts/kanban/headers/group-by-card.tsx b/apps/web/core/components/issues/issue-layouts/kanban/headers/group-by-card.tsx index b529b6f3e50..dc6d05206e4 100644 --- a/apps/web/core/components/issues/issue-layouts/kanban/headers/group-by-card.tsx +++ b/apps/web/core/components/issues/issue-layouts/kanban/headers/group-by-card.tsx @@ -31,7 +31,7 @@ interface IHeaderGroupByCard { collapsedGroups: TIssueKanbanFilters; handleCollapsedGroups: (toggle: "group_by" | "sub_group_by", value: string) => void; handleExpandedGroups?: (toggle: "group_by" | "sub_group_by", value: string) => void; - expandedGroupId?: string; + expandedGroupIds?: ReadonlySet; issuePayload: Partial; disableIssueCreation?: boolean; addIssuesToView?: (issueIds: string[]) => Promise; @@ -48,7 +48,7 @@ export const HeaderGroupByCard = observer(function HeaderGroupByCard(props: IHea collapsedGroups, handleCollapsedGroups, handleExpandedGroups, - expandedGroupId, + expandedGroupIds, issuePayload, disableIssueCreation, addIssuesToView, @@ -145,7 +145,7 @@ export const HeaderGroupByCard = observer(function HeaderGroupByCard(props: IHea className="flex h-[20px] w-[20px] flex-shrink-0 cursor-pointer items-center justify-center overflow-hidden rounded-sm bg-layer-transparent transition-all hover:bg-layer-transparent-hover" onClick={() => handleExpandedGroups?.("group_by", column_id)} > - {expandedGroupId === column_id ? ( + {expandedGroupIds?.has(column_id) ? ( ) : ( From 557678b9fb173e27c9ca7971810b63e18e79a44b Mon Sep 17 00:00:00 2001 From: Josh Rimes - Desktop Date: Wed, 2 Sep 2026 22:51:31 +0100 Subject: [PATCH 3/6] change button position and visibility --- .../kanban/headers/group-by-card.tsx | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/apps/web/core/components/issues/issue-layouts/kanban/headers/group-by-card.tsx b/apps/web/core/components/issues/issue-layouts/kanban/headers/group-by-card.tsx index dc6d05206e4..6d76f26031d 100644 --- a/apps/web/core/components/issues/issue-layouts/kanban/headers/group-by-card.tsx +++ b/apps/web/core/components/issues/issue-layouts/kanban/headers/group-by-card.tsx @@ -140,17 +140,19 @@ export const HeaderGroupByCard = observer(function HeaderGroupByCard(props: IHea
{sub_group_by === null && ( -
- +
+ {!verticalAlignPosition && ( + + )}