Skip to content

Commit e35f0b8

Browse files
committed
feat: Collapse - add Collapse component, DeploymentConfigDiff - handling for scrolling selected config into view
1 parent 315a320 commit e35f0b8

File tree

4 files changed

+92
-51
lines changed

4 files changed

+92
-51
lines changed

src/Shared/Components/CICDHistory/DeploymentHistoryConfigDiff/DeploymentHistoryConfigDiffCompare.tsx

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ import {
1111
} from '@Shared/Components/SelectPicker'
1212
import { ComponentSizeType } from '@Shared/constants'
1313

14-
import { DeploymentHistoryDiffDetailedProps, DeploymentHistoryConfigDiffQueryParams } from './types'
14+
import {
15+
DeploymentHistoryDiffDetailedProps,
16+
DeploymentHistoryConfigDiffQueryParams,
17+
DeploymentHistoryConfigDiffRouteParams,
18+
} from './types'
1519
import { getPipelineDeploymentsOptions, parseDeploymentHistoryDiffSearchParams } from './utils'
1620

1721
export const DeploymentHistoryConfigDiffCompare = ({
@@ -28,7 +32,8 @@ export const DeploymentHistoryConfigDiffCompare = ({
2832
...props
2933
}: DeploymentHistoryDiffDetailedProps) => {
3034
// HOOKS
31-
const { path, params } = useRouteMatch()
35+
const { path, params } = useRouteMatch<DeploymentHistoryConfigDiffRouteParams>()
36+
const { resourceType, resourceName } = params
3237

3338
// URL FILTERS
3439
const { compareWfrId, updateSearchParams, sortBy, sortOrder, handleSorting } = useUrlFilters<
@@ -118,12 +123,13 @@ export const DeploymentHistoryConfigDiffCompare = ({
118123
showDetailedDiffState
119124
navHeading={`Comparing ${envName}`}
120125
headerText={!pipelineDeploymentsOptions.length ? '' : undefined} // using `undefined` to ensure component picks default value
126+
scrollIntoViewId={`${resourceType}${resourceName ? `-${resourceName}` : ''}`}
121127
navHelpText={
122128
compareWfrId
123129
? `Showing diff in configuration deployed on: ${pipelineDeploymentsOptions.find(({ value }) => value === compareWfrId).label} & ${currentDeployment}`
124130
: null
125131
}
126-
goBackURL={generatePath(path.split('/:resourceType')[0], params)}
132+
goBackURL={generatePath(path.split('/:resourceType')[0], { ...params })}
127133
selectorsConfig={selectorsConfig}
128134
sortingConfig={sortingConfig}
129135
scopeVariablesConfig={scopeVariablesConfig}
Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,41 @@
1+
import { useEffect, useState, useRef, useMemo } from 'react'
2+
13
import { CollapseProps } from './types'
24

3-
export const Collapse = ({ expand, children }: CollapseProps) => (
4-
// TODO: removed animation because of miscalculations (broken with auto editor height)
5-
<div>{expand ? children : null}</div>
6-
)
5+
/**
6+
* Collapse component for expanding/collapsing content with smooth transitions.
7+
* Dynamically calculates and applies height based on the content, with support
8+
* for callback execution when the transition ends.
9+
*/
10+
export const Collapse = ({ expand, onTransitionEnd, children }: CollapseProps) => {
11+
// Ref to access the content container
12+
const contentRef = useRef<HTMLDivElement>(null)
13+
// State for dynamically calculated height
14+
const [contentHeight, setContentHeight] = useState(0)
15+
16+
// Calculate and update content height when children change or initially on mount
17+
useEffect(() => {
18+
if (contentRef.current) {
19+
const _contentHeight = contentRef.current.clientHeight || 0
20+
setContentHeight(_contentHeight)
21+
}
22+
}, [children])
23+
24+
const collapseStyle = useMemo(
25+
() => ({
26+
// Set height based on the 'expand' prop
27+
height: expand ? contentHeight : 0,
28+
transition: 'height 200ms ease-out',
29+
// Hide content overflow during collapse
30+
overflow: 'hidden',
31+
}),
32+
[expand, contentHeight],
33+
)
34+
35+
return (
36+
<div style={collapseStyle} onTransitionEnd={onTransitionEnd}>
37+
{/* Content container with reference to calculate height */}
38+
<div ref={contentRef}>{children}</div>
39+
</div>
40+
)
41+
}
Lines changed: 33 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,41 @@
1-
import { forwardRef } from 'react'
2-
31
import { ReactComponent as ICCaretDown } from '@Icons/ic-caret-down.svg'
42

53
import { Collapse } from '../Collapse'
64
import { DeploymentConfigDiffAccordionProps, DeploymentConfigDiffState } from './DeploymentConfigDiff.types'
75
import { diffStateTextColorMap, diffStateTextMap } from './DeploymentConfigDiff.constants'
86

9-
export const DeploymentConfigDiffAccordion = forwardRef<HTMLDivElement, DeploymentConfigDiffAccordionProps>(
10-
(
11-
{
12-
diffState,
13-
showDetailedDiffState,
14-
children,
15-
title,
16-
id,
17-
isExpanded,
18-
onClick,
19-
onTransitionEnd,
20-
}: DeploymentConfigDiffAccordionProps,
21-
ref,
22-
) => (
23-
<div ref={ref} id={id} className="dc__border br-4 deployment-config-diff__accordion">
24-
<button
25-
type="button"
26-
className="dc__unset-button-styles px-16 py-10 flexbox dc__align-items-center dc__gap-8 w-100 br-4 bcn-50 dc__position-sticky dc__top-0 dc__zi-10"
27-
aria-label="expand-collapse-btn"
28-
onClick={onClick}
7+
export const DeploymentConfigDiffAccordion = ({
8+
diffState,
9+
showDetailedDiffState,
10+
children,
11+
title,
12+
id,
13+
isExpanded,
14+
onClick,
15+
onTransitionEnd,
16+
}: DeploymentConfigDiffAccordionProps) => (
17+
<div id={id} className="dc__border br-4 deployment-config-diff__accordion">
18+
<button
19+
type="button"
20+
className="dc__unset-button-styles px-16 py-10 flexbox dc__align-items-center dc__gap-8 w-100 br-4 bcn-50 dc__position-sticky dc__top-0 dc__zi-10"
21+
aria-label="expand-collapse-btn"
22+
onClick={onClick}
23+
>
24+
<ICCaretDown
25+
className="icon-dim-16 fsn-6 rotate"
26+
style={{ ['--rotateBy' as string]: isExpanded ? '360deg' : '270deg' }}
27+
/>
28+
<p className="m-0 cn-9 fs-13 lh-20">{title}</p>
29+
<p
30+
className={`m-0 fs-13 lh-20 fw-6 ${showDetailedDiffState ? diffStateTextColorMap[diffState] : (diffState !== DeploymentConfigDiffState.NO_DIFF && 'cy-7') || 'cg-7'}`}
2931
>
30-
<ICCaretDown
31-
className="icon-dim-16 fsn-6 rotate"
32-
style={{ ['--rotateBy' as string]: isExpanded ? '360deg' : '270deg' }}
33-
/>
34-
<p className="m-0 cn-9 fs-13 lh-20">{title}</p>
35-
<p
36-
className={`m-0 fs-13 lh-20 fw-6 ${showDetailedDiffState ? diffStateTextColorMap[diffState] : (diffState !== DeploymentConfigDiffState.NO_DIFF && 'cy-7') || 'cg-7'}`}
37-
>
38-
{showDetailedDiffState
39-
? diffStateTextMap[diffState]
40-
: `${diffState !== DeploymentConfigDiffState.NO_DIFF ? 'Has' : 'No'} difference`}
41-
</p>
42-
</button>
43-
<Collapse expand={isExpanded} onTransitionEnd={onTransitionEnd}>
44-
{children}
45-
</Collapse>
46-
</div>
47-
),
32+
{showDetailedDiffState
33+
? diffStateTextMap[diffState]
34+
: `${diffState !== DeploymentConfigDiffState.NO_DIFF ? 'Has' : 'No'} difference`}
35+
</p>
36+
</button>
37+
<Collapse expand={isExpanded} onTransitionEnd={onTransitionEnd}>
38+
{children}
39+
</Collapse>
40+
</div>
4841
)

src/Shared/Components/DeploymentConfigDiff/DeploymentConfigDiffMain.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Fragment, TransitionEvent, useEffect, useState } from 'react'
1+
import { Fragment, useEffect, useRef, useState } from 'react'
22
import Tippy from '@tippyjs/react'
33

44
import { ReactComponent as ICSortArrowDown } from '@Icons/ic-sort-arrow-down.svg'
@@ -19,6 +19,7 @@ import {
1919
DeploymentConfigDiffMainProps,
2020
DeploymentConfigDiffSelectPickerProps,
2121
DeploymentConfigDiffState,
22+
DeploymentConfigDiffAccordionProps,
2223
} from './DeploymentConfigDiff.types'
2324

2425
export const DeploymentConfigDiffMain = ({
@@ -35,15 +36,20 @@ export const DeploymentConfigDiffMain = ({
3536
// STATES
3637
const [expandedView, setExpandedView] = useState<Record<string | number, boolean>>({})
3738

39+
// REFS
40+
/** Ref to track if the element should scroll into view after expanding */
41+
const scrollIntoViewAfterExpand = useRef(false)
42+
3843
const handleAccordionClick = (id: string) => () => {
3944
setExpandedView({
4045
...expandedView,
4146
[id]: !expandedView[id],
4247
})
4348
}
4449

45-
const handleTransitionEnd = (id: string) => (e: TransitionEvent<HTMLDivElement>) => {
46-
if (e.target === e.currentTarget && scrollIntoViewId === id) {
50+
const onTransitionEnd: DeploymentConfigDiffAccordionProps['onTransitionEnd'] = (e) => {
51+
if (scrollIntoViewAfterExpand.current && e.target === e.currentTarget) {
52+
scrollIntoViewAfterExpand.current = false
4753
const element = document.querySelector(`#${scrollIntoViewId}`)
4854
element?.scrollIntoView({ block: 'start' })
4955
}
@@ -65,6 +71,7 @@ export const DeploymentConfigDiffMain = ({
6571

6672
useEffect(() => {
6773
if (scrollIntoViewId) {
74+
scrollIntoViewAfterExpand.current = true
6875
setExpandedView((prev) => ({ ...prev, [scrollIntoViewId]: true }))
6976
}
7077
}, [scrollIntoViewId])
@@ -176,7 +183,7 @@ export const DeploymentConfigDiffMain = ({
176183
isExpanded={expandedView[id]}
177184
diffState={diffState}
178185
onClick={handleAccordionClick(id)}
179-
onTransitionEnd={handleTransitionEnd(id)}
186+
onTransitionEnd={onTransitionEnd}
180187
showDetailedDiffState={showDetailedDiffState}
181188
>
182189
{singleView ? (

0 commit comments

Comments
 (0)