Skip to content

Commit 4b50b27

Browse files
authored
[WEB-2442] feat: Minor Timeline view Enhancements (#5987)
* fix timeline scroll to the right in some cases (cherry picked from commit 17043a6) * add get position based on Date (cherry picked from commit 2fbe22d) * Add sticky block name to enable it to be read throughout the block regardless of scroll position (cherry picked from commit 447af2e) * Enable blocks to have a single date on the block charts (cherry picked from commit cb055d5) * revert back date-range changes * change gradient of half blocks on Timeline * Add instance Id for Timeline Sidebar dragging to avoid enabling dropping of other drag instances * fix timeline scrolling height
1 parent f44db89 commit 4b50b27

File tree

16 files changed

+187
-90
lines changed

16 files changed

+187
-90
lines changed

web/ce/store/timeline/base-timeline.store.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@ import { computedFn } from "mobx-utils";
55
// components
66
import { ChartDataType, IBlockUpdateDependencyData, IGanttBlock, TGanttViews } from "@/components/gantt-chart";
77
import { currentViewDataWithView } from "@/components/gantt-chart/data";
8-
import { getDateFromPositionOnGantt, getItemPositionWidth } from "@/components/gantt-chart/views/helpers";
8+
import {
9+
getDateFromPositionOnGantt,
10+
getItemPositionWidth,
11+
getPositionFromDate,
12+
} from "@/components/gantt-chart/views/helpers";
913
// helpers
1014
import { renderFormattedPayloadDate } from "@/helpers/date-time.helper";
1115
// store
@@ -47,6 +51,7 @@ export interface IBaseTimelineStore {
4751
initGantt: () => void;
4852

4953
getDateFromPositionOnGantt: (position: number, offsetDays: number) => Date | undefined;
54+
getPositionFromDateOnGantt: (date: string | Date, offSetWidth: number) => number | undefined;
5055
}
5156

5257
export class BaseTimeLineStore implements IBaseTimelineStore {
@@ -186,7 +191,7 @@ export class BaseTimeLineStore implements IBaseTimelineStore {
186191
start_date: blockData?.start_date ?? undefined,
187192
target_date: blockData?.target_date ?? undefined,
188193
};
189-
if (this.currentViewData && this.currentViewData?.data?.startDate && this.currentViewData?.data?.dayWidth) {
194+
if (this.currentViewData && (this.currentViewData?.data?.startDate || this.currentViewData?.data?.dayWidth)) {
190195
block.position = getItemPositionWidth(this.currentViewData, block);
191196
}
192197

@@ -227,6 +232,15 @@ export class BaseTimeLineStore implements IBaseTimelineStore {
227232
return Math.round(position / this.currentViewData.data.dayWidth);
228233
};
229234

235+
/**
236+
* returns position of the date on chart
237+
*/
238+
getPositionFromDateOnGantt = computedFn((date: string | Date, offSetWidth: number) => {
239+
if (!this.currentViewData) return;
240+
241+
return getPositionFromDate(this.currentViewData, date, offSetWidth);
242+
});
243+
230244
/**
231245
* returns the date at which the position corresponds to on the timeline chart
232246
*/

web/core/components/gantt-chart/blocks/block-row.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export const BlockRow: React.FC<Props> = observer((props) => {
6868
// hide the block if it doesn't have start and target dates and showAllBlocks is false
6969
if (!block || !block.data || (!showAllBlocks && !(block.start_date && block.target_date))) return null;
7070

71-
const isBlockVisibleOnChart = block.start_date && block.target_date;
71+
const isBlockVisibleOnChart = block.start_date || block.target_date;
7272
const isBlockSelected = selectionHelpers.getIsEntitySelected(block.id);
7373
const isBlockFocused = selectionHelpers.getIsEntityActive(block.id);
7474
const isBlockHoveredOn = isBlockActive(block.id);

web/core/components/gantt-chart/blocks/block.tsx

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,11 @@ export const GanttChartBlock: React.FC<Props> = observer((props) => {
4646

4747
const { isMoving, handleBlockDrag } = useGanttResizable(block, resizableRef, ganttContainerRef, updateBlockDates);
4848

49-
// hide the block if it doesn't have start and target dates and showAllBlocks is false
50-
if (!block || (!showAllBlocks && !(block.start_date && block.target_date))) return null;
49+
const isBlockVisibleOnChart = block?.start_date || block?.target_date;
50+
const isBlockComplete = block?.start_date && block?.target_date;
5151

52-
const isBlockVisibleOnChart = block.start_date && block.target_date;
52+
// hide the block if it doesn't have start and target dates and showAllBlocks is false
53+
if (!block || (!showAllBlocks && !isBlockVisibleOnChart)) return null;
5354

5455
if (!block.data) return null;
5556

@@ -63,7 +64,7 @@ export const GanttChartBlock: React.FC<Props> = observer((props) => {
6364
ref={resizableRef}
6465
style={{
6566
height: `${BLOCK_HEIGHT}px`,
66-
transform: `translateX(${block.position?.marginLeft}px)`,
67+
marginLeft: `${block.position?.marginLeft}px`,
6768
width: `${block.position?.width}px`,
6869
}}
6970
>
@@ -88,7 +89,7 @@ export const GanttChartBlock: React.FC<Props> = observer((props) => {
8889
handleBlockDrag={handleBlockDrag}
8990
enableBlockLeftResize={enableBlockLeftResize}
9091
enableBlockRightResize={enableBlockRightResize}
91-
enableBlockMove={enableBlockMove}
92+
enableBlockMove={enableBlockMove && !!isBlockComplete}
9293
isMoving={isMoving}
9394
ganttContainerRef={ganttContainerRef}
9495
/>

web/core/components/gantt-chart/chart/main-content.tsx

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ import { IssueBulkOperationsRoot } from "@/plane-web/components/issues";
2828
import { useBulkOperationStatus } from "@/plane-web/hooks/use-bulk-operation-status";
2929
//
3030
import { GanttChartRowList } from "../blocks/block-row-list";
31-
import { GANTT_SELECT_GROUP, HEADER_HEIGHT } from "../constants";
31+
import { DEFAULT_BLOCK_WIDTH, GANTT_SELECT_GROUP, HEADER_HEIGHT } from "../constants";
3232
import { getItemPositionWidth } from "../views";
3333
import { TimelineDragHelper } from "./timeline-drag-helper";
3434

@@ -108,14 +108,20 @@ export const GanttChartMainContent: React.FC<Props> = observer((props) => {
108108

109109
const approxRangeLeft = scrollLeft;
110110
const approxRangeRight = scrollWidth - (scrollLeft + clientWidth);
111+
const calculatedRangeRight = itemsContainerWidth - (scrollLeft + clientWidth);
111112

112-
if (approxRangeRight < clientWidth) updateCurrentViewRenderPayload("right", currentView);
113-
if (approxRangeLeft < clientWidth) updateCurrentViewRenderPayload("left", currentView);
113+
if (approxRangeRight < clientWidth || calculatedRangeRight < clientWidth) {
114+
updateCurrentViewRenderPayload("right", currentView);
115+
}
116+
if (approxRangeLeft < clientWidth) {
117+
updateCurrentViewRenderPayload("left", currentView);
118+
}
114119
};
115120

116121
const handleScrollToBlock = (block: IGanttBlock) => {
117122
const scrollContainer = ganttContainerRef.current as HTMLDivElement;
118-
const scrollToDate = getDate(block.start_date);
123+
const scrollToEndDate = !block.start_date && block.target_date;
124+
const scrollToDate = block.start_date ? getDate(block.start_date) : getDate(block.target_date);
119125
let chartData;
120126

121127
if (!scrollContainer || !currentViewData || !scrollToDate) return;
@@ -129,7 +135,8 @@ export const GanttChartMainContent: React.FC<Props> = observer((props) => {
129135
const updatedPosition = getItemPositionWidth(chartData ?? currentViewData, block);
130136

131137
setTimeout(() => {
132-
if (updatedPosition) scrollContainer.scrollLeft = updatedPosition.marginLeft - 4;
138+
if (updatedPosition)
139+
scrollContainer.scrollLeft = updatedPosition.marginLeft - 4 - (scrollToEndDate ? DEFAULT_BLOCK_WIDTH : 0);
133140
});
134141
};
135142

@@ -189,6 +196,7 @@ export const GanttChartMainContent: React.FC<Props> = observer((props) => {
189196
style={{
190197
width: `${itemsContainerWidth}px`,
191198
transform: `translateY(${HEADER_HEIGHT}px)`,
199+
paddingBottom: `${HEADER_HEIGHT}px`,
192200
}}
193201
>
194202
<GanttChartRowList

web/core/components/gantt-chart/chart/views/month.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ export const MonthChartView: FC<any> = observer(() => {
2525
const marginLeftDays = getNumberOfDaysBetweenTwoDates(monthsStartDate, weeksStartDate);
2626

2727
return (
28-
<div className={`absolute top-0 left-0 h-max w-max flex`} style={{ minHeight: `calc(100% + ${HEADER_HEIGHT}px` }}>
28+
<div className={`absolute top-0 left-0 min-h-full h-max w-max flex`}>
2929
{currentViewData && (
3030
<div className="relative flex flex-col outline-[0.25px] outline outline-custom-border-200">
3131
{/** Header Div */}

web/core/components/gantt-chart/chart/views/quarter.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export const QuarterChartView: FC<any> = observer(() => {
1515
const quarterBlocks: IQuarterMonthBlock[] = groupMonthsToQuarters(monthBlocks);
1616

1717
return (
18-
<div className={`absolute top-0 left-0 h-max w-max flex`} style={{ minHeight: `calc(100% + ${HEADER_HEIGHT}px` }}>
18+
<div className={`absolute top-0 left-0 min-h-full h-max w-max flex`}>
1919
{currentViewData &&
2020
quarterBlocks?.map((quarterBlock, rootIndex) => (
2121
<div

web/core/components/gantt-chart/chart/views/week.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export const WeekChartView: FC<any> = observer(() => {
1313
const weekBlocks: IWeekBlock[] = renderView;
1414

1515
return (
16-
<div className={`absolute top-0 left-0 h-max w-max flex`} style={{ minHeight: `calc(100% + ${HEADER_HEIGHT}px` }}>
16+
<div className={`absolute top-0 left-0 min-h-full h-max w-max flex`}>
1717
{currentViewData &&
1818
weekBlocks?.map((block, rootIndex) => (
1919
<div

web/core/components/gantt-chart/constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,6 @@ export const GANTT_BREADCRUMBS_HEIGHT = 40;
66

77
export const SIDEBAR_WIDTH = 360;
88

9+
export const DEFAULT_BLOCK_WIDTH = 60;
10+
911
export const GANTT_SELECT_GROUP = "gantt-issues";

web/core/components/gantt-chart/helpers/blockResizables/use-gantt-resizable.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ export const useGanttResizable = (
7171
// calculate new marginLeft and update the initial marginLeft to the newly calculated one
7272
marginLeft = Math.round(mouseX / dayWidth) * dayWidth;
7373
// get Dimensions from dom's style
74-
const prevMarginLeft = parseFloat(resizableDiv.style.transform.slice(11, -3));
74+
const prevMarginLeft = parseFloat(resizableDiv.style.marginLeft.slice(0, -2));
7575
const prevWidth = parseFloat(resizableDiv.style.width.slice(0, -2));
7676
// calculate new width
7777
const marginDelta = prevMarginLeft - marginLeft;
@@ -88,7 +88,7 @@ export const useGanttResizable = (
8888
if (width < dayWidth) return;
8989

9090
resizableDiv.style.width = `${width}px`;
91-
resizableDiv.style.transform = `translateX(${marginLeft}px)`;
91+
resizableDiv.style.marginLeft = `${marginLeft}px`;
9292

9393
const deltaLeft = Math.round((marginLeft - (block.position?.marginLeft ?? 0)) / dayWidth) * dayWidth;
9494
const deltaWidth = Math.round((width - (block.position?.width ?? 0)) / dayWidth) * dayWidth;

web/core/components/gantt-chart/sidebar/gantt-dnd-HOC.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export const GanttDnDHOC = observer((props: Props) => {
3434
draggable({
3535
element,
3636
canDrag: () => isDragEnabled,
37-
getInitialData: () => ({ id }),
37+
getInitialData: () => ({ id, dragInstanceId: "GANTT_REORDER" }),
3838
onDragStart: () => {
3939
setIsDragging(true);
4040
},
@@ -44,7 +44,7 @@ export const GanttDnDHOC = observer((props: Props) => {
4444
}),
4545
dropTargetForElements({
4646
element,
47-
canDrop: ({ source }) => source?.data?.id !== id,
47+
canDrop: ({ source }) => source?.data?.id !== id && source?.data?.dragInstanceId === "GANTT_REORDER",
4848
getData: ({ input, element }) => {
4949
const data = { id };
5050

0 commit comments

Comments
 (0)