forked from github/plane
fix: horizontal scroll in gantt chart while dragging (#3664)
* fix horizontal scroll in gantt chart while dragging * add aline indicator for quick add * add border color for line above quick add in gantt to make it look better in dark mode
This commit is contained in:
parent
b827a1af27
commit
489555f788
@ -33,6 +33,7 @@ type Props = {
|
|||||||
sidebarToRender: (props: any) => React.ReactNode;
|
sidebarToRender: (props: any) => React.ReactNode;
|
||||||
title: string;
|
title: string;
|
||||||
updateCurrentViewRenderPayload: (direction: "left" | "right", currentView: TGanttViews) => void;
|
updateCurrentViewRenderPayload: (direction: "left" | "right", currentView: TGanttViews) => void;
|
||||||
|
quickAdd?: React.JSX.Element | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GanttChartMainContent: React.FC<Props> = (props) => {
|
export const GanttChartMainContent: React.FC<Props> = (props) => {
|
||||||
@ -52,6 +53,7 @@ export const GanttChartMainContent: React.FC<Props> = (props) => {
|
|||||||
sidebarToRender,
|
sidebarToRender,
|
||||||
title,
|
title,
|
||||||
updateCurrentViewRenderPayload,
|
updateCurrentViewRenderPayload,
|
||||||
|
quickAdd,
|
||||||
} = props;
|
} = props;
|
||||||
// chart hook
|
// chart hook
|
||||||
const { currentView, currentViewData, updateScrollLeft } = useChart();
|
const { currentView, currentViewData, updateScrollLeft } = useChart();
|
||||||
@ -101,6 +103,7 @@ export const GanttChartMainContent: React.FC<Props> = (props) => {
|
|||||||
enableReorder={enableReorder}
|
enableReorder={enableReorder}
|
||||||
sidebarToRender={sidebarToRender}
|
sidebarToRender={sidebarToRender}
|
||||||
title={title}
|
title={title}
|
||||||
|
quickAdd={quickAdd}
|
||||||
/>
|
/>
|
||||||
<div className="relative min-h-full h-max flex-shrink-0 flex-grow">
|
<div className="relative min-h-full h-max flex-shrink-0 flex-grow">
|
||||||
<ActiveChartView />
|
<ActiveChartView />
|
||||||
|
@ -31,6 +31,7 @@ type ChartViewRootProps = {
|
|||||||
enableAddBlock: boolean;
|
enableAddBlock: boolean;
|
||||||
bottomSpacing: boolean;
|
bottomSpacing: boolean;
|
||||||
showAllBlocks: boolean;
|
showAllBlocks: boolean;
|
||||||
|
quickAdd?: React.JSX.Element | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ChartViewRoot: FC<ChartViewRootProps> = (props) => {
|
export const ChartViewRoot: FC<ChartViewRootProps> = (props) => {
|
||||||
@ -49,6 +50,7 @@ export const ChartViewRoot: FC<ChartViewRootProps> = (props) => {
|
|||||||
enableAddBlock,
|
enableAddBlock,
|
||||||
bottomSpacing,
|
bottomSpacing,
|
||||||
showAllBlocks,
|
showAllBlocks,
|
||||||
|
quickAdd,
|
||||||
} = props;
|
} = props;
|
||||||
// states
|
// states
|
||||||
const [itemsContainerWidth, setItemsContainerWidth] = useState(0);
|
const [itemsContainerWidth, setItemsContainerWidth] = useState(0);
|
||||||
@ -200,6 +202,7 @@ export const ChartViewRoot: FC<ChartViewRootProps> = (props) => {
|
|||||||
sidebarToRender={sidebarToRender}
|
sidebarToRender={sidebarToRender}
|
||||||
title={title}
|
title={title}
|
||||||
updateCurrentViewRenderPayload={updateCurrentViewRenderPayload}
|
updateCurrentViewRenderPayload={updateCurrentViewRenderPayload}
|
||||||
|
quickAdd={quickAdd}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -12,6 +12,7 @@ type GanttChartRootProps = {
|
|||||||
blockUpdateHandler: (block: any, payload: IBlockUpdateData) => void;
|
blockUpdateHandler: (block: any, payload: IBlockUpdateData) => void;
|
||||||
blockToRender: (data: any) => React.ReactNode;
|
blockToRender: (data: any) => React.ReactNode;
|
||||||
sidebarToRender: (props: any) => React.ReactNode;
|
sidebarToRender: (props: any) => React.ReactNode;
|
||||||
|
quickAdd?: React.JSX.Element | undefined;
|
||||||
enableBlockLeftResize?: boolean;
|
enableBlockLeftResize?: boolean;
|
||||||
enableBlockRightResize?: boolean;
|
enableBlockRightResize?: boolean;
|
||||||
enableBlockMove?: boolean;
|
enableBlockMove?: boolean;
|
||||||
@ -37,6 +38,7 @@ export const GanttChartRoot: FC<GanttChartRootProps> = (props) => {
|
|||||||
enableAddBlock = false,
|
enableAddBlock = false,
|
||||||
bottomSpacing = false,
|
bottomSpacing = false,
|
||||||
showAllBlocks = false,
|
showAllBlocks = false,
|
||||||
|
quickAdd,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -56,6 +58,7 @@ export const GanttChartRoot: FC<GanttChartRootProps> = (props) => {
|
|||||||
enableAddBlock={enableAddBlock}
|
enableAddBlock={enableAddBlock}
|
||||||
bottomSpacing={bottomSpacing}
|
bottomSpacing={bottomSpacing}
|
||||||
showAllBlocks={showAllBlocks}
|
showAllBlocks={showAllBlocks}
|
||||||
|
quickAdd={quickAdd}
|
||||||
/>
|
/>
|
||||||
</ChartContextProvider>
|
</ChartContextProvider>
|
||||||
);
|
);
|
||||||
|
@ -7,42 +7,23 @@ import { useIssueDetail } from "hooks/store";
|
|||||||
// ui
|
// ui
|
||||||
import { Loader } from "@plane/ui";
|
import { Loader } from "@plane/ui";
|
||||||
// components
|
// components
|
||||||
import { GanttQuickAddIssueForm, IssueGanttSidebarBlock } from "components/issues";
|
import { IssueGanttSidebarBlock } from "components/issues";
|
||||||
// helpers
|
// helpers
|
||||||
import { findTotalDaysInRange } from "helpers/date-time.helper";
|
import { findTotalDaysInRange } from "helpers/date-time.helper";
|
||||||
import { cn } from "helpers/common.helper";
|
import { cn } from "helpers/common.helper";
|
||||||
// types
|
// types
|
||||||
import { IGanttBlock, IBlockUpdateData } from "components/gantt-chart/types";
|
import { IGanttBlock, IBlockUpdateData } from "components/gantt-chart/types";
|
||||||
import { TIssue } from "@plane/types";
|
|
||||||
import { BLOCK_HEIGHT } from "../constants";
|
import { BLOCK_HEIGHT } from "../constants";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
blockUpdateHandler: (block: any, payload: IBlockUpdateData) => void;
|
blockUpdateHandler: (block: any, payload: IBlockUpdateData) => void;
|
||||||
blocks: IGanttBlock[] | null;
|
blocks: IGanttBlock[] | null;
|
||||||
enableReorder: boolean;
|
enableReorder: boolean;
|
||||||
enableQuickIssueCreate?: boolean;
|
|
||||||
quickAddCallback?: (
|
|
||||||
workspaceSlug: string,
|
|
||||||
projectId: string,
|
|
||||||
data: TIssue,
|
|
||||||
viewId?: string
|
|
||||||
) => Promise<TIssue | undefined>;
|
|
||||||
viewId?: string;
|
|
||||||
disableIssueCreation?: boolean;
|
|
||||||
showAllBlocks?: boolean;
|
showAllBlocks?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const IssueGanttSidebar: React.FC<Props> = observer((props) => {
|
export const IssueGanttSidebar: React.FC<Props> = observer((props: Props) => {
|
||||||
const {
|
const { blockUpdateHandler, blocks, enableReorder, showAllBlocks = false } = props;
|
||||||
blockUpdateHandler,
|
|
||||||
blocks,
|
|
||||||
enableReorder,
|
|
||||||
enableQuickIssueCreate,
|
|
||||||
quickAddCallback,
|
|
||||||
viewId,
|
|
||||||
disableIssueCreation,
|
|
||||||
showAllBlocks = false,
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
const { activeBlock, dispatch } = useChart();
|
const { activeBlock, dispatch } = useChart();
|
||||||
const { peekIssue } = useIssueDetail();
|
const { peekIssue } = useIssueDetail();
|
||||||
@ -187,9 +168,6 @@ export const IssueGanttSidebar: React.FC<Props> = observer((props) => {
|
|||||||
)}
|
)}
|
||||||
</Droppable>
|
</Droppable>
|
||||||
</DragDropContext>
|
</DragDropContext>
|
||||||
{enableQuickIssueCreate && !disableIssueCreation && (
|
|
||||||
<GanttQuickAddIssueForm quickAddCallback={quickAddCallback} viewId={viewId} />
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -9,16 +9,17 @@ type Props = {
|
|||||||
enableReorder: boolean;
|
enableReorder: boolean;
|
||||||
sidebarToRender: (props: any) => React.ReactNode;
|
sidebarToRender: (props: any) => React.ReactNode;
|
||||||
title: string;
|
title: string;
|
||||||
|
quickAdd?: React.JSX.Element | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const GanttChartSidebar: React.FC<Props> = (props) => {
|
export const GanttChartSidebar: React.FC<Props> = (props) => {
|
||||||
const { blocks, blockUpdateHandler, enableReorder, sidebarToRender, title } = props;
|
const { blocks, blockUpdateHandler, enableReorder, sidebarToRender, title, quickAdd } = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
// DO NOT REMOVE THE ID
|
// DO NOT REMOVE THE ID
|
||||||
id="gantt-sidebar"
|
id="gantt-sidebar"
|
||||||
className="sticky top-0 left-0 z-10 min-h-full h-max flex-shrink-0 border-r-[0.5px] border-custom-border-200 bg-custom-background-100"
|
className="sticky left-0 z-10 min-h-full h-max flex-shrink-0 border-r-[0.5px] border-custom-border-200 bg-custom-background-100"
|
||||||
style={{
|
style={{
|
||||||
width: `${SIDEBAR_WIDTH}px`,
|
width: `${SIDEBAR_WIDTH}px`,
|
||||||
}}
|
}}
|
||||||
@ -33,9 +34,10 @@ export const GanttChartSidebar: React.FC<Props> = (props) => {
|
|||||||
<h6>Duration</h6>
|
<h6>Duration</h6>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="min-h-full h-max bg-custom-background-100">
|
<div className="min-h-full h-max bg-custom-background-100 overflow-x-hidden overflow-y-auto">
|
||||||
{sidebarToRender && sidebarToRender({ title, blockUpdateHandler, blocks, enableReorder })}
|
{sidebarToRender && sidebarToRender({ title, blockUpdateHandler, blocks, enableReorder })}
|
||||||
</div>
|
</div>
|
||||||
|
{quickAdd ? quickAdd : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -4,7 +4,7 @@ import { observer } from "mobx-react-lite";
|
|||||||
// hooks
|
// hooks
|
||||||
import { useIssues, useUser } from "hooks/store";
|
import { useIssues, useUser } from "hooks/store";
|
||||||
// components
|
// components
|
||||||
import { IssueGanttBlock } from "components/issues";
|
import { GanttQuickAddIssueForm, IssueGanttBlock } from "components/issues";
|
||||||
import {
|
import {
|
||||||
GanttChartRoot,
|
GanttChartRoot,
|
||||||
IBlockUpdateData,
|
IBlockUpdateData,
|
||||||
@ -70,21 +70,17 @@ export const BaseGanttRoot: React.FC<IBaseGanttRoot> = observer((props: IBaseGan
|
|||||||
blocks={issues ? renderIssueBlocksStructure(issues as TIssue[]) : null}
|
blocks={issues ? renderIssueBlocksStructure(issues as TIssue[]) : null}
|
||||||
blockUpdateHandler={updateIssueBlockStructure}
|
blockUpdateHandler={updateIssueBlockStructure}
|
||||||
blockToRender={(data: TIssue) => <IssueGanttBlock issueId={data.id} />}
|
blockToRender={(data: TIssue) => <IssueGanttBlock issueId={data.id} />}
|
||||||
sidebarToRender={(props) => (
|
sidebarToRender={(props) => <IssueGanttSidebar {...props} showAllBlocks />}
|
||||||
<IssueGanttSidebar
|
|
||||||
{...props}
|
|
||||||
quickAddCallback={issueStore.quickAddIssue}
|
|
||||||
viewId={viewId}
|
|
||||||
enableQuickIssueCreate
|
|
||||||
disableIssueCreation={!enableIssueCreation || !isAllowed}
|
|
||||||
showAllBlocks
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
enableBlockLeftResize={isAllowed}
|
enableBlockLeftResize={isAllowed}
|
||||||
enableBlockRightResize={isAllowed}
|
enableBlockRightResize={isAllowed}
|
||||||
enableBlockMove={isAllowed}
|
enableBlockMove={isAllowed}
|
||||||
enableReorder={appliedDisplayFilters?.order_by === "sort_order" && isAllowed}
|
enableReorder={appliedDisplayFilters?.order_by === "sort_order" && isAllowed}
|
||||||
enableAddBlock={isAllowed}
|
enableAddBlock={isAllowed}
|
||||||
|
quickAdd={
|
||||||
|
enableIssueCreation && isAllowed ? (
|
||||||
|
<GanttQuickAddIssueForm quickAddCallback={issueStore.quickAddIssue} viewId={viewId} />
|
||||||
|
) : undefined
|
||||||
|
}
|
||||||
showAllBlocks
|
showAllBlocks
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -159,7 +159,7 @@ export const GanttQuickAddIssueForm: React.FC<IGanttQuickAddIssueForm> = observe
|
|||||||
) : (
|
) : (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="sticky bottom-0 z-[1] flex w-full cursor-pointer items-center gap-2 p-3 py-3 text-custom-primary-100 bg-custom-background-100"
|
className="sticky bottom-0 z-[1] flex w-full cursor-pointer items-center gap-2 p-3 py-3 text-custom-primary-100 bg-custom-background-100 border-custom-border-200 border-t-[1px]"
|
||||||
onClick={() => setIsOpen(true)}
|
onClick={() => setIsOpen(true)}
|
||||||
>
|
>
|
||||||
<PlusIcon className="h-3.5 w-3.5 stroke-2" />
|
<PlusIcon className="h-3.5 w-3.5 stroke-2" />
|
||||||
|
Loading…
Reference in New Issue
Block a user