snapshot of https://github.com/makeplane/plane.git @ d868349a55de79979eb8b98701bf1702c67ad634 (2026-09-15)
Some checks failed
CodeQL / Analyze (javascript) (push) Failing after 16s
CodeQL / Analyze (python) (push) Failing after 3s
i18n sync check / check:sync (push) Failing after 3s
React Doctor / react-doctor (push) Failing after 16s
Branch Build CE / Build-Push Admin Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Admin Manifest (push) Has been cancelled
Branch Build CE / Build-Push Web Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Web Manifest (push) Has been cancelled
Branch Build CE / Build-Push Space Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Proxy Manifest (push) Has been cancelled
Branch Build CE / Merge Space Manifest (push) Has been cancelled
Branch Build CE / Prepare AIO Assets (push) Has been cancelled
Branch Build CE / Build Setup (push) Has been cancelled
Branch Build CE / Build-Push Live Collaboration Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge Live Collaboration Manifest (push) Has been cancelled
Branch Build CE / Build-Push API Server Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge API Server Manifest (push) Has been cancelled
Branch Build CE / Build-Push Proxy Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Build-Push AIO Docker Image (${{ matrix.arch }}) (push) Has been cancelled
Branch Build CE / Merge AIO Manifest (push) Has been cancelled
Branch Build CE / Upload Build Assets (push) Has been cancelled
Branch Build CE / Build Release (push) Has been cancelled

This commit is contained in:
upstream-mirror
2026-09-15 15:14:58 +05:00
commit 23059a1de3
5252 changed files with 573834 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
// components
import type { IBlockUpdateData, IGanttBlock } from "@plane/types";
import RenderIfVisible from "@/components/core/render-if-visible-HOC";
// hooks
import { BlockRow } from "@/components/gantt-chart/blocks/block-row";
import { BLOCK_HEIGHT } from "@/components/gantt-chart/constants";
import type { TSelectionHelper } from "@/hooks/use-multiple-select";
// types
export type GanttChartBlocksProps = {
blockIds: string[];
blockUpdateHandler: (block: any, payload: IBlockUpdateData) => void;
handleScrollToBlock: (block: IGanttBlock) => void;
enableAddBlock: boolean | ((blockId: string) => boolean);
showAllBlocks: boolean;
selectionHelpers: TSelectionHelper;
ganttContainerRef: React.RefObject<HTMLDivElement | null>;
};
export function GanttChartRowList(props: GanttChartBlocksProps) {
const {
blockIds,
blockUpdateHandler,
handleScrollToBlock,
enableAddBlock,
showAllBlocks,
selectionHelpers,
ganttContainerRef,
} = props;
return (
<div className="absolute top-0 left-0 w-max min-w-full">
{blockIds?.map((blockId) => (
<>
<RenderIfVisible
root={ganttContainerRef}
horizontalOffset={100}
verticalOffset={200}
classNames="relative min-w-full w-max"
placeholderChildren={<div className="pointer-events-none w-full" style={{ height: `${BLOCK_HEIGHT}px` }} />}
shouldRecordHeights={false}
>
<BlockRow
key={blockId}
blockId={blockId}
showAllBlocks={showAllBlocks}
blockUpdateHandler={blockUpdateHandler}
handleScrollToBlock={handleScrollToBlock}
enableAddBlock={typeof enableAddBlock === "function" ? enableAddBlock(blockId) : enableAddBlock}
selectionHelpers={selectionHelpers}
ganttContainerRef={ganttContainerRef}
/>
</RenderIfVisible>
</>
))}
</div>
);
}

View File

@@ -0,0 +1,121 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import { useEffect, useState } from "react";
import { observer } from "mobx-react";
import { ArrowNarrowRightOutline } from "@makeplane/propel/icons";
// helpers
import type { IBlockUpdateData, IGanttBlock } from "@plane/types";
import { cn } from "@plane/utils";
// hooks
import { useIssueDetail } from "@/hooks/store/use-issue-detail";
import type { TSelectionHelper } from "@/hooks/use-multiple-select";
import { useTimeLineChartStore } from "@/hooks/use-timeline-chart";
//
import { BLOCK_HEIGHT, SIDEBAR_WIDTH } from "../constants";
import { ChartAddBlock } from "../helpers";
type Props = {
blockId: string;
showAllBlocks: boolean;
blockUpdateHandler: (block: any, payload: IBlockUpdateData) => void;
handleScrollToBlock: (block: IGanttBlock) => void;
enableAddBlock: boolean;
selectionHelpers: TSelectionHelper;
ganttContainerRef: React.RefObject<HTMLDivElement | null>;
};
export const BlockRow = observer(function BlockRow(props: Props) {
const { blockId, showAllBlocks, blockUpdateHandler, handleScrollToBlock, enableAddBlock, selectionHelpers } = props;
// states
const [isHidden, setIsHidden] = useState(false);
const [isBlockHiddenOnLeft, setIsBlockHiddenOnLeft] = useState(false);
// store hooks
const { getBlockById, updateActiveBlockId, isBlockActive } = useTimeLineChartStore();
const { getIsIssuePeeked } = useIssueDetail();
const block = getBlockById(blockId);
useEffect(() => {
const intersectionRoot = document.querySelector("#gantt-container") as HTMLDivElement;
const timelineBlock = document.getElementById(`gantt-block-${block?.id}`);
if (!timelineBlock || !intersectionRoot) return;
setIsBlockHiddenOnLeft(
!!block.position?.marginLeft &&
!!block.position?.width &&
intersectionRoot.scrollLeft > block.position.marginLeft + block.position.width
);
// Observe if the block is visible on the chart
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((entry) => {
setIsHidden(!entry.isIntersecting);
setIsBlockHiddenOnLeft(entry.boundingClientRect.right < (entry.rootBounds?.left ?? 0));
});
},
{
root: intersectionRoot,
rootMargin: `0px 0px 0px -${SIDEBAR_WIDTH}px`,
}
);
observer.observe(timelineBlock);
return () => {
observer.unobserve(timelineBlock);
};
}, [block]);
// hide the block if it doesn't have start and target dates and showAllBlocks is false
if (!block || !block.data || (!showAllBlocks && !(block.start_date && block.target_date))) return null;
const isBlockVisibleOnChart = block.start_date || block.target_date;
const isBlockSelected = selectionHelpers.getIsEntitySelected(block.id);
const isBlockFocused = selectionHelpers.getIsEntityActive(block.id);
const isBlockHoveredOn = isBlockActive(block.id);
return (
<div
className="relative w-max min-w-full"
onMouseEnter={() => updateActiveBlockId(blockId)}
onMouseLeave={() => updateActiveBlockId(null)}
style={{
height: `${BLOCK_HEIGHT}px`,
}}
>
<div
className={cn("relative h-full bg-layer-transparent hover:bg-layer-transparent-hover", {
"rounded-l-sm border border-r-0 border-accent-strong": getIsIssuePeeked(block.data.id),
"bg-layer-transparent-hover": isBlockHoveredOn,
"bg-accent-primary/5 hover:bg-accent-primary/10": isBlockSelected,
"bg-accent-primary/10": isBlockSelected && isBlockHoveredOn,
"border border-r-0 border-strong-1": isBlockFocused,
})}
>
{isBlockVisibleOnChart
? isHidden && (
<button
type="button"
className="sticky z-[5] grid h-8 w-8 translate-y-1.5 cursor-pointer place-items-center rounded-sm border border-strong bg-layer-1 text-secondary hover:text-primary"
style={{
left: `${SIDEBAR_WIDTH + 4}px`,
}}
onClick={() => handleScrollToBlock(block)}
>
<ArrowNarrowRightOutline
className={cn("h-3.5 w-3.5", {
"rotate-180": isBlockHiddenOnLeft,
})}
/>
</button>
)
: enableAddBlock && <ChartAddBlock block={block} blockUpdateHandler={blockUpdateHandler} />}
</div>
</div>
);
});

View File

@@ -0,0 +1,111 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
import type { RefObject } from "react";
import { useRef } from "react";
import { observer } from "mobx-react";
// components
import type { IBlockUpdateDependencyData } from "@plane/types";
import { cn } from "@plane/utils";
import RenderIfVisible from "@/components/core/render-if-visible-HOC";
// helpers
// hooks
import { useTimeLineChartStore } from "@/hooks/use-timeline-chart";
// constants
import { BLOCK_HEIGHT } from "../constants";
// components
import { ChartDraggable } from "../helpers";
import { useGanttResizable } from "../helpers/blockResizables/use-gantt-resizable";
type Props = {
blockId: string;
showAllBlocks: boolean;
blockToRender: (data: any) => React.ReactNode;
enableBlockLeftResize: boolean;
enableBlockRightResize: boolean;
enableBlockMove: boolean;
enableDependency: boolean;
ganttContainerRef: RefObject<HTMLDivElement | null>;
updateBlockDates?: (updates: IBlockUpdateDependencyData[]) => Promise<void>;
};
export const GanttChartBlock = observer(function GanttChartBlock(props: Props) {
const {
blockId,
showAllBlocks,
blockToRender,
enableBlockLeftResize,
enableBlockRightResize,
enableBlockMove,
ganttContainerRef,
enableDependency,
updateBlockDates,
} = props;
// store hooks
const { updateActiveBlockId, getBlockById, getIsCurrentDependencyDragging, currentView } = useTimeLineChartStore();
// refs
const resizableRef = useRef<HTMLDivElement>(null);
const block = getBlockById(blockId);
const isCurrentDependencyDragging = getIsCurrentDependencyDragging(blockId);
const { isMoving, handleBlockDrag } = useGanttResizable(block, resizableRef, ganttContainerRef, updateBlockDates);
const isBlockVisibleOnChart = block?.start_date || block?.target_date;
const isBlockComplete = block?.start_date && block?.target_date;
// hide the block if it doesn't have start and target dates and showAllBlocks is false
if (!block || (!showAllBlocks && !isBlockVisibleOnChart)) return null;
if (!block.data) return null;
return (
<div
className={cn("relative z-[5]", {
"transition-all": !!isMoving && currentView === "week",
"pointer-events-none": !isBlockVisibleOnChart,
})}
id={`gantt-block-${block.id}`}
ref={resizableRef}
style={{
height: `${BLOCK_HEIGHT}px`,
marginLeft: `${block.position?.marginLeft}px`,
width: `${block.position?.width}px`,
}}
>
{isBlockVisibleOnChart && (
<RenderIfVisible
root={ganttContainerRef}
horizontalOffset={100}
verticalOffset={200}
classNames="flex h-full w-full items-center"
placeholderChildren={<div className="h-8 w-full rounded-sm bg-layer-1" />}
shouldRecordHeights={false}
forceRender={isCurrentDependencyDragging}
>
<div
className={cn("relative h-full w-full")}
onMouseEnter={() => updateActiveBlockId(blockId)}
onMouseLeave={() => updateActiveBlockId(null)}
>
<ChartDraggable
block={block}
blockToRender={blockToRender}
handleBlockDrag={handleBlockDrag}
enableBlockLeftResize={enableBlockLeftResize}
enableBlockRightResize={enableBlockRightResize}
enableBlockMove={enableBlockMove && !!isBlockComplete}
enableDependency={enableDependency}
isMoving={isMoving}
ganttContainerRef={ganttContainerRef}
/>
</div>
</RenderIfVisible>
)}
</div>
);
});

View File

@@ -0,0 +1,58 @@
/**
* Copyright (c) 2023-present Plane Software, Inc. and contributors
* SPDX-License-Identifier: AGPL-3.0-only
* See the LICENSE file for details.
*/
//
import type { IBlockUpdateDependencyData } from "@plane/types";
import { GanttChartBlock } from "@/components/gantt-chart/blocks/block";
export type GanttChartBlocksProps = {
blockIds: string[];
blockToRender: (data: any) => React.ReactNode;
enableBlockLeftResize: boolean | ((blockId: string) => boolean);
enableBlockRightResize: boolean | ((blockId: string) => boolean);
enableBlockMove: boolean | ((blockId: string) => boolean);
ganttContainerRef: React.RefObject<HTMLDivElement | null>;
showAllBlocks: boolean;
updateBlockDates?: (updates: IBlockUpdateDependencyData[]) => Promise<void>;
enableDependency: boolean | ((blockId: string) => boolean);
};
export function GanttChartBlocksList(props: GanttChartBlocksProps) {
const {
blockIds,
blockToRender,
enableBlockLeftResize,
enableBlockRightResize,
enableBlockMove,
ganttContainerRef,
showAllBlocks,
updateBlockDates,
enableDependency,
} = props;
return (
<>
{blockIds?.map((blockId) => (
<GanttChartBlock
key={blockId}
blockId={blockId}
showAllBlocks={showAllBlocks}
blockToRender={blockToRender}
enableBlockLeftResize={
typeof enableBlockLeftResize === "function" ? enableBlockLeftResize(blockId) : enableBlockLeftResize
}
enableBlockRightResize={
typeof enableBlockRightResize === "function" ? enableBlockRightResize(blockId) : enableBlockRightResize
}
enableBlockMove={typeof enableBlockMove === "function" ? enableBlockMove(blockId) : enableBlockMove}
enableDependency={typeof enableDependency === "function" ? enableDependency(blockId) : enableDependency}
ganttContainerRef={ganttContainerRef}
updateBlockDates={updateBlockDates}
/>
))}
</>
);
}