131 lines
4.1 KiB
TypeScript
131 lines
4.1 KiB
TypeScript
/**
|
|
* Copyright (c) 2023-present Plane Software, Inc. and contributors
|
|
* SPDX-License-Identifier: AGPL-3.0-only
|
|
* See the LICENSE file for details.
|
|
*/
|
|
|
|
import type { MutableRefObject } from "react";
|
|
import { isNil } from "lodash-es";
|
|
import { observer } from "mobx-react";
|
|
// types
|
|
import type {
|
|
GroupByColumnTypes,
|
|
IGroupByColumn,
|
|
TGroupedIssues,
|
|
IIssueDisplayProperties,
|
|
TSubGroupedIssues,
|
|
TIssueGroupByOptions,
|
|
TPaginationData,
|
|
TLoader,
|
|
} from "@plane/types";
|
|
// hooks
|
|
import { useCycle } from "@/hooks/store/use-cycle";
|
|
import { useLabel } from "@/hooks/store/use-label";
|
|
import { useMember } from "@/hooks/store/use-member";
|
|
import { useModule } from "@/hooks/store/use-module";
|
|
import { useStates } from "@/hooks/store/use-state";
|
|
//
|
|
import { getGroupByColumns } from "../utils";
|
|
// components
|
|
import { HeaderGroupByCard } from "./headers/group-by-card";
|
|
import { KanbanGroup } from "./kanban-group";
|
|
|
|
export interface IKanBan {
|
|
groupedIssueIds: TGroupedIssues | TSubGroupedIssues;
|
|
displayProperties: IIssueDisplayProperties | undefined;
|
|
subGroupBy: TIssueGroupByOptions | undefined;
|
|
groupBy: TIssueGroupByOptions | undefined;
|
|
subGroupId?: string;
|
|
loadMoreIssues: (groupId?: string, subGroupId?: string) => void;
|
|
getGroupIssueCount: (
|
|
groupId: string | undefined,
|
|
subGroupId: string | undefined,
|
|
isSubGroupCumulative: boolean
|
|
) => number | undefined;
|
|
getPaginationData: (groupId: string | undefined, subGroupId: string | undefined) => TPaginationData | undefined;
|
|
getIssueLoader: (groupId?: string, subGroupId?: string) => TLoader;
|
|
scrollableContainerRef?: MutableRefObject<HTMLDivElement | null>;
|
|
showEmptyGroup?: boolean;
|
|
}
|
|
|
|
export const KanBan = observer(function KanBan(props: IKanBan) {
|
|
const {
|
|
groupedIssueIds,
|
|
displayProperties,
|
|
subGroupBy,
|
|
groupBy,
|
|
subGroupId = "null",
|
|
loadMoreIssues,
|
|
getGroupIssueCount,
|
|
getPaginationData,
|
|
getIssueLoader,
|
|
scrollableContainerRef,
|
|
showEmptyGroup = true,
|
|
} = props;
|
|
|
|
const member = useMember();
|
|
const label = useLabel();
|
|
const cycle = useCycle();
|
|
const modules = useModule();
|
|
const state = useStates();
|
|
|
|
const groupList = getGroupByColumns(groupBy as GroupByColumnTypes, cycle, modules, label, state, member);
|
|
|
|
if (!groupList) return null;
|
|
|
|
const visibilityGroupBy = (_list: IGroupByColumn): { showGroup: boolean; showIssues: boolean } => {
|
|
const groupVisibility = {
|
|
showGroup: true,
|
|
showIssues: true,
|
|
};
|
|
|
|
if (!showEmptyGroup) {
|
|
groupVisibility.showGroup = (getGroupIssueCount(_list.id, undefined, false) ?? 0) > 0;
|
|
}
|
|
return groupVisibility;
|
|
};
|
|
|
|
return (
|
|
<div className="relative flex size-full gap-2 px-2">
|
|
{groupList?.map((subList) => {
|
|
const groupByVisibilityToggle = visibilityGroupBy(subList);
|
|
|
|
if (groupByVisibilityToggle.showGroup === false) return <></>;
|
|
return (
|
|
<div
|
|
key={subList.id}
|
|
className={`group relative flex shrink-0 flex-col ${
|
|
groupByVisibilityToggle.showIssues ? `w-[350px]` : ``
|
|
} `}
|
|
>
|
|
{isNil(subGroupBy) && (
|
|
<div className="sticky top-0 z-2 w-full shrink-0 py-1">
|
|
<HeaderGroupByCard
|
|
groupBy={groupBy}
|
|
icon={subList.icon as any}
|
|
title={subList.name}
|
|
count={getGroupIssueCount(subList.id, undefined, false) ?? 0}
|
|
/>
|
|
</div>
|
|
)}
|
|
|
|
{groupByVisibilityToggle.showIssues && (
|
|
<KanbanGroup
|
|
groupId={subList.id}
|
|
groupedIssueIds={groupedIssueIds}
|
|
displayProperties={displayProperties}
|
|
subGroupBy={subGroupBy}
|
|
subGroupId={subGroupId}
|
|
scrollableContainerRef={scrollableContainerRef}
|
|
loadMoreIssues={loadMoreIssues}
|
|
getGroupIssueCount={getGroupIssueCount}
|
|
getPaginationData={getPaginationData}
|
|
getIssueLoader={getIssueLoader}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
})}
|
|
</div>
|
|
);
|
|
});
|