2023-04-29 00:19:31 +08:00
import { css , cx } from '@emotion/css' ;
import React , { useRef } from 'react' ;
import { Observable } from 'rxjs' ;
2023-04-19 21:08:09 +08:00
2023-04-29 00:19:31 +08:00
import { DataSourceInstanceSettings , DataSourceRef , GrafanaTheme2 } from '@grafana/data' ;
2023-04-21 23:07:11 +08:00
import { getTemplateSrv } from '@grafana/runtime' ;
2023-04-29 00:19:31 +08:00
import { useTheme2 } from '@grafana/ui' ;
2023-04-21 23:07:11 +08:00
2023-04-29 00:19:31 +08:00
import { useDatasources , useKeyboardNavigatableList , useRecentlyUsedDataSources } from '../../hooks' ;
2023-04-19 21:08:09 +08:00
import { DataSourceCard } from './DataSourceCard' ;
2023-04-21 23:07:11 +08:00
import { getDataSourceCompareFn , isDataSourceMatch } from './utils' ;
2023-04-19 21:08:09 +08:00
/ * *
* Component props description for the { @link DataSourceList }
*
* @internal
* /
export interface DataSourceListProps {
className? : string ;
onChange : ( ds : DataSourceInstanceSettings ) = > void ;
2023-04-20 18:11:13 +08:00
current : DataSourceRef | DataSourceInstanceSettings | string | null | undefined ;
/** Would be nicer if these parameters were part of a filtering object */
2023-04-19 21:08:09 +08:00
tracing? : boolean ;
mixed? : boolean ;
dashboard? : boolean ;
metrics? : boolean ;
type ? : string | string [ ] ;
annotations? : boolean ;
variables? : boolean ;
alerting? : boolean ;
pluginId? : string ;
/** If true,we show only DSs with logs; and if true, pluginId shouldnt be passed in */
logs? : boolean ;
width? : number ;
2023-04-29 00:19:31 +08:00
keyboardEvents? : Observable < React.KeyboardEvent > ;
2023-04-19 21:08:09 +08:00
inputId? : string ;
filter ? : ( dataSource : DataSourceInstanceSettings ) = > boolean ;
onClear ? : ( ) = > void ;
2023-04-29 00:19:31 +08:00
enableKeyboardNavigation? : boolean ;
2023-04-19 21:08:09 +08:00
}
2023-04-20 18:11:13 +08:00
export function DataSourceList ( props : DataSourceListProps ) {
2023-04-29 00:19:31 +08:00
const containerRef = useRef < HTMLDivElement > ( null ) ;
const [ navigatableProps , selectedItemCssSelector ] = useKeyboardNavigatableList ( {
keyboardEvents : props.keyboardEvents ,
containerRef : containerRef ,
} ) ;
const theme = useTheme2 ( ) ;
const styles = getStyles ( theme , selectedItemCssSelector ) ;
const { className , current , onChange , enableKeyboardNavigation } = props ;
2023-04-20 18:11:13 +08:00
// QUESTION: Should we use data from the Redux store as admin DS view does?
2023-04-21 23:07:11 +08:00
const dataSources = useDatasources ( {
2023-04-20 18:11:13 +08:00
alerting : props.alerting ,
annotations : props.annotations ,
dashboard : props.dashboard ,
logs : props.logs ,
metrics : props.metrics ,
mixed : props.mixed ,
pluginId : props.pluginId ,
tracing : props.tracing ,
type : props . type ,
variables : props.variables ,
} ) ;
2023-04-21 23:07:11 +08:00
const [ recentlyUsedDataSources , pushRecentlyUsedDataSource ] = useRecentlyUsedDataSources ( ) ;
2023-04-20 18:11:13 +08:00
return (
2023-04-29 00:19:31 +08:00
< div ref = { containerRef } className = { cx ( className , styles . container ) } >
2023-04-20 18:11:13 +08:00
{ dataSources
. filter ( ( ds ) = > ( props . filter ? props . filter ( ds ) : true ) )
2023-04-21 23:07:11 +08:00
. sort ( getDataSourceCompareFn ( current , recentlyUsedDataSources , getDataSourceVariableIDs ( ) ) )
2023-04-20 18:11:13 +08:00
. map ( ( ds ) = > (
2023-04-19 21:08:09 +08:00
< DataSourceCard
key = { ds . uid }
ds = { ds }
2023-04-21 23:07:11 +08:00
onClick = { ( ) = > {
pushRecentlyUsedDataSource ( ds ) ;
onChange ( ds ) ;
} }
2023-04-19 21:08:09 +08:00
selected = { ! ! isDataSourceMatch ( ds , current ) }
2023-04-29 00:19:31 +08:00
{ . . . ( enableKeyboardNavigation ? navigatableProps : { } ) }
2023-04-19 21:08:09 +08:00
/ >
) ) }
2023-04-20 18:11:13 +08:00
< / div >
) ;
2023-04-19 21:08:09 +08:00
}
2023-04-21 23:07:11 +08:00
function getDataSourceVariableIDs() {
const templateSrv = getTemplateSrv ( ) ;
/** Unforunately there is no easy way to identify data sources that are variables. The uid of the data source will be the name of the variable in a templating syntax $([name]) **/
return templateSrv
. getVariables ( )
. filter ( ( v ) = > v . type === 'datasource' )
. map ( ( v ) = > ` \ ${ $ { v . id } } ` ) ;
}
2023-04-29 00:19:31 +08:00
function getStyles ( theme : GrafanaTheme2 , selectedItemCssSelector : string ) {
return {
container : css `
$ { selectedItemCssSelector } {
background - color : $ { theme . colors . background . secondary } ;
}
` ,
} ;
}