Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Gantt chart layout #3585

Merged
merged 19 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
5ca137f
chore: gantt sidebar and main content scroll sync
aaryan610 Jan 31, 2024
0cea960
Merge branch 'develop' of https://github.com/makeplane/plane into fix…
aaryan610 Feb 1, 2024
b45ed5c
chore: add arrow navigation position logic
aaryan610 Feb 1, 2024
829cce7
refactor: scroll position update logic
aaryan610 Feb 1, 2024
fb46d50
Merge branch 'develop' of https://github.com/makeplane/plane into fix…
aaryan610 Feb 2, 2024
4943eb3
refactor: gantt chart components
aaryan610 Feb 2, 2024
38f6c03
refactor: gantt sidebar
aaryan610 Feb 5, 2024
ae86b0c
Merge branch 'develop' of https://github.com/makeplane/plane into fix…
aaryan610 Feb 5, 2024
fed8e56
fix: vertical scroll issue
aaryan610 Feb 7, 2024
31a4860
fix: move to the hidden block button flickering
aaryan610 Feb 7, 2024
db3886b
refactor: gantt sidebar components
aaryan610 Feb 7, 2024
a4da51c
chore: move timeline header outside
aaryan610 Feb 7, 2024
53c00ca
Merge branch 'develop' of https://github.com/makeplane/plane into fix…
aaryan610 Feb 7, 2024
79d7db6
fix gantt scroll issue
rahulramesha Feb 8, 2024
b86354f
Merge branch 'fix/gantt-scroll' of https://github.com/makeplane/plane…
aaryan610 Feb 8, 2024
eaba741
fix: sticky position issues
aaryan610 Feb 8, 2024
938391c
fix: merge conflicts resolved from develop
aaryan610 Feb 12, 2024
ac3550e
fix: infinite timeline scroll logic
aaryan610 Feb 12, 2024
96c6336
chore: removed unnecessary import statements
aaryan610 Feb 12, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 39 additions & 16 deletions web/components/cycles/gantt-chart/blocks.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,30 @@
import { useRouter } from "next/router";
import { observer } from "mobx-react";
// hooks
import { useApplication, useCycle } from "hooks/store";
// ui
import { Tooltip, ContrastIcon } from "@plane/ui";
// helpers
import { renderFormattedDate } from "helpers/date-time.helper";
// types
import { ICycle } from "@plane/types";

export const CycleGanttBlock = ({ data }: { data: ICycle }) => {
type Props = {
cycleId: string;
};

export const CycleGanttBlock: React.FC<Props> = observer((props) => {
const { cycleId } = props;
// router
const router = useRouter();
const { workspaceSlug } = router.query;
// store hooks
const {
router: { workspaceSlug },
} = useApplication();
const { getCycleById } = useCycle();
// derived values
const cycleDetails = getCycleById(cycleId);

const cycleStatus = cycleDetails?.status.toLocaleLowerCase();

const cycleStatus = data.status.toLocaleLowerCase();
return (
<div
className="relative flex h-full w-full items-center rounded"
Expand All @@ -26,36 +40,45 @@ export const CycleGanttBlock = ({ data }: { data: ICycle }) => {
? "rgb(var(--color-text-200))"
: "",
}}
onClick={() => router.push(`/${workspaceSlug}/projects/${data?.project}/cycles/${data?.id}`)}
onClick={() => router.push(`/${workspaceSlug}/projects/${cycleDetails?.project}/cycles/${cycleDetails?.id}`)}
>
<div className="absolute left-0 top-0 h-full w-full bg-custom-background-100/50" />
<Tooltip
tooltipContent={
<div className="space-y-1">
<h5>{data?.name}</h5>
<h5>{cycleDetails?.name}</h5>
<div>
{renderFormattedDate(data?.start_date ?? "")} to {renderFormattedDate(data?.end_date ?? "")}
{renderFormattedDate(cycleDetails?.start_date ?? "")} to{" "}
{renderFormattedDate(cycleDetails?.end_date ?? "")}
</div>
</div>
}
position="top-left"
>
<div className="relative w-full truncate px-2.5 py-1 text-sm text-custom-text-100">{data?.name}</div>
<div className="relative w-full truncate px-2.5 py-1 text-sm text-custom-text-100">{cycleDetails?.name}</div>
</Tooltip>
</div>
);
};
});

export const CycleGanttSidebarBlock = ({ data }: { data: ICycle }) => {
export const CycleGanttSidebarBlock: React.FC<Props> = observer((props) => {
const { cycleId } = props;
// router
const router = useRouter();
const { workspaceSlug } = router.query;
// store hooks
const {
router: { workspaceSlug },
} = useApplication();
const { getCycleById } = useCycle();
// derived values
const cycleDetails = getCycleById(cycleId);

const cycleStatus = data.status.toLocaleLowerCase();
const cycleStatus = cycleDetails?.status.toLocaleLowerCase();

return (
<div
className="relative flex h-full w-full items-center gap-2"
onClick={() => router.push(`/${workspaceSlug}/projects/${data?.project}/cycles/${data?.id}`)}
onClick={() => router.push(`/${workspaceSlug}/projects/${cycleDetails?.project}/cycles/${cycleDetails?.id}`)}
>
<ContrastIcon
className="h-5 w-5 flex-shrink-0"
Expand All @@ -71,7 +94,7 @@ export const CycleGanttSidebarBlock = ({ data }: { data: ICycle }) => {
: ""
}`}
/>
<h6 className="flex-grow truncate text-sm font-medium">{data?.name}</h6>
<h6 className="flex-grow truncate text-sm font-medium">{cycleDetails?.name}</h6>
</div>
);
};
});
2 changes: 1 addition & 1 deletion web/components/cycles/gantt-chart/cycles-list-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export const CyclesListGanttChartView: FC<Props> = observer((props) => {
blocks={cycleIds ? blockFormat(cycleIds.map((c) => getCycleById(c))) : null}
blockUpdateHandler={(block, payload) => handleCycleUpdate(block, payload)}
sidebarToRender={(props) => <CycleGanttSidebar {...props} />}
blockToRender={(data: ICycle) => <CycleGanttBlock data={data} />}
blockToRender={(data: ICycle) => <CycleGanttBlock cycleId={data.id} />}
enableBlockLeftResize={false}
enableBlockRightResize={false}
enableBlockMove={false}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { observer } from "mobx-react";
import { FC } from "react";
// hooks
import { useIssueDetail } from "hooks/store";
Expand All @@ -8,6 +9,8 @@ import { renderFormattedPayloadDate } from "helpers/date-time.helper";
import { cn } from "helpers/common.helper";
// types
import { IBlockUpdateData, IGanttBlock } from "../types";
// constants
import { BLOCK_HEIGHT, HEADER_HEIGHT } from "../constants";

export type GanttChartBlocksProps = {
itemsContainerWidth: number;
Expand All @@ -20,7 +23,7 @@ export type GanttChartBlocksProps = {
showAllBlocks: boolean;
};

export const GanttChartBlocks: FC<GanttChartBlocksProps> = (props) => {
export const GanttChartBlocksList: FC<GanttChartBlocksProps> = observer((props) => {
const {
itemsContainerWidth,
blocks,
Expand All @@ -31,9 +34,10 @@ export const GanttChartBlocks: FC<GanttChartBlocksProps> = (props) => {
enableBlockMove,
showAllBlocks,
} = props;

const { activeBlock, dispatch } = useChart();
// store hooks
const { peekIssue } = useIssueDetail();
// chart hook
const { activeBlock, dispatch } = useChart();

// update the active block on hover
const updateActiveBlock = (block: IGanttBlock | null) => {
Expand Down Expand Up @@ -77,43 +81,51 @@ export const GanttChartBlocks: FC<GanttChartBlocksProps> = (props) => {

return (
<div
className="relative z-[5] mt-[72px] h-full overflow-hidden overflow-y-auto"
style={{ width: `${itemsContainerWidth}px` }}
className="h-full"
style={{
width: `${itemsContainerWidth}px`,
marginTop: `${HEADER_HEIGHT}px`,
}}
>
{blocks &&
blocks.length > 0 &&
blocks.map((block) => {
// hide the block if it doesn't have start and target dates and showAllBlocks is false
if (!showAllBlocks && !(block.start_date && block.target_date)) return;
{blocks?.map((block) => {
// hide the block if it doesn't have start and target dates and showAllBlocks is false
if (!showAllBlocks && !(block.start_date && block.target_date)) return;

const isBlockVisibleOnChart = block.start_date && block.target_date;
const isBlockVisibleOnChart = block.start_date && block.target_date;

return (
return (
<div
key={`block-${block.id}`}
className="relative min-w-full w-max"
style={{
height: `${BLOCK_HEIGHT}px`,
}}
>
<div
key={`block-${block.id}`}
className={cn(
"h-11",
{ "rounded bg-custom-background-80": activeBlock?.id === block.id },
{
"rounded-l border border-r-0 border-custom-primary-70 hover:border-custom-primary-70":
peekIssue?.issueId === block.data.id,
}
)}
className={cn("relative h-full", {
"bg-custom-background-80": activeBlock?.id === block.id,
"rounded-l border border-r-0 border-custom-primary-70 hover:border-custom-primary-70":
peekIssue?.issueId === block.data.id,
})}
onMouseEnter={() => updateActiveBlock(block)}
onMouseLeave={() => updateActiveBlock(null)}
>
{!isBlockVisibleOnChart && <ChartAddBlock block={block} blockUpdateHandler={blockUpdateHandler} />}
<ChartDraggable
block={block}
blockToRender={blockToRender}
handleBlock={(...args) => handleChartBlockPosition(block, ...args)}
enableBlockLeftResize={enableBlockLeftResize}
enableBlockRightResize={enableBlockRightResize}
enableBlockMove={enableBlockMove}
/>
{isBlockVisibleOnChart ? (
<ChartDraggable
block={block}
blockToRender={blockToRender}
handleBlock={(...args) => handleChartBlockPosition(block, ...args)}
enableBlockLeftResize={enableBlockLeftResize}
enableBlockRightResize={enableBlockRightResize}
enableBlockMove={enableBlockMove}
/>
) : (
<ChartAddBlock block={block} blockUpdateHandler={blockUpdateHandler} />
)}
</div>
);
})}
</div>
);
})}
</div>
);
};
});
2 changes: 1 addition & 1 deletion web/components/gantt-chart/blocks/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export * from "./blocks-display";
export * from "./blocks-list";
59 changes: 59 additions & 0 deletions web/components/gantt-chart/chart/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { Expand, Shrink } from "lucide-react";
// hooks
import { useChart } from "../hooks";
// helpers
import { cn } from "helpers/common.helper";
// types
import { IGanttBlock, TGanttViews } from "../types";

type Props = {
blocks: IGanttBlock[] | null;
fullScreenMode: boolean;
handleChartView: (view: TGanttViews) => void;
handleToday: () => void;
loaderTitle: string;
title: string;
toggleFullScreenMode: () => void;
};

export const GanttChartHeader: React.FC<Props> = (props) => {
const { blocks, fullScreenMode, handleChartView, handleToday, loaderTitle, title, toggleFullScreenMode } = props;
// chart hook
const { currentView, allViews } = useChart();

return (
<div className="relative flex w-full flex-shrink-0 flex-wrap items-center gap-2 whitespace-nowrap px-2.5 py-2 z-10">
<div className="flex items-center gap-2 text-lg font-medium">{title}</div>
<div className="ml-auto">
<div className="ml-auto text-sm font-medium">{blocks ? `${blocks.length} ${loaderTitle}` : "Loading..."}</div>
</div>

<div className="flex flex-wrap items-center gap-2">
{allViews?.map((chartView: any) => (
<div
key={chartView?.key}
className={cn("cursor-pointer rounded-sm p-1 px-2 text-xs", {
"bg-custom-background-80": currentView === chartView?.key,
"hover:bg-custom-background-90": currentView !== chartView?.key,
})}
onClick={() => handleChartView(chartView?.key)}
>
{chartView?.title}
</div>
))}
</div>

<button type="button" className="rounded-sm p-1 px-2 text-xs hover:bg-custom-background-80" onClick={handleToday}>
Today
</button>

<button
type="button"
className="flex items-center justify-center rounded-sm border border-custom-border-200 p-1 transition-all hover:bg-custom-background-80"
onClick={toggleFullScreenMode}
>
{fullScreenMode ? <Shrink className="h-4 w-4" /> : <Expand className="h-4 w-4" />}
</button>
</div>
);
};
4 changes: 4 additions & 0 deletions web/components/gantt-chart/chart/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from "./views";
export * from "./header";
export * from "./main-content";
export * from "./root";
Loading
Loading