Skip to content

Commit

Permalink
fix(frontend): Fixing Resizable Panels UI bugs (#2827)
Browse files Browse the repository at this point in the history
  • Loading branch information
xoscar committed Jun 26, 2023
1 parent 53d5886 commit c1fad40
Show file tree
Hide file tree
Showing 18 changed files with 382 additions and 403 deletions.
5 changes: 5 additions & 0 deletions web/src/components/ResizablePanels/FillPanel.tsx
@@ -0,0 +1,5 @@
import * as Spaces from 'react-spaces';

const FillPanel: React.FC = ({children}) => <Spaces.Fill>{children}</Spaces.Fill>;

export default FillPanel;
29 changes: 29 additions & 0 deletions web/src/components/ResizablePanels/LeftPanel.tsx
@@ -0,0 +1,29 @@
import * as Spaces from 'react-spaces';
import useResizablePanel, {TPanel, TSize} from '../ResizablePanels/hooks/useResizablePanel';
import Splitter from '../ResizablePanels/Splitter';

interface IProps {
panel: TPanel;
order?: number;
children(size: TSize): React.ReactNode;
}

const LeftPanel = ({panel, order = 1, children}: IProps) => {
const {size, toggle, onStopResize} = useResizablePanel({panel});

return (
<Spaces.LeftResizable
onResizeEnd={newSize => onStopResize(newSize)}
minimumSize={size.minSize}
maximumSize={size.maxSize}
size={size.size}
key={size.name}
order={order}
handleRender={props => <Splitter {...props} name={size.name} isOpen={size.isOpen} onClick={() => toggle()} />}
>
{children(size)}
</Spaces.LeftResizable>
);
};

export default LeftPanel;
26 changes: 25 additions & 1 deletion web/src/components/ResizablePanels/ResizablePanels.styled.ts
@@ -1,4 +1,4 @@
import styled, {createGlobalStyle} from 'styled-components';
import styled, {createGlobalStyle, css} from 'styled-components';

export const GlobalStyle = createGlobalStyle`
.spaces-resize-handle {
Expand All @@ -11,6 +11,30 @@ export const ButtonContainer = styled.div`
position: absolute;
right: -12px;
top: 48px;
z-index: 100;
`;

export const SplitterContainer = styled.div``;

export const PanelContainer = styled.div<{$isOpen: boolean}>`
background-color: ${({theme}) => theme.color.white};
box-shadow: 0 20px 24px rgba(153, 155, 168, 0.18);
height: 100%;
overflow: visible;
overflow-y: scroll;
position: relative;
> div {
opacity: 0;
pointer-events: none;
}
${({$isOpen}) =>
$isOpen &&
css`
> div {
opacity: 1;
pointer-events: auto;
}
`}
`;
76 changes: 2 additions & 74 deletions web/src/components/ResizablePanels/ResizablePanels.tsx
@@ -1,84 +1,12 @@
import * as Spaces from 'react-spaces';
import {useCallback, useMemo} from 'react';
import * as S from './ResizablePanels.styled';
import useResizablePanels, {TSize} from './hooks/useResizablePanels';
import Splitter from './Splitter';

export type TPanelComponentProps = {size: TSize};

export type TPanel = {
name: string;
isDefaultOpen?: boolean;
minSize?: number;
maxSize?: number;
position?: 'left' | 'right' | undefined;
component(props: TPanelComponentProps): React.ReactElement;
};

interface IProps {
panels: TPanel[];
}

const ResizablePanels = ({panels}: IProps) => {
const {onStopResize, toggle, sizes} = useResizablePanels({panels});

const getPanel = useCallback((name: string) => panels.find(panel => panel.name === name), [panels]);

const elements = useMemo(
() =>
Object.values(sizes).reduce<React.ReactNode[]>((acc, size, index) => {
const {component: Component, position} = getPanel(size.name)!;

if (position === 'left') {
return acc.concat([
<Spaces.LeftResizable
onResizeEnd={newSize => onStopResize(size, newSize)}
minimumSize={size.minSize}
maximumSize={size.maxSize}
size={size.size}
key={size.name}
handleRender={props => (
<Splitter {...props} name={size.name} isOpen={size.isOpen} onClick={() => toggle(size)} />
)}
order={index + 1}
>
<Component size={size} />
</Spaces.LeftResizable>,
]);
}

if (position === 'right') {
return acc.concat([
<Spaces.RightResizable
onResizeEnd={newSize => onStopResize(size, newSize)}
minimumSize={size.minSize}
maximumSize={size.maxSize}
size={size.size}
key={size.name}
handleRender={props => (
<Splitter {...props} name={size.name} isOpen={!size.isOpen} onClick={() => toggle(size)} />
)}
order={index + 1}
>
<Component size={size} />
</Spaces.RightResizable>,
]);
}

return acc.concat(
<Spaces.Fill>
<Component size={size} />
</Spaces.Fill>
);
}, []),
[getPanel, onStopResize, sizes, toggle]
);

const ResizablePanels: React.FC = ({children}) => {
return (
<>
<S.GlobalStyle />
<Spaces.Fixed height="100%" width="100vw">
{elements}
{children}
</Spaces.Fixed>
</>
);
Expand Down
29 changes: 29 additions & 0 deletions web/src/components/ResizablePanels/RightPanel.tsx
@@ -0,0 +1,29 @@
import * as Spaces from 'react-spaces';
import Splitter from '../ResizablePanels/Splitter';
import useResizablePanel, {TPanel, TSize} from '../ResizablePanels/hooks/useResizablePanel';

interface IProps {
panel: TPanel;
order?: number;
children(size: TSize): React.ReactNode;
}

const RightPanel = ({panel, order = 1, children}: IProps) => {
const {size, toggle, onStopResize} = useResizablePanel({panel});

return (
<Spaces.RightResizable
onResizeEnd={newSize => onStopResize(newSize)}
minimumSize={size.minSize}
maximumSize={size.maxSize}
size={size.size}
key={size.name}
order={order}
handleRender={props => <Splitter {...props} name={size.name} isOpen={!size.isOpen} onClick={() => toggle()} />}
>
{children(size)}
</Spaces.RightResizable>
);
};

export default RightPanel;
63 changes: 63 additions & 0 deletions web/src/components/ResizablePanels/hooks/useResizablePanel.ts
@@ -0,0 +1,63 @@
import {useCallback, useState} from 'react';

export type TPanel = {
name: string;
isDefaultOpen?: boolean;
minSize?: number;
maxSize?: number;
};

interface IProps {
panel: TPanel;
}

export type TSize = Exclude<TPanel, 'component'> & {
size: number;
isOpen: boolean;
minSize: number;
maxSize: number;
};

const useResizablePanel = ({panel}: IProps) => {
const [size, setSize] = useState<TSize>({
...panel,
size: (panel.isDefaultOpen && panel.maxSize) || panel.minSize || 0,
isOpen: panel.isDefaultOpen || false,
minSize: panel.minSize || 0,
maxSize: panel.maxSize || 0,
});

const toggle = useCallback(() => {
if (size.size <= size.minSize) {
const currentSize = size.maxSize;
setSize({
...size,
size: currentSize,
isOpen: currentSize > size.minSize,
});
return;
}
setSize({
...size,
size: size.minSize || 0,
isOpen: false,
});
}, [size]);

const onStopResize = useCallback(
newSize => {
const currentSize = Number(newSize);

setSize({
...size,
size: currentSize,
isOpen: currentSize > size.minSize,
});
},
[size]
);

return {toggle, onStopResize, size};
};

export default useResizablePanel;
76 changes: 0 additions & 76 deletions web/src/components/ResizablePanels/hooks/useResizablePanels.ts

This file was deleted.

6 changes: 6 additions & 0 deletions web/src/components/ResizablePanels/index.ts
@@ -1,2 +1,8 @@
import LeftPanel from './LeftPanel';
import RightPanel from './RightPanel';
import FillPanel from './FillPanel';
import {PanelContainer} from './ResizablePanels.styled';

// eslint-disable-next-line no-restricted-exports
export {default} from './ResizablePanels';
export {LeftPanel, RightPanel, FillPanel, PanelContainer};
13 changes: 7 additions & 6 deletions web/src/components/RunDetailTest/RunDetailTest.tsx
@@ -1,11 +1,10 @@
import PanelLayout from 'components/ResizablePanels';
import {useMemo} from 'react';
import TestRun from 'models/TestRun.model';
import TestRunEvent from 'models/TestRunEvent.model';
import * as S from './RunDetailTest.styled';
import {getTestPanel} from './TestPanel';
import SetupAlert from '../SetupAlert/SetupAlert';
import {getSpanDetailsPanel} from './SpanDetailPanel';
import ResizablePanels from '../ResizablePanels/ResizablePanels';
import SpanDetailsPanel from './SpanDetailsPanel';
import TestPanel from './TestPanel';

interface IProps {
run: TestRun;
Expand All @@ -14,11 +13,13 @@ interface IProps {
}

const RunDetailTest = ({run, runEvents, testId}: IProps) => {
const panels = useMemo(() => [getSpanDetailsPanel(), getTestPanel(testId, run, runEvents)], [run, runEvents, testId]);
return (
<S.Container>
<SetupAlert />
<PanelLayout panels={panels} />
<ResizablePanels>
<SpanDetailsPanel />
<TestPanel run={run} runEvents={runEvents} testId={testId} />
</ResizablePanels>
</S.Container>
);
};
Expand Down
24 changes: 0 additions & 24 deletions web/src/components/RunDetailTest/SpanDetailPanel.tsx

This file was deleted.

0 comments on commit c1fad40

Please sign in to comment.