import React, { useState } from 'react'; import { PopValueActionMeta, RemoveValueActionMeta } from 'react-select'; import { DataSourceInstanceSettings, getDataSourceUID, isUnsignedPluginSignature, SelectableValue, } from '@grafana/data'; import { selectors } from '@grafana/e2e-selectors'; import { getDataSourceSrv, DataSourcePickerState, DataSourcePickerProps } from '@grafana/runtime'; import { ExpressionDatasourceRef } from '@grafana/runtime/src/utils/DataSourceWithBackend'; import { ActionMeta, HorizontalGroup, PluginSignatureBadge, MultiSelect } from '@grafana/ui'; import { isDataSourceManagingAlerts } from '../../utils/datasource'; export interface MultipleDataSourcePickerProps extends Omit { onChange: (ds: DataSourceInstanceSettings, action: 'add' | 'remove') => void; current: string[] | undefined; } export const MultipleDataSourcePicker = (props: MultipleDataSourcePickerProps) => { const dataSourceSrv = getDataSourceSrv(); const [state, setState] = useState(); const onChange = (items: Array>, actionMeta: ActionMeta) => { if (actionMeta.action === 'clear' && props.onClear) { props.onClear(); return; } const selectedItem = items[items.length - 1]; let dataSourceName, action: 'add' | 'remove'; if (actionMeta.action === 'pop-value' || actionMeta.action === 'remove-value') { const castedActionMeta: | RemoveValueActionMeta> | PopValueActionMeta> = actionMeta; dataSourceName = castedActionMeta.removedValue?.value; action = 'remove'; } else { dataSourceName = selectedItem.value; action = 'add'; } const dsSettings = dataSourceSrv.getInstanceSettings(dataSourceName); if (dsSettings) { props.onChange(dsSettings, action); setState({ error: undefined }); } }; const getCurrentValue = (): Array> | undefined => { const { current, hideTextValue, noDefault } = props; if (!current && noDefault) { return; } return current?.map((dataSourceName: string) => { const ds = dataSourceSrv.getInstanceSettings(dataSourceName); if (ds) { return { label: ds.name.slice(0, 37), value: ds.name, imgUrl: ds.meta.info.logos.small, hideText: hideTextValue, meta: ds.meta, }; } const uid = getDataSourceUID(dataSourceName); if (uid === ExpressionDatasourceRef.uid || uid === ExpressionDatasourceRef.name) { return { label: uid, value: uid, hideText: hideTextValue }; } return { label: (uid ?? 'no name') + ' - not found', value: uid ?? undefined, imgUrl: '', hideText: hideTextValue, }; }); }; const getDataSourceOptions = () => { const { alerting, tracing, metrics, mixed, dashboard, variables, annotations, pluginId, type, filter, logs } = props; const dataSources = dataSourceSrv.getList({ alerting, tracing, metrics, logs, dashboard, mixed, variables, annotations, pluginId, filter, type, }); const alertManagingDs = dataSources.filter(isDataSourceManagingAlerts).map((ds) => ({ value: ds.name, label: `${ds.name}${ds.isDefault ? ' (default)' : ''}`, imgUrl: ds.meta.info.logos.small, meta: ds.meta, })); const nonAlertManagingDs = dataSources .filter((ds) => !isDataSourceManagingAlerts(ds)) .map((ds) => ({ value: ds.name, label: `${ds.name}${ds.isDefault ? ' (default)' : ''}`, imgUrl: ds.meta.info.logos.small, meta: ds.meta, })); const groupedOptions = [ { label: 'Data sources with configured alert rules', options: alertManagingDs, expanded: true }, { label: 'Other data sources', options: nonAlertManagingDs, expanded: true }, ]; return groupedOptions; }; const { autoFocus, onBlur, onClear, openMenuOnFocus, placeholder, width, inputId, disabled = false, isLoading = false, } = props; const options = getDataSourceOptions(); const value = getCurrentValue(); const isClearable = typeof onClear === 'function'; return (
{ if (o.meta && isUnsignedPluginSignature(o.meta.signature) && o !== value) { return ( {o.label} ); } return o.label || ''; }} />
); };