Skip to content

Commit 10d011f

Browse files
committed
fix(ui): freight timeline scroll and overlap
Signed-off-by: Mayursinh Sarvaiya <marvinduff97@gmail.com>
1 parent 5593414 commit 10d011f

1 file changed

Lines changed: 83 additions & 67 deletions

File tree

ui/src/features/project/pipelines/freight/freight-timeline.tsx

Lines changed: 83 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,8 @@ export const FreightTimeline = (props: { freights: Freight[]; project: string })
144144
]);
145145

146146
const freightListStyleRef = useRef<HTMLDivElement>(null);
147+
const freightListContainerRef = useRef<HTMLDivElement>(null);
148+
const carouselButtonRef = useRef<HTMLDivElement>(null);
147149

148150
const loadMore = useCallback(() => {
149151
setVisibleCount((prev) => Math.min(prev + PAGE_SIZE, filteredFreights.length));
@@ -162,15 +164,21 @@ export const FreightTimeline = (props: { freights: Freight[]; project: string })
162164
};
163165

164166
const scrollCarouselRight = () => {
165-
const right = freightListStyleRef.current?.style.right || '0px';
167+
const rightStr = freightListStyleRef.current?.style.right || '0px';
166168

167-
const nextRight = +right.slice(0, -2) + 160;
169+
const right = +rightStr.slice(0, -2);
168170

169-
if (nextRight >= (freightListStyleRef.current?.clientWidth || 0) / 2) {
170-
// At the edge — load more items if available
171-
if (visibleCount < filteredFreights.length) {
172-
loadMore();
173-
}
171+
const actualScrollEndFromRight =
172+
(freightListStyleRef.current?.getBoundingClientRect().width ?? 0) -
173+
(freightListContainerRef.current?.getBoundingClientRect().width ?? 0);
174+
175+
const nextRight = right + 160;
176+
177+
const isFreightScrollEnd = right > actualScrollEndFromRight;
178+
179+
if (isFreightScrollEnd && visibleCount < filteredFreights.length) {
180+
loadMore();
181+
} else if (isFreightScrollEnd) {
174182
return;
175183
}
176184

@@ -210,84 +218,92 @@ export const FreightTimeline = (props: { freights: Freight[]; project: string })
210218
preferredFilter={freightTimelineControllerContext.preferredFilter}
211219
/>
212220
<div
213-
className={classNames('w-full flex relative px-5', {
214-
'overflow-hidden': !dndContext.active
215-
})}
221+
className='flex flex-1 min-w-0'
216222
onWheel={(e) => {
217223
if (e.deltaY > 0) {
218224
scrollCarouselRight();
219225
} else if (e.deltaY < 0) {
220226
scrollCarouselLeft();
221227
}
222228
}}
229+
ref={freightListContainerRef}
223230
>
224231
<div
225-
className='flex gap-1 relative right-0 transition-[right] duration-300 ease-out'
226-
ref={freightListStyleRef}
232+
className='bg-gray-100 px-1 flex items-center cursor-pointer rounded-sm hover:bg-gray-200 flex-shrink-0'
233+
onClick={() => {
234+
scrollCarouselLeft();
235+
}}
236+
ref={carouselButtonRef}
237+
>
238+
<FontAwesomeIcon icon={faCaretLeft} />
239+
</div>
240+
241+
<div
242+
className={classNames('flex-1 relative min-w-0', {
243+
'overflow-hidden': !dndContext.active
244+
})}
227245
>
228-
{filteredFreights.slice(0, visibleCount).map((freight) => {
229-
const freightSoakTime = soakTime?.[freight?.metadata?.name || ''];
246+
<div
247+
className='w-fit flex gap-1 relative right-0 transition-[right] duration-300 ease-out'
248+
ref={freightListStyleRef}
249+
>
250+
{filteredFreights.slice(0, visibleCount).map((freight) => {
251+
const freightSoakTime = soakTime?.[freight?.metadata?.name || ''];
252+
253+
const promotionEligible = Boolean(
254+
promotionEligibleFreight?.find(
255+
(f) => f?.metadata?.name === freight?.metadata?.name
256+
)
257+
);
230258

231-
const promotionEligible = Boolean(
232-
promotionEligibleFreight?.find((f) => f?.metadata?.name === freight?.metadata?.name)
233-
);
259+
if (freight.count && freight.count > 0) {
260+
return (
261+
<FreightExpandTile
262+
key={`expand-tile-${freight?.metadata?.uid}-${freight?.count}`}
263+
count={freight.count}
264+
/>
265+
);
266+
}
234267

235-
if (freight.count && freight.count > 0) {
236268
return (
237-
<FreightExpandTile
238-
key={`expand-tile-${freight?.metadata?.uid}-${freight?.count}`}
239-
count={freight.count}
269+
<FreightCard
270+
key={`${freight?.metadata?.uid}-${freight?.count}`}
271+
className='h-full'
272+
stagesInFreight={
273+
dictionaryContext?.freightInStages?.[freight?.metadata?.name || ''] || []
274+
}
275+
freight={freight}
276+
preferredFilter={freightTimelineControllerContext.preferredFilter}
277+
setViewingFreight={setViewingFreight}
278+
viewingFreight={viewingFreight}
279+
inUse={
280+
(dictionaryContext?.freightInStages[freight?.metadata?.name || '']?.length ||
281+
0) > 0
282+
}
283+
stageColorMap={colorContext.stageColorMap}
284+
promote={isPromotionMode}
285+
isPromotionEligibleLoading={getPromotionEligibleFreightQuery.isFetching}
286+
promotionEligible={promotionEligible}
287+
onReviewAndPromote={() => {
288+
const stage = actionContext?.action?.stage?.metadata?.name || '';
289+
290+
navigate(
291+
generatePath(paths.promote, {
292+
name: props.project,
293+
freight: freight?.metadata?.name,
294+
stage: stage
295+
})
296+
);
297+
}}
298+
soakTime={freightSoakTime}
240299
/>
241300
);
242-
}
243-
244-
return (
245-
<FreightCard
246-
key={`${freight?.metadata?.uid}-${freight?.count}`}
247-
className='h-full'
248-
stagesInFreight={
249-
dictionaryContext?.freightInStages?.[freight?.metadata?.name || ''] || []
250-
}
251-
freight={freight}
252-
preferredFilter={freightTimelineControllerContext.preferredFilter}
253-
setViewingFreight={setViewingFreight}
254-
viewingFreight={viewingFreight}
255-
inUse={
256-
(dictionaryContext?.freightInStages[freight?.metadata?.name || '']?.length ||
257-
0) > 0
258-
}
259-
stageColorMap={colorContext.stageColorMap}
260-
promote={isPromotionMode}
261-
isPromotionEligibleLoading={getPromotionEligibleFreightQuery.isFetching}
262-
promotionEligible={promotionEligible}
263-
onReviewAndPromote={() => {
264-
const stage = actionContext?.action?.stage?.metadata?.name || '';
265-
266-
navigate(
267-
generatePath(paths.promote, {
268-
name: props.project,
269-
freight: freight?.metadata?.name,
270-
stage: stage
271-
})
272-
);
273-
}}
274-
soakTime={freightSoakTime}
275-
/>
276-
);
277-
})}
278-
</div>
279-
280-
<div
281-
className='absolute left-0 h-full bg-gray-100 px-1 flex items-center cursor-pointer rounded-sm hover:bg-gray-200'
282-
onClick={() => {
283-
scrollCarouselLeft();
284-
}}
285-
>
286-
<FontAwesomeIcon icon={faCaretLeft} />
301+
})}
302+
</div>
287303
</div>
288304

289305
<div
290-
className='absolute right-0 h-full bg-gray-100 px-1 flex items-center cursor-pointer rounded-sm hover:bg-gray-200'
306+
className='bg-gray-100 px-1 flex items-center cursor-pointer rounded-sm hover:bg-gray-200 flex-shrink-0'
291307
onClick={() => {
292308
scrollCarouselRight();
293309
}}

0 commit comments

Comments
 (0)