2021-07-13 09:36:51 +02:00
import { css , cx } from '@emotion/css' ;
2022-04-22 14:33:13 +01:00
import React , { useCallback , useState } from 'react' ;
2020-08-31 08:47:27 +02:00
import { Draggable } from 'react-beautiful-dnd' ;
2022-04-22 14:33:13 +01:00
import { useUpdateEffect } from 'react-use' ;
import { GrafanaTheme } from '@grafana/data' ;
2022-02-16 05:16:25 -08:00
import { reportInteraction } from '@grafana/runtime' ;
2022-04-22 14:33:13 +01:00
import { Icon , ReactUtils , stylesFactory , useTheme } from '@grafana/ui' ;
2020-04-09 21:23:22 +02:00
interface QueryOperationRowProps {
2020-08-31 08:47:27 +02:00
index : number ;
id : string ;
2021-01-07 15:33:15 +01:00
title? : string ;
headerElement? : QueryOperationRowRenderProp ;
actions? : QueryOperationRowRenderProp ;
2020-04-09 21:23:22 +02:00
onOpen ? : ( ) = > void ;
onClose ? : ( ) = > void ;
children : React.ReactNode ;
isOpen? : boolean ;
2020-08-31 08:47:27 +02:00
draggable? : boolean ;
2021-07-13 09:36:51 +02:00
disabled? : boolean ;
2020-04-09 21:23:22 +02:00
}
2021-01-07 15:33:15 +01:00
export type QueryOperationRowRenderProp = ( ( props : QueryOperationRowRenderProps ) = > React . ReactNode ) | React . ReactNode ;
export interface QueryOperationRowRenderProps {
isOpen : boolean ;
onOpen : ( ) = > void ;
onClose : ( ) = > void ;
}
2020-04-09 21:23:22 +02:00
export const QueryOperationRow : React.FC < QueryOperationRowProps > = ( {
children ,
actions ,
title ,
2020-04-26 21:59:14 +02:00
headerElement ,
2020-04-09 21:23:22 +02:00
onClose ,
onOpen ,
isOpen ,
2021-07-13 09:36:51 +02:00
disabled ,
2020-08-31 08:47:27 +02:00
draggable ,
index ,
id ,
2020-04-09 21:23:22 +02:00
} : QueryOperationRowProps ) = > {
const [ isContentVisible , setIsContentVisible ] = useState ( isOpen !== undefined ? isOpen : true ) ;
const theme = useTheme ( ) ;
const styles = getQueryOperationRowStyles ( theme ) ;
2020-08-31 08:47:27 +02:00
const onRowToggle = useCallback ( ( ) = > {
setIsContentVisible ( ! isContentVisible ) ;
} , [ isContentVisible , setIsContentVisible ] ) ;
Chore: Fix all Typescript strict null errors (#26204)
* Chore: Fix typescript strict null errors
* Added new limit
* Fixed ts issue
* fixed tests
* trying to fix type inference
* Fixing more ts errors
* Revert tsconfig option
* Fix
* Fixed code
* More fixes
* fix tests
* Updated snapshot
* Chore: More ts strict null fixes
* More fixes in some really messed up azure config components
* More fixes, current count: 441
* 419
* More fixes
* Fixed invalid initial state in explore
* Fixing tests
* Fixed tests
* Explore fix
* More fixes
* Progress
* Sub 300
* Now at 218
* Progress
* Update
* Progress
* Updated tests
* at 159
* fixed tests
* Progress
* YAy blow 100! at 94
* 10,9,8,7,6,5,4,3,2,1... lift off
* Fixed tests
* Fixed more type errors
Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
2020-07-10 12:46:59 +02:00
2022-02-16 05:16:25 -08:00
const reportDragMousePosition = useCallback ( ( e ) = > {
// When drag detected react-beautiful-dnd will preventDefault the event
// Ref: https://github.com/atlassian/react-beautiful-dnd/blob/master/docs/guides/how-we-use-dom-events.md#a-mouse-drag-has-started-and-the-user-is-now-dragging
if ( e . defaultPrevented ) {
const rect = e . currentTarget . getBoundingClientRect ( ) ;
var x = e . clientX - rect . left ;
var y = e . clientY - rect . top ;
// report relative mouse position within the header element
reportInteraction ( 'query_row_reorder_drag_position' , {
x : x / rect . width ,
y : y / rect . height ,
width : rect.width ,
height : rect.height ,
} ) ;
}
} , [ ] ) ;
2020-04-09 21:23:22 +02:00
useUpdateEffect ( ( ) = > {
if ( isContentVisible ) {
if ( onOpen ) {
onOpen ( ) ;
}
} else {
if ( onClose ) {
onClose ( ) ;
}
}
} , [ isContentVisible ] ) ;
2021-01-07 15:33:15 +01:00
const renderPropArgs : QueryOperationRowRenderProps = {
isOpen : isContentVisible ,
onOpen : ( ) = > {
setIsContentVisible ( true ) ;
} ,
onClose : ( ) = > {
setIsContentVisible ( false ) ;
} ,
} ;
2021-11-23 15:41:51 +01:00
const titleElement = title && ReactUtils . renderOrCallToRender ( title , renderPropArgs ) ;
const actionsElement = actions && ReactUtils . renderOrCallToRender ( actions , renderPropArgs ) ;
const headerElementRendered = headerElement && ReactUtils . renderOrCallToRender ( headerElement , renderPropArgs ) ;
2020-04-09 21:23:22 +02:00
2020-08-31 08:47:27 +02:00
const rowHeader = (
< div className = { styles . header } >
2021-10-07 09:13:07 +01:00
< div className = { styles . column } >
< Icon
name = { isContentVisible ? 'angle-down' : 'angle-right' }
className = { styles . collapseIcon }
onClick = { onRowToggle }
/ >
{ title && (
< div className = { styles . titleWrapper } onClick = { onRowToggle } aria-label = "Query operation row title" >
< div className = { cx ( styles . title , disabled && styles . disabled ) } > { titleElement } < / div >
< / div >
) }
{ headerElementRendered }
< / div >
< div className = { styles . column } >
{ actionsElement }
{ draggable && (
< Icon title = "Drag and drop to reorder" name = "draggabledots" size = "lg" className = { styles . dragIcon } / >
) }
< / div >
2020-08-31 08:47:27 +02:00
< / div >
) ;
2020-09-14 08:54:42 +02:00
if ( draggable ) {
return (
< Draggable draggableId = { id } index = { index } >
2021-01-20 07:59:48 +01:00
{ ( provided ) = > {
2021-10-13 06:09:35 +02:00
const dragHandleProps = { . . . provided . dragHandleProps , role : 'group' } ; // replace the role="button" because it causes https://dequeuniversity.com/rules/axe/4.3/nested-interactive?application=msftAI
2020-09-14 08:54:42 +02:00
return (
< >
< div ref = { provided . innerRef } className = { styles . wrapper } { ...provided.draggableProps } >
2022-02-16 05:16:25 -08:00
< div { ...dragHandleProps } onMouseMove = { reportDragMousePosition } >
{ rowHeader }
< / div >
2020-09-14 08:54:42 +02:00
{ isContentVisible && < div className = { styles . content } > { children } < / div > }
< / div >
< / >
) ;
} }
< / Draggable >
) ;
}
return (
2020-04-09 21:23:22 +02:00
< div className = { styles . wrapper } >
2020-08-31 08:47:27 +02:00
{ rowHeader }
2020-04-09 21:23:22 +02:00
{ isContentVisible && < div className = { styles . content } > { children } < / div > }
< / div >
) ;
} ;
const getQueryOperationRowStyles = stylesFactory ( ( theme : GrafanaTheme ) = > {
return {
wrapper : css `
2020-04-26 21:59:14 +02:00
margin - bottom : $ { theme . spacing . md } ;
2020-04-09 21:23:22 +02:00
` ,
header : css `
2021-10-07 09:13:07 +01:00
label : Header ;
2020-06-29 13:31:39 +02:00
padding : $ { theme . spacing . xs } $ { theme . spacing . sm } ;
2020-04-09 21:23:22 +02:00
border - radius : $ { theme . border . radius . sm } ;
2020-04-13 09:58:40 +02:00
background : $ { theme . colors . bg2 } ;
2020-06-29 13:31:39 +02:00
min - height : $ { theme . spacing . formInputHeight } px ;
2021-10-07 09:13:07 +01:00
display : grid ;
grid - template - columns : minmax ( 100 px , max - content ) min - content ;
2020-04-13 09:58:40 +02:00
align - items : center ;
justify - content : space - between ;
2021-03-15 10:15:14 +00:00
white - space : nowrap ;
2021-04-16 15:22:31 +02:00
& : focus {
outline : none ;
}
2020-04-09 21:23:22 +02:00
` ,
2021-10-07 09:13:07 +01:00
column : css `
label : Column ;
display : flex ;
align - items : center ;
` ,
2020-08-31 08:47:27 +02:00
dragIcon : css `
2021-10-04 09:05:43 +03:00
cursor : grab ;
2020-09-14 08:54:42 +02:00
color : $ { theme . colors . textWeak } ;
& : hover {
color : $ { theme . colors . text } ;
}
2020-08-31 08:47:27 +02:00
` ,
2020-04-09 21:23:22 +02:00
collapseIcon : css `
color : $ { theme . colors . textWeak } ;
2021-01-07 15:33:15 +01:00
cursor : pointer ;
2020-04-26 21:59:14 +02:00
& : hover {
color : $ { theme . colors . text } ;
}
2020-04-09 21:23:22 +02:00
` ,
titleWrapper : css `
display : flex ;
align - items : center ;
2020-09-14 08:54:42 +02:00
flex - grow : 1 ;
2020-04-09 21:23:22 +02:00
cursor : pointer ;
2020-09-14 08:54:42 +02:00
overflow : hidden ;
margin - right : $ { theme . spacing . sm } ;
2020-04-09 21:23:22 +02:00
` ,
title : css `
font - weight : $ { theme . typography . weight . semibold } ;
2020-04-13 09:58:40 +02:00
color : $ { theme . colors . textBlue } ;
2020-04-09 21:23:22 +02:00
margin - left : $ { theme . spacing . sm } ;
2020-09-21 15:33:50 +02:00
overflow : hidden ;
2021-10-07 09:13:07 +01:00
text - overflow : ellipsis ;
2020-04-09 21:23:22 +02:00
` ,
content : css `
2022-01-25 09:19:39 +01:00
margin - top : $ { theme . spacing . inlineFormMargin } ;
margin - left : $ { theme . spacing . lg } ;
2020-04-09 21:23:22 +02:00
` ,
2021-07-13 09:36:51 +02:00
disabled : css `
color : $ { theme . colors . textWeak } ;
` ,
2020-04-09 21:23:22 +02:00
} ;
} ) ;
QueryOperationRow . displayName = 'QueryOperationRow' ;