mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
add logic to render all the issues at once
This commit is contained in:
parent
76808e6dc9
commit
73ffed3fd0
@ -10,6 +10,10 @@ type Props = {
|
||||
as?: keyof JSX.IntrinsicElements;
|
||||
classNames?: string;
|
||||
alwaysRender?: boolean;
|
||||
getShouldRender?: (index: number) => boolean;
|
||||
updateRenderTracker?: (index: number, isVisble: boolean) => void;
|
||||
placeholderChildren?: ReactNode;
|
||||
index: number;
|
||||
};
|
||||
|
||||
const RenderIfVisible: React.FC<Props> = (props) => {
|
||||
@ -22,14 +26,26 @@ const RenderIfVisible: React.FC<Props> = (props) => {
|
||||
children,
|
||||
classNames = "",
|
||||
alwaysRender = false,
|
||||
...others
|
||||
getShouldRender,
|
||||
updateRenderTracker,
|
||||
placeholderChildren = null,
|
||||
index,
|
||||
} = props;
|
||||
const [shouldVisible, setShouldVisible] = useState<boolean>(alwaysRender);
|
||||
const defaultVisible = !!getShouldRender && getShouldRender(index);
|
||||
const [shouldVisible, setShouldVisible] = useState<boolean>(alwaysRender || defaultVisible);
|
||||
const placeholderHeight = useRef<number>(defaultHeight);
|
||||
const intersectionRef = useRef<HTMLElement | null>(null);
|
||||
|
||||
const isVisible = alwaysRender || shouldVisible;
|
||||
|
||||
useEffect(() => {
|
||||
if (getShouldRender && getShouldRender(index)) setShouldVisible(true);
|
||||
}, [getShouldRender, index]);
|
||||
|
||||
useEffect(() => {
|
||||
updateRenderTracker && updateRenderTracker(index, shouldVisible);
|
||||
}, [index, shouldVisible]);
|
||||
|
||||
// Set visibility with intersection observer
|
||||
useEffect(() => {
|
||||
if (intersectionRef.current) {
|
||||
@ -64,9 +80,9 @@ const RenderIfVisible: React.FC<Props> = (props) => {
|
||||
}
|
||||
}, [isVisible, intersectionRef, alwaysRender]);
|
||||
|
||||
const child = isVisible ? <>{children}</> : null;
|
||||
const child = isVisible ? <>{children}</> : placeholderChildren;
|
||||
const style = isVisible ? {} : { height: placeholderHeight.current, width: "100%" };
|
||||
const className = isVisible ? classNames : cn(classNames, "animate-pulse");
|
||||
const className = isVisible ? classNames : cn(classNames, "animate-pulse bg-custom-background-80");
|
||||
|
||||
return React.createElement(as, { ref: intersectionRef, style, className }, child);
|
||||
};
|
||||
|
@ -139,6 +139,7 @@ export const KanbanIssueBlock: React.FC<IssueBlockProps> = memo((props) => {
|
||||
defaultHeight={100}
|
||||
horizonatlOffset={50}
|
||||
alwaysRender={snapshot.isDragging}
|
||||
index={index}
|
||||
>
|
||||
<KanbanIssueDetailsBlock
|
||||
issue={issue}
|
||||
|
@ -1,5 +1,8 @@
|
||||
import { useRef } from "react";
|
||||
// components
|
||||
import { IssueBlock, IssueBlocksList, ListQuickAddIssueForm } from "components/issues";
|
||||
import { IssueBlock, ListQuickAddIssueForm } from "components/issues";
|
||||
import { HeaderGroupByCard } from "./headers/group-by-card";
|
||||
import RenderIfVisible from "components/core/render-if-visible-HOC";
|
||||
// hooks
|
||||
import { useLabel, useMember, useProject, useProjectState } from "hooks/store";
|
||||
// types
|
||||
@ -14,11 +17,8 @@ import {
|
||||
} from "@plane/types";
|
||||
import { EIssueActions } from "../types";
|
||||
// constants
|
||||
import { HeaderGroupByCard } from "./headers/group-by-card";
|
||||
import { getGroupByColumns, getIssueFlatList } from "../utils";
|
||||
import { EIssueListRow, TCreateModalStoreTypes } from "constants/issue";
|
||||
import { useRef } from "react";
|
||||
import RenderIfVisible from "components/core/render-if-visible-HOC";
|
||||
import { getGroupByColumns, getIssueFlatList } from "../utils";
|
||||
|
||||
export interface IGroupByList {
|
||||
issueIds: TGroupedIssues | TUnGroupedIssues | any;
|
||||
@ -108,7 +108,7 @@ const GroupByList: React.FC<IGroupByList> = (props) => {
|
||||
<div ref={containerRef} className="relative overflow-auto h-full w-full">
|
||||
{list &&
|
||||
list.length > 0 &&
|
||||
list.map((listRow: IIssueListRow) => {
|
||||
list.map((listRow: IIssueListRow, index) => {
|
||||
switch (listRow.type) {
|
||||
case EIssueListRow.HEADER:
|
||||
return (
|
||||
@ -159,6 +159,7 @@ const GroupByList: React.FC<IGroupByList> = (props) => {
|
||||
defaultHeight={45}
|
||||
root={containerRef}
|
||||
classNames={"relative border border-transparent border-b-custom-border-200 last:border-b-transparent"}
|
||||
index={index}
|
||||
>
|
||||
<IssueBlock
|
||||
issueId={listRow.id}
|
||||
@ -237,5 +238,3 @@ export const List: React.FC<IList> = (props) => {
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
@ -5,9 +5,8 @@ import { EIssueActions } from "../types";
|
||||
//components
|
||||
import { SpreadsheetIssueRow } from "./issue-row";
|
||||
import { SpreadsheetHeader } from "./spreadsheet-header";
|
||||
import { MutableRefObject, useRef } from "react";
|
||||
import { MutableRefObject } from "react";
|
||||
import RenderIfVisible from "components/core/render-if-visible-HOC";
|
||||
import { cn } from "helpers/common.helper";
|
||||
|
||||
type Props = {
|
||||
displayProperties: IIssueDisplayProperties;
|
||||
@ -49,8 +48,15 @@ export const SpreadsheetTable = observer((props: Props) => {
|
||||
isEstimateEnabled={isEstimateEnabled}
|
||||
/>
|
||||
<tbody>
|
||||
{issueIds.map((id) => (
|
||||
<RenderIfVisible key={id} as="tr" defaultHeight={44.5} root={containerRef}>
|
||||
{issueIds.map((id, index) => (
|
||||
<RenderIfVisible
|
||||
key={id}
|
||||
as="tr"
|
||||
defaultHeight={44.5}
|
||||
root={containerRef}
|
||||
placeholderChildren={<td colSpan={100} className="border-b-[0.5px]" />}
|
||||
index={index}
|
||||
>
|
||||
<SpreadsheetIssueRow
|
||||
issueId={id}
|
||||
displayProperties={displayProperties}
|
||||
|
32
web/hooks/use-virtualization-helper.tsx
Normal file
32
web/hooks/use-virtualization-helper.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
import { useRef } from "react";
|
||||
|
||||
const initializeRows = (rows: number) => {
|
||||
const initailizedRows: { [id: number]: boolean } = {};
|
||||
for (let i = 0; i < rows; ++i) initailizedRows[i] = true;
|
||||
return initailizedRows;
|
||||
};
|
||||
|
||||
const getMinMaxIndex = (renderedRows: { [id: number]: boolean }) => {
|
||||
const rowIndexes = Object.keys(renderedRows).sort((a: string, b: string) => parseInt(a) - parseInt(b));
|
||||
|
||||
return { min: parseInt(rowIndexes[0]), max: parseInt(rowIndexes[rowIndexes.length - 1]) };
|
||||
};
|
||||
|
||||
export const useVirtualizationHelper = (defaultNumberOfRows: number) => {
|
||||
const renderedRows = useRef<{ [id: number]: boolean }>(initializeRows(defaultNumberOfRows));
|
||||
|
||||
const getShouldRender = (index: number) => {
|
||||
const { min, max } = getMinMaxIndex(renderedRows.current);
|
||||
return min !== undefined && max !== undefined && index !== undefined && index >= min && max >= index;
|
||||
};
|
||||
|
||||
const updateRenderTracker = (index: number, isVisble: boolean) => {
|
||||
if (isVisble) renderedRows.current[index] = true;
|
||||
else if (renderedRows.current[index]) delete renderedRows.current[index];
|
||||
};
|
||||
|
||||
return {
|
||||
getShouldRender,
|
||||
updateRenderTracker,
|
||||
};
|
||||
};
|
Loading…
Reference in New Issue
Block a user