import React , { FC , useEffect , useState } from 'react' ; import { i18n } from '@kbn/i18n' ; import { FormattedMessage } from '@kbn/i18n-react' ; import { EuiButtonEmpty , EuiFlexGroup , EuiFlexItem , EuiSpacer } from '@elastic/eui' ; import { Cytoscape , Controls , JobMapLegend } from './components' ; import { useMlKibana , useMlLocator } from '../../../contexts/kibana' ; import { JOB_MAP_NODE_TYPES } from '../../../../../common/constants/data_frame_analytics' ; import { ML_PAGES } from '../../../../../common/constants/locator' ; import { useCurrentEuiTheme , EuiThemeType } from '../../../components/color_range_legend' ; import { useRefDimensions } from './components/use_ref_dimensions' ; import { useFetchAnalyticsMapData } from './use_fetch_analytics_map_data' ; import { JobMapTitle } from './job_map_title' ; const getCytoscapeDivStyle = ( theme ) => ( { background : `linear-gradient(
  90deg,
  ${ theme . euiPageBackgroundColor }
    calc(${ theme . euiSizeL } - calc(${ theme . euiSizeXS } / 2)),
  transparent 1%
)
center,
linear-gradient(
  ${ theme . euiPageBackgroundColor }
    calc(${ theme . euiSizeL } - calc(${ theme . euiSizeXS } / 2)),
  transparent 1%
)
center,
${ theme . euiColorLightShade }` , backgroundSize : `${ theme . euiSizeL } ${ theme . euiSizeL }` , margin : `-${ theme . gutterTypes . gutterLarge }` , marginTop : 0 , } ) ; interface Props { analyticsId ? : string ; modelId ? : string ; } export const JobMap = ( { analyticsId , modelId } ) => { const [ itemsDeleted , setItemsDeleted ] = useState < boolean > ( false ) ; const [ resetCyToggle , setResetCyToggle ] = useState < boolean > ( false ) ; const { elements , error , fetchAndSetElementsWrapper , isLoading , message , nodeDetails , setElements , setError , } = useFetchAnalyticsMapData ( ) ; const { services : { notifications , application : { navigateToUrl } , } , } = useMlKibana ( ) ; const locator = useMlLocator ( ) ! ; const { euiTheme } = useCurrentEuiTheme ( ) ; const redirectToAnalyticsManagementPage = async ( ) => { const url = await locator . getUrl ( { page : ML_PAGES . DATA_FRAME_ANALYTICS_JOBS_MANAGE } ) ; await navigateToUrl ( url ) ; } ; const updateElements = ( nodeId , nodeLabel , destIndexNode ? ) => { if ( nodeLabel === analyticsId ) { redirectToAnalyticsManagementPage ( ) ; } else { const filteredElements = elements . filter ( ( e ) => { let isNotDeletedNodeOrRelated = e . data . id !== nodeId && e . data . target !== nodeId && e . data . source !== nodeId ; if ( e . data . id !== undefined && e . data . type === JOB_MAP_NODE_TYPES . TRAINED_MODEL ) { isNotDeletedNodeOrRelated = isNotDeletedNodeOrRelated && nodeDetails [ e . data . id ] ?. metadata ?. analytics_config ?. id !== nodeLabel ; } if ( destIndexNode !== undefined ) { return ( isNotDeletedNodeOrRelated && e . data . id !== destIndexNode && e . data . target !== destIndexNode && e . data . source !== destIndexNode ) ; } return isNotDeletedNodeOrRelated ; } ) ; setItemsDeleted ( true ) ; setElements ( filteredElements ) ; } } ; useEffect ( ( ) => { fetchAndSetElementsWrapper ( { analyticsId , modelId } ) ; } , [ analyticsId , modelId ] ) ; useEffect ( ( ) => { if ( message !== undefined ) { notifications . toasts . add ( message ) ; } } , [ message ] ) ; if ( error !== undefined ) { notifications . toasts . addDanger ( i18n . translate ( 'xpack.ml.dataframe.analyticsMap.fetchDataErrorMessage' , { defaultMessage : 'Unable to fetch some data. An error occurred: {error}' , values : { error : JSON . stringify ( error ) } , } ) ) ; setError ( undefined ) ; } const { ref , width , height } = useRefDimensions ( ) ; const refreshCallback = ( ) => fetchAndSetElementsWrapper ( { analyticsId , modelId } ) ; return ( < div data - test - subj = "mlPageDataFrameAnalyticsMap" > < EuiSpacer size = "m" / > < EuiFlexGroup direction = "column" gutterSize = "none" justifyContent = "spaceBetween" > < EuiFlexItem grow = { false } > < EuiFlexGroup justifyContent = "spaceBetween" alignItems = "center" > < EuiFlexItem grow = { false } > < JobMapTitle analyticsId = { analyticsId } modelId = { modelId } / > < /EuiFlexItem> < EuiFlexItem grow = { false } > < JobMapLegend theme = { euiTheme } /> < /EuiFlexItem> < /EuiFlexGroup> < /EuiFlexItem> < EuiFlexItem grow = { false } > < EuiFlexGroup gutterSize = "xs" component = "span" > < EuiFlexItem grow = { false } > < EuiButtonEmpty size = "xs" data - test - subj = { `mlAnalyticsRefreshMapButton${ isLoading ? ' loading' : ' loaded' }` } onClick = { refreshCallback } isLoading = { isLoading } > < FormattedMessage id = "xpack.ml.dataframe.analyticsList.refreshMapButtonLabel" defaultMessage = "Refresh" / > < /EuiButtonEmpty> < /EuiFlexItem> < EuiFlexItem grow = { false } > < EuiButtonEmpty size = "xs" data - test - subj = "mlAnalyticsResetGraphButton" onClick = { ( ) => setResetCyToggle ( ! resetCyToggle ) } > < FormattedMessage id = "xpack.ml.dataframe.analyticsList.resetMapButtonLabel" defaultMessage = "Reset" / > < /EuiButtonEmpty> < /EuiFlexItem> < /EuiFlexGroup> < /EuiFlexItem> < /EuiFlexGroup> < div style = { { height : height - parseInt ( euiTheme . gutterTypes . gutterLarge , 10 ) - 20 } } ref = { ref } > < Cytoscape theme = { euiTheme } height = { height - 20 } elements = { elements } width = { width } style = { getCytoscapeDivStyle ( euiTheme ) } itemsDeleted = { itemsDeleted } resetCy = { resetCyToggle } > < Controls details = { nodeDetails } getNodeData = { fetchAndSetElementsWrapper } modelId = { modelId } updateElements = { updateElements } refreshJobsCallback = { refreshCallback } / > < /Cytoscape> < /div> < /div>); } ;