[WEB-5599] refactor: enhance Kanban swimlane components with improved props and structure (#8262)

This commit is contained in:
Prateek Shourya 2025-12-08 18:17:29 +05:30 committed by GitHub
parent f41e121e58
commit 316856a555
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -1,5 +1,6 @@
import type { MutableRefObject } from "react"; import type { MutableRefObject } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
// plane imports
import type { import type {
GroupByColumnTypes, GroupByColumnTypes,
IGroupByColumn, IGroupByColumn,
@ -12,33 +13,32 @@ import type {
TIssueGroupByOptions, TIssueGroupByOptions,
TIssueOrderByOptions, TIssueOrderByOptions,
} from "@plane/types"; } from "@plane/types";
// UI
import { Row } from "@plane/ui"; import { Row } from "@plane/ui";
// hooks // hooks
import { useIssueStoreType } from "@/hooks/use-issue-layout-store"; import { useIssueStoreType } from "@/hooks/use-issue-layout-store";
// components // plane web imports
import { useWorkFlowFDragNDrop } from "@/plane-web/components/workflow"; import { useWorkFlowFDragNDrop } from "@/plane-web/components/workflow";
// local imports
import type { TRenderQuickActions } from "../list/list-view-types"; import type { TRenderQuickActions } from "../list/list-view-types";
import type { GroupDropLocation } from "../utils"; import type { GroupDropLocation } from "../utils";
import { getGroupByColumns, isWorkspaceLevel } from "../utils"; import { getGroupByColumns, isWorkspaceLevel } from "../utils";
import { KanBan } from "./default"; import { KanBan } from "./default";
import { HeaderGroupByCard } from "./headers/group-by-card"; import { HeaderGroupByCard } from "./headers/group-by-card";
import { HeaderSubGroupByCard } from "./headers/sub-group-by-card"; import { HeaderSubGroupByCard } from "./headers/sub-group-by-card";
// types
// constants
interface ISubGroupSwimlaneHeader { interface ISubGroupSwimlaneHeader {
collapsedGroups: TIssueKanbanFilters;
group_by: TIssueGroupByOptions | undefined;
getGroupIssueCount: ( getGroupIssueCount: (
groupId: string | undefined, groupId: string | undefined,
subGroupId: string | undefined, subGroupId: string | undefined,
isSubGroupCumulative: boolean isSubGroupCumulative: boolean
) => number | undefined; ) => number | undefined;
sub_group_by: TIssueGroupByOptions | undefined;
group_by: TIssueGroupByOptions | undefined;
list: IGroupByColumn[];
collapsedGroups: TIssueKanbanFilters;
handleCollapsedGroups: (toggle: "group_by" | "sub_group_by", value: string) => void; handleCollapsedGroups: (toggle: "group_by" | "sub_group_by", value: string) => void;
isEpic?: boolean;
list: IGroupByColumn[];
showEmptyGroup: boolean; showEmptyGroup: boolean;
sub_group_by: TIssueGroupByOptions | undefined;
} }
const visibilitySubGroupByGroupCount = (subGroupIssueCount: number, showEmptyGroup: boolean): boolean => { const visibilitySubGroupByGroupCount = (subGroupIssueCount: number, showEmptyGroup: boolean): boolean => {
@ -54,13 +54,14 @@ const visibilitySubGroupByGroupCount = (subGroupIssueCount: number, showEmptyGro
}; };
const SubGroupSwimlaneHeader = observer(function SubGroupSwimlaneHeader({ const SubGroupSwimlaneHeader = observer(function SubGroupSwimlaneHeader({
getGroupIssueCount,
sub_group_by,
group_by,
list,
collapsedGroups, collapsedGroups,
getGroupIssueCount,
group_by,
handleCollapsedGroups, handleCollapsedGroups,
isEpic = false,
list,
showEmptyGroup, showEmptyGroup,
sub_group_by,
}: ISubGroupSwimlaneHeader) { }: ISubGroupSwimlaneHeader) {
const { getIsWorkflowWorkItemCreationDisabled } = useWorkFlowFDragNDrop(group_by, sub_group_by); const { getIsWorkflowWorkItemCreationDisabled } = useWorkFlowFDragNDrop(group_by, sub_group_by);
@ -88,6 +89,7 @@ const SubGroupSwimlaneHeader = observer(function SubGroupSwimlaneHeader({
handleCollapsedGroups={handleCollapsedGroups} handleCollapsedGroups={handleCollapsedGroups}
issuePayload={_list.payload} issuePayload={_list.payload}
disableIssueCreation={getIsWorkflowWorkItemCreationDisabled(_list.id)} disableIssueCreation={getIsWorkflowWorkItemCreationDisabled(_list.id)}
isEpic={isEpic}
/> />
</div> </div>
); );
@ -97,53 +99,55 @@ const SubGroupSwimlaneHeader = observer(function SubGroupSwimlaneHeader({
}); });
interface ISubGroupSwimlane extends ISubGroupSwimlaneHeader { interface ISubGroupSwimlane extends ISubGroupSwimlaneHeader {
issuesMap: IIssueMap; addIssuesToView?: (issueIds: string[]) => Promise<TIssue>;
groupedIssueIds: TGroupedIssues | TSubGroupedIssues; canEditProperties: (projectId: string | undefined) => boolean;
collapsedGroups: TIssueKanbanFilters;
disableIssueCreation?: boolean;
displayProperties: IIssueDisplayProperties | undefined;
enableQuickIssueCreate: boolean;
getGroupIssueCount: ( getGroupIssueCount: (
groupId: string | undefined, groupId: string | undefined,
subGroupId: string | undefined, subGroupId: string | undefined,
isSubGroupCumulative: boolean isSubGroupCumulative: boolean
) => number | undefined; ) => number | undefined;
showEmptyGroup: boolean; groupedIssueIds: TGroupedIssues | TSubGroupedIssues;
displayProperties: IIssueDisplayProperties | undefined;
updateIssue: ((projectId: string | null, issueId: string, data: Partial<TIssue>) => Promise<void>) | undefined;
quickActions: TRenderQuickActions;
collapsedGroups: TIssueKanbanFilters;
handleCollapsedGroups: (toggle: "group_by" | "sub_group_by", value: string) => void; handleCollapsedGroups: (toggle: "group_by" | "sub_group_by", value: string) => void;
handleOnDrop: (source: GroupDropLocation, destination: GroupDropLocation) => Promise<void>; handleOnDrop: (source: GroupDropLocation, destination: GroupDropLocation) => Promise<void>;
disableIssueCreation?: boolean; isEpic?: boolean;
enableQuickIssueCreate: boolean; issuesMap: IIssueMap;
loadMoreIssues: (groupId?: string, subGroupId?: string) => void;
orderBy: TIssueOrderByOptions | undefined; orderBy: TIssueOrderByOptions | undefined;
canEditProperties: (projectId: string | undefined) => boolean; quickActions: TRenderQuickActions;
addIssuesToView?: (issueIds: string[]) => Promise<TIssue>;
quickAddCallback?: (projectId: string | null | undefined, data: TIssue) => Promise<TIssue | undefined>; quickAddCallback?: (projectId: string | null | undefined, data: TIssue) => Promise<TIssue | undefined>;
scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>; scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>;
loadMoreIssues: (groupId?: string, subGroupId?: string) => void; showEmptyGroup: boolean;
updateIssue: ((projectId: string | null, issueId: string, data: Partial<TIssue>) => Promise<void>) | undefined;
} }
const SubGroupSwimlane = observer(function SubGroupSwimlane(props: ISubGroupSwimlane) { const SubGroupSwimlane = observer(function SubGroupSwimlane(props: ISubGroupSwimlane) {
const { const {
issuesMap,
groupedIssueIds,
getGroupIssueCount,
sub_group_by,
group_by,
list,
updateIssue,
quickActions,
displayProperties,
collapsedGroups,
handleCollapsedGroups,
loadMoreIssues,
showEmptyGroup,
enableQuickIssueCreate,
disableIssueCreation,
canEditProperties,
addIssuesToView, addIssuesToView,
canEditProperties,
collapsedGroups,
disableIssueCreation,
displayProperties,
enableQuickIssueCreate,
getGroupIssueCount,
group_by,
groupedIssueIds,
handleCollapsedGroups,
handleOnDrop,
isEpic = false,
issuesMap,
list,
loadMoreIssues,
orderBy,
quickActions,
quickAddCallback, quickAddCallback,
scrollableContainerRef, scrollableContainerRef,
handleOnDrop, showEmptyGroup,
orderBy, sub_group_by,
updateIssue,
} = props; } = props;
const visibilitySubGroupBy = ( const visibilitySubGroupBy = (
@ -214,6 +218,7 @@ const SubGroupSwimlane = observer(function SubGroupSwimlane(props: ISubGroupSwim
orderBy={orderBy} orderBy={orderBy}
isDropDisabled={_list.isDropDisabled} isDropDisabled={_list.isDropDisabled}
dropErrorMessage={_list.dropErrorMessage} dropErrorMessage={_list.dropErrorMessage}
isEpic={isEpic}
/> />
</div> </div>
)} )}
@ -225,30 +230,31 @@ const SubGroupSwimlane = observer(function SubGroupSwimlane(props: ISubGroupSwim
}); });
export interface IKanBanSwimLanes { export interface IKanBanSwimLanes {
issuesMap: IIssueMap; addIssuesToView?: (issueIds: string[]) => Promise<TIssue>;
groupedIssueIds: TGroupedIssues | TSubGroupedIssues; canEditProperties: (projectId: string | undefined) => boolean;
collapsedGroups: TIssueKanbanFilters;
disableIssueCreation?: boolean;
displayProperties: IIssueDisplayProperties | undefined;
enableQuickIssueCreate: boolean;
getGroupIssueCount: ( getGroupIssueCount: (
groupId: string | undefined, groupId: string | undefined,
subGroupId: string | undefined, subGroupId: string | undefined,
isSubGroupCumulative: boolean isSubGroupCumulative: boolean
) => number | undefined; ) => number | undefined;
displayProperties: IIssueDisplayProperties | undefined;
sub_group_by: TIssueGroupByOptions | undefined;
group_by: TIssueGroupByOptions | undefined; group_by: TIssueGroupByOptions | undefined;
updateIssue: ((projectId: string | null, issueId: string, data: Partial<TIssue>) => Promise<void>) | undefined; groupedIssueIds: TGroupedIssues | TSubGroupedIssues;
quickActions: TRenderQuickActions;
collapsedGroups: TIssueKanbanFilters;
handleCollapsedGroups: (toggle: "group_by" | "sub_group_by", value: string) => void; handleCollapsedGroups: (toggle: "group_by" | "sub_group_by", value: string) => void;
loadMoreIssues: (groupId?: string, subGroupId?: string) => void;
showEmptyGroup: boolean;
handleOnDrop: (source: GroupDropLocation, destination: GroupDropLocation) => Promise<void>; handleOnDrop: (source: GroupDropLocation, destination: GroupDropLocation) => Promise<void>;
disableIssueCreation?: boolean; isEpic?: boolean;
addIssuesToView?: (issueIds: string[]) => Promise<TIssue>; issuesMap: IIssueMap;
enableQuickIssueCreate: boolean; loadMoreIssues: (groupId?: string, subGroupId?: string) => void;
quickAddCallback?: (projectId: string | null | undefined, data: TIssue) => Promise<TIssue | undefined>;
canEditProperties: (projectId: string | undefined) => boolean;
scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>;
orderBy: TIssueOrderByOptions | undefined; orderBy: TIssueOrderByOptions | undefined;
quickActions: TRenderQuickActions;
quickAddCallback?: (projectId: string | null | undefined, data: TIssue) => Promise<TIssue | undefined>;
scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>;
showEmptyGroup: boolean;
sub_group_by: TIssueGroupByOptions | undefined;
updateIssue: ((projectId: string | null, issueId: string, data: Partial<TIssue>) => Promise<void>) | undefined;
} }
export const KanBanSwimLanes = observer(function KanBanSwimLanes(props: IKanBanSwimLanes) { export const KanBanSwimLanes = observer(function KanBanSwimLanes(props: IKanBanSwimLanes) {
@ -273,6 +279,7 @@ export const KanBanSwimLanes = observer(function KanBanSwimLanes(props: IKanBanS
addIssuesToView, addIssuesToView,
quickAddCallback, quickAddCallback,
scrollableContainerRef, scrollableContainerRef,
isEpic = false,
} = props; } = props;
// store hooks // store hooks
const storeType = useIssueStoreType(); const storeType = useIssueStoreType();
@ -281,11 +288,13 @@ export const KanBanSwimLanes = observer(function KanBanSwimLanes(props: IKanBanS
groupBy: group_by as GroupByColumnTypes, groupBy: group_by as GroupByColumnTypes,
includeNone: true, includeNone: true,
isWorkspaceLevel: isWorkspaceLevel(storeType), isWorkspaceLevel: isWorkspaceLevel(storeType),
isEpic: isEpic,
}); });
const subGroupByList = getGroupByColumns({ const subGroupByList = getGroupByColumns({
groupBy: sub_group_by as GroupByColumnTypes, groupBy: sub_group_by as GroupByColumnTypes,
includeNone: true, includeNone: true,
isWorkspaceLevel: isWorkspaceLevel(storeType), isWorkspaceLevel: isWorkspaceLevel(storeType),
isEpic: isEpic,
}); });
if (!groupByList || !subGroupByList) return null; if (!groupByList || !subGroupByList) return null;
@ -301,6 +310,7 @@ export const KanBanSwimLanes = observer(function KanBanSwimLanes(props: IKanBanS
handleCollapsedGroups={handleCollapsedGroups} handleCollapsedGroups={handleCollapsedGroups}
list={groupByList} list={groupByList}
showEmptyGroup={showEmptyGroup} showEmptyGroup={showEmptyGroup}
isEpic={isEpic}
/> />
</Row> </Row>
@ -327,6 +337,7 @@ export const KanBanSwimLanes = observer(function KanBanSwimLanes(props: IKanBanS
canEditProperties={canEditProperties} canEditProperties={canEditProperties}
quickAddCallback={quickAddCallback} quickAddCallback={quickAddCallback}
scrollableContainerRef={scrollableContainerRef} scrollableContainerRef={scrollableContainerRef}
isEpic={isEpic}
/> />
)} )}
</div> </div>