-
Notifications
You must be signed in to change notification settings - Fork 3.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(flows): draggable results panels (#18460)
* feat: WIP drag to resize results * refactor: WIP make dragging smoother * refactor: make resizing cells nice and smooth * refactor: move height/visibility update handlers into results component * refactor: use vanilla Math instead of lodash * refactor: consolidate visibility and resizing code in Resizer component * refactor: rename resizer components to be more generic * fix: use updated component name * refactor: use PipeData type instead of any * chore: misc cleanup
- Loading branch information
1 parent
7d4d08f
commit c6ad3cb
Showing
7 changed files
with
311 additions
and
133 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
// Libraries | ||
import React, {FC, useRef, useEffect, ReactNode, useState} from 'react' | ||
import classnames from 'classnames' | ||
|
||
// Components | ||
import ResizerHeader from 'src/notebooks/pipes/Query/ResizerHeader' | ||
|
||
// Types | ||
import {Visibility} from 'src/notebooks/pipes/Query' | ||
import {PipeData} from 'src/notebooks/index' | ||
|
||
interface Props { | ||
data: PipeData | ||
onUpdate: (data: any) => void | ||
children: ReactNode | ||
resizingEnabled: boolean | ||
} | ||
|
||
const MINIMUM_RESULTS_PANEL_HEIGHT = 100 | ||
|
||
const Resizer: FC<Props> = ({data, onUpdate, children, resizingEnabled}) => { | ||
const height = data.resultsPanelHeight | ||
const visibility = data.resultsVisibility | ||
|
||
const [size, updateSize] = useState<number>(height) | ||
const [isDragging, updateDragging] = useState<boolean>(false) | ||
const resultsBodyRef = useRef<HTMLDivElement>(null) | ||
const dragHandleRef = useRef<HTMLDivElement>(null) | ||
|
||
const resultsBodyClassName = classnames('notebook-raw-data--body', { | ||
[`notebook-raw-data--body__${visibility}`]: resizingEnabled && visibility, | ||
}) | ||
|
||
const updateResultsStyle = (): void => { | ||
if (resultsBodyRef.current && resizingEnabled && visibility === 'visible') { | ||
resultsBodyRef.current.setAttribute('style', `height: ${size}px`) | ||
} else { | ||
resultsBodyRef.current.setAttribute('style', '') | ||
} | ||
} | ||
|
||
const handleUpdateVisibility = (resultsVisibility: Visibility): void => { | ||
onUpdate({resultsVisibility}) | ||
} | ||
|
||
const handleUpdateHeight = (resultsPanelHeight: number): void => { | ||
onUpdate({resultsPanelHeight}) | ||
} | ||
|
||
// Ensure results renders with proper height on initial render | ||
useEffect(() => { | ||
updateResultsStyle() | ||
}, []) | ||
|
||
// Update results height when associated props change | ||
useEffect(() => { | ||
updateResultsStyle() | ||
}, [size, visibility, resizingEnabled]) | ||
|
||
// Update local height when context height changes | ||
// so long as it is a different value | ||
useEffect(() => { | ||
if (height !== size) { | ||
updateSize(height) | ||
} | ||
}, [height]) | ||
|
||
// Handle changes in drag state | ||
useEffect(() => { | ||
if (isDragging === true) { | ||
dragHandleRef.current && | ||
dragHandleRef.current.classList.add( | ||
'notebook-raw-data--drag-handle__dragging' | ||
) | ||
} | ||
|
||
if (isDragging === false) { | ||
dragHandleRef.current && | ||
dragHandleRef.current.classList.remove( | ||
'notebook-raw-data--drag-handle__dragging' | ||
) | ||
handleUpdateHeight(size) | ||
} | ||
}, [isDragging]) | ||
|
||
const handleMouseMove = (e: MouseEvent): void => { | ||
if (!resultsBodyRef.current) { | ||
return | ||
} | ||
|
||
const {pageY} = e | ||
const {top} = resultsBodyRef.current.getBoundingClientRect() | ||
|
||
const updatedHeight = Math.round( | ||
Math.max(pageY - top, MINIMUM_RESULTS_PANEL_HEIGHT) | ||
) | ||
|
||
updateSize(updatedHeight) | ||
} | ||
|
||
const handleMouseDown = (): void => { | ||
updateDragging(true) | ||
const body = document.getElementsByTagName('body')[0] | ||
body && body.classList.add('notebook-results--dragging') | ||
|
||
window.addEventListener('mousemove', handleMouseMove) | ||
window.addEventListener('mouseup', handleMouseUp) | ||
} | ||
|
||
const handleMouseUp = (): void => { | ||
updateDragging(false) | ||
const body = document.getElementsByTagName('body')[0] | ||
body && body.classList.remove('notebook-results--dragging') | ||
|
||
window.removeEventListener('mousemove', handleMouseMove) | ||
window.removeEventListener('mouseup', handleMouseUp) | ||
} | ||
|
||
let resultsBody = children | ||
|
||
if (!resizingEnabled) { | ||
resultsBody = ( | ||
<div className="notebook-raw-data--empty"> | ||
Run the Flow to see results | ||
</div> | ||
) | ||
} | ||
|
||
if (resizingEnabled && visibility === 'hidden') { | ||
resultsBody = <div className="notebook-raw-data--empty">Results hidden</div> | ||
} | ||
|
||
return ( | ||
<> | ||
<ResizerHeader | ||
resizingEnabled={resizingEnabled} | ||
visibility={visibility} | ||
onUpdateVisibility={handleUpdateVisibility} | ||
onStartDrag={handleMouseDown} | ||
dragHandleRef={dragHandleRef} | ||
/> | ||
<div className={resultsBodyClassName} ref={resultsBodyRef}> | ||
{resultsBody} | ||
</div> | ||
</> | ||
) | ||
} | ||
|
||
export default Resizer |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Libraries | ||
import React, {FC, RefObject} from 'react' | ||
import classnames from 'classnames' | ||
|
||
// Components | ||
import {Icon, IconFont} from '@influxdata/clockface' | ||
|
||
// Types | ||
import {Visibility} from 'src/notebooks/pipes/Query' | ||
|
||
interface Props { | ||
visibility: Visibility | ||
onUpdateVisibility: (visibility: Visibility) => void | ||
onStartDrag: () => void | ||
resizingEnabled: boolean | ||
dragHandleRef: RefObject<HTMLDivElement> | ||
} | ||
|
||
const ResizerHeader: FC<Props> = ({ | ||
visibility, | ||
onUpdateVisibility, | ||
onStartDrag, | ||
resizingEnabled, | ||
dragHandleRef, | ||
}) => { | ||
const glyph = visibility === 'visible' ? IconFont.EyeOpen : IconFont.EyeClosed | ||
const className = classnames('notebook-raw-data--header', { | ||
[`notebook-raw-data--header__${visibility}`]: resizingEnabled && visibility, | ||
}) | ||
|
||
if (!resizingEnabled) { | ||
return ( | ||
<div className={className}> | ||
<Icon glyph={IconFont.Zap} className="notebook-raw-data--vis-toggle" /> | ||
</div> | ||
) | ||
} | ||
|
||
const handleToggleVisibility = (): void => { | ||
if (visibility === 'visible') { | ||
onUpdateVisibility('hidden') | ||
} else { | ||
onUpdateVisibility('visible') | ||
} | ||
} | ||
|
||
return ( | ||
<div className={className}> | ||
<div onClick={handleToggleVisibility}> | ||
<Icon className="notebook-raw-data--vis-toggle" glyph={glyph} /> | ||
</div> | ||
<div | ||
className="notebook-raw-data--drag-handle" | ||
onMouseDown={onStartDrag} | ||
ref={dragHandleRef} | ||
title="Drag to resize results table" | ||
> | ||
<div className="notebook-raw-data--drag-icon" /> | ||
<div className="notebook-raw-data--drag-icon" /> | ||
<div className="notebook-raw-data--drag-icon" /> | ||
</div> | ||
</div> | ||
) | ||
} | ||
|
||
export default ResizerHeader |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.