Skip to content

Commit c1fad40

Browse files
authored
fix(frontend): Fixing Resizable Panels UI bugs (#2827)
1 parent 53d5886 commit c1fad40

18 files changed

+382
-403
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import * as Spaces from 'react-spaces';
2+
3+
const FillPanel: React.FC = ({children}) => <Spaces.Fill>{children}</Spaces.Fill>;
4+
5+
export default FillPanel;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import * as Spaces from 'react-spaces';
2+
import useResizablePanel, {TPanel, TSize} from '../ResizablePanels/hooks/useResizablePanel';
3+
import Splitter from '../ResizablePanels/Splitter';
4+
5+
interface IProps {
6+
panel: TPanel;
7+
order?: number;
8+
children(size: TSize): React.ReactNode;
9+
}
10+
11+
const LeftPanel = ({panel, order = 1, children}: IProps) => {
12+
const {size, toggle, onStopResize} = useResizablePanel({panel});
13+
14+
return (
15+
<Spaces.LeftResizable
16+
onResizeEnd={newSize => onStopResize(newSize)}
17+
minimumSize={size.minSize}
18+
maximumSize={size.maxSize}
19+
size={size.size}
20+
key={size.name}
21+
order={order}
22+
handleRender={props => <Splitter {...props} name={size.name} isOpen={size.isOpen} onClick={() => toggle()} />}
23+
>
24+
{children(size)}
25+
</Spaces.LeftResizable>
26+
);
27+
};
28+
29+
export default LeftPanel;

web/src/components/ResizablePanels/ResizablePanels.styled.ts

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import styled, {createGlobalStyle} from 'styled-components';
1+
import styled, {createGlobalStyle, css} from 'styled-components';
22

33
export const GlobalStyle = createGlobalStyle`
44
.spaces-resize-handle {
@@ -11,6 +11,30 @@ export const ButtonContainer = styled.div`
1111
position: absolute;
1212
right: -12px;
1313
top: 48px;
14+
z-index: 100;
1415
`;
1516

1617
export const SplitterContainer = styled.div``;
18+
19+
export const PanelContainer = styled.div<{$isOpen: boolean}>`
20+
background-color: ${({theme}) => theme.color.white};
21+
box-shadow: 0 20px 24px rgba(153, 155, 168, 0.18);
22+
height: 100%;
23+
overflow: visible;
24+
overflow-y: scroll;
25+
position: relative;
26+
27+
> div {
28+
opacity: 0;
29+
pointer-events: none;
30+
}
31+
32+
${({$isOpen}) =>
33+
$isOpen &&
34+
css`
35+
> div {
36+
opacity: 1;
37+
pointer-events: auto;
38+
}
39+
`}
40+
`;

web/src/components/ResizablePanels/ResizablePanels.tsx

Lines changed: 2 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,12 @@
11
import * as Spaces from 'react-spaces';
2-
import {useCallback, useMemo} from 'react';
32
import * as S from './ResizablePanels.styled';
4-
import useResizablePanels, {TSize} from './hooks/useResizablePanels';
5-
import Splitter from './Splitter';
6-
7-
export type TPanelComponentProps = {size: TSize};
8-
9-
export type TPanel = {
10-
name: string;
11-
isDefaultOpen?: boolean;
12-
minSize?: number;
13-
maxSize?: number;
14-
position?: 'left' | 'right' | undefined;
15-
component(props: TPanelComponentProps): React.ReactElement;
16-
};
17-
18-
interface IProps {
19-
panels: TPanel[];
20-
}
21-
22-
const ResizablePanels = ({panels}: IProps) => {
23-
const {onStopResize, toggle, sizes} = useResizablePanels({panels});
24-
25-
const getPanel = useCallback((name: string) => panels.find(panel => panel.name === name), [panels]);
26-
27-
const elements = useMemo(
28-
() =>
29-
Object.values(sizes).reduce<React.ReactNode[]>((acc, size, index) => {
30-
const {component: Component, position} = getPanel(size.name)!;
31-
32-
if (position === 'left') {
33-
return acc.concat([
34-
<Spaces.LeftResizable
35-
onResizeEnd={newSize => onStopResize(size, newSize)}
36-
minimumSize={size.minSize}
37-
maximumSize={size.maxSize}
38-
size={size.size}
39-
key={size.name}
40-
handleRender={props => (
41-
<Splitter {...props} name={size.name} isOpen={size.isOpen} onClick={() => toggle(size)} />
42-
)}
43-
order={index + 1}
44-
>
45-
<Component size={size} />
46-
</Spaces.LeftResizable>,
47-
]);
48-
}
49-
50-
if (position === 'right') {
51-
return acc.concat([
52-
<Spaces.RightResizable
53-
onResizeEnd={newSize => onStopResize(size, newSize)}
54-
minimumSize={size.minSize}
55-
maximumSize={size.maxSize}
56-
size={size.size}
57-
key={size.name}
58-
handleRender={props => (
59-
<Splitter {...props} name={size.name} isOpen={!size.isOpen} onClick={() => toggle(size)} />
60-
)}
61-
order={index + 1}
62-
>
63-
<Component size={size} />
64-
</Spaces.RightResizable>,
65-
]);
66-
}
67-
68-
return acc.concat(
69-
<Spaces.Fill>
70-
<Component size={size} />
71-
</Spaces.Fill>
72-
);
73-
}, []),
74-
[getPanel, onStopResize, sizes, toggle]
75-
);
763

4+
const ResizablePanels: React.FC = ({children}) => {
775
return (
786
<>
797
<S.GlobalStyle />
808
<Spaces.Fixed height="100%" width="100vw">
81-
{elements}
9+
{children}
8210
</Spaces.Fixed>
8311
</>
8412
);
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import * as Spaces from 'react-spaces';
2+
import Splitter from '../ResizablePanels/Splitter';
3+
import useResizablePanel, {TPanel, TSize} from '../ResizablePanels/hooks/useResizablePanel';
4+
5+
interface IProps {
6+
panel: TPanel;
7+
order?: number;
8+
children(size: TSize): React.ReactNode;
9+
}
10+
11+
const RightPanel = ({panel, order = 1, children}: IProps) => {
12+
const {size, toggle, onStopResize} = useResizablePanel({panel});
13+
14+
return (
15+
<Spaces.RightResizable
16+
onResizeEnd={newSize => onStopResize(newSize)}
17+
minimumSize={size.minSize}
18+
maximumSize={size.maxSize}
19+
size={size.size}
20+
key={size.name}
21+
order={order}
22+
handleRender={props => <Splitter {...props} name={size.name} isOpen={!size.isOpen} onClick={() => toggle()} />}
23+
>
24+
{children(size)}
25+
</Spaces.RightResizable>
26+
);
27+
};
28+
29+
export default RightPanel;
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import {useCallback, useState} from 'react';
2+
3+
export type TPanel = {
4+
name: string;
5+
isDefaultOpen?: boolean;
6+
minSize?: number;
7+
maxSize?: number;
8+
};
9+
10+
interface IProps {
11+
panel: TPanel;
12+
}
13+
14+
export type TSize = Exclude<TPanel, 'component'> & {
15+
size: number;
16+
isOpen: boolean;
17+
minSize: number;
18+
maxSize: number;
19+
};
20+
21+
const useResizablePanel = ({panel}: IProps) => {
22+
const [size, setSize] = useState<TSize>({
23+
...panel,
24+
size: (panel.isDefaultOpen && panel.maxSize) || panel.minSize || 0,
25+
isOpen: panel.isDefaultOpen || false,
26+
minSize: panel.minSize || 0,
27+
maxSize: panel.maxSize || 0,
28+
});
29+
30+
const toggle = useCallback(() => {
31+
if (size.size <= size.minSize) {
32+
const currentSize = size.maxSize;
33+
setSize({
34+
...size,
35+
size: currentSize,
36+
isOpen: currentSize > size.minSize,
37+
});
38+
return;
39+
}
40+
setSize({
41+
...size,
42+
size: size.minSize || 0,
43+
isOpen: false,
44+
});
45+
}, [size]);
46+
47+
const onStopResize = useCallback(
48+
newSize => {
49+
const currentSize = Number(newSize);
50+
51+
setSize({
52+
...size,
53+
size: currentSize,
54+
isOpen: currentSize > size.minSize,
55+
});
56+
},
57+
[size]
58+
);
59+
60+
return {toggle, onStopResize, size};
61+
};
62+
63+
export default useResizablePanel;

web/src/components/ResizablePanels/hooks/useResizablePanels.ts

Lines changed: 0 additions & 76 deletions
This file was deleted.
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,8 @@
1+
import LeftPanel from './LeftPanel';
2+
import RightPanel from './RightPanel';
3+
import FillPanel from './FillPanel';
4+
import {PanelContainer} from './ResizablePanels.styled';
5+
16
// eslint-disable-next-line no-restricted-exports
27
export {default} from './ResizablePanels';
8+
export {LeftPanel, RightPanel, FillPanel, PanelContainer};

web/src/components/RunDetailTest/RunDetailTest.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
import PanelLayout from 'components/ResizablePanels';
2-
import {useMemo} from 'react';
31
import TestRun from 'models/TestRun.model';
42
import TestRunEvent from 'models/TestRunEvent.model';
53
import * as S from './RunDetailTest.styled';
6-
import {getTestPanel} from './TestPanel';
74
import SetupAlert from '../SetupAlert/SetupAlert';
8-
import {getSpanDetailsPanel} from './SpanDetailPanel';
5+
import ResizablePanels from '../ResizablePanels/ResizablePanels';
6+
import SpanDetailsPanel from './SpanDetailsPanel';
7+
import TestPanel from './TestPanel';
98

109
interface IProps {
1110
run: TestRun;
@@ -14,11 +13,13 @@ interface IProps {
1413
}
1514

1615
const RunDetailTest = ({run, runEvents, testId}: IProps) => {
17-
const panels = useMemo(() => [getSpanDetailsPanel(), getTestPanel(testId, run, runEvents)], [run, runEvents, testId]);
1816
return (
1917
<S.Container>
2018
<SetupAlert />
21-
<PanelLayout panels={panels} />
19+
<ResizablePanels>
20+
<SpanDetailsPanel />
21+
<TestPanel run={run} runEvents={runEvents} testId={testId} />
22+
</ResizablePanels>
2223
</S.Container>
2324
);
2425
};

web/src/components/RunDetailTest/SpanDetailPanel.tsx

Lines changed: 0 additions & 24 deletions
This file was deleted.

0 commit comments

Comments
 (0)