mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
DataSourcePicker: Refactor and collapse the DataSourceDropdown components (#66820)
* clean up the components and convert to functional components * Create hooks for getting DS * remove focus style override from input --------- Co-authored-by: Ivan Ortega <ivanortegaalba@gmail.com>
This commit is contained in:
@@ -12,10 +12,10 @@ import { Button, CustomScrollbar, Icon, Input, ModalsController, Portal, useStyl
|
||||
import { DataSourceList } from './DataSourceList';
|
||||
import { DataSourceLogo, DataSourceLogoPlaceHolder } from './DataSourceLogo';
|
||||
import { DataSourceModal } from './DataSourceModal';
|
||||
import { PickerContentProps, DataSourceDrawerProps } from './types';
|
||||
import { dataSourceName as dataSourceLabel } from './utils';
|
||||
import { PickerContentProps, DataSourceDropdownProps } from './types';
|
||||
import { dataSourceLabel, useGetDatasource } from './utils';
|
||||
|
||||
export function DataSourceDropdown(props: DataSourceDrawerProps) {
|
||||
export function DataSourceDropdown(props: DataSourceDropdownProps) {
|
||||
const { current, onChange, ...restProps } = props;
|
||||
|
||||
const [isOpen, setOpen] = useState(false);
|
||||
@@ -23,6 +23,8 @@ export function DataSourceDropdown(props: DataSourceDrawerProps) {
|
||||
const [selectorElement, setSelectorElement] = useState<HTMLDivElement | null>();
|
||||
const [filterTerm, setFilterTerm] = useState<string>();
|
||||
|
||||
const currentDataSourceInstanceSettings = useGetDatasource(current);
|
||||
|
||||
const popper = usePopper(markerElement, selectorElement, {
|
||||
placement: 'bottom-start',
|
||||
});
|
||||
@@ -51,10 +53,15 @@ export function DataSourceDropdown(props: DataSourceDrawerProps) {
|
||||
{isOpen ? (
|
||||
<FocusScope contain autoFocus restoreFocus>
|
||||
<Input
|
||||
prefix={filterTerm ? <DataSourceLogoPlaceHolder /> : <DataSourceLogo dataSource={current} />}
|
||||
prefix={
|
||||
filterTerm ? (
|
||||
<DataSourceLogoPlaceHolder />
|
||||
) : (
|
||||
<DataSourceLogo dataSource={currentDataSourceInstanceSettings} />
|
||||
)
|
||||
}
|
||||
suffix={<Icon name={filterTerm ? 'search' : 'angle-down'} />}
|
||||
placeholder={dataSourceLabel(current)}
|
||||
className={styles.input}
|
||||
placeholder={dataSourceLabel(currentDataSourceInstanceSettings)}
|
||||
onChange={(e) => {
|
||||
setFilterTerm(e.currentTarget.value);
|
||||
}}
|
||||
@@ -73,7 +80,7 @@ export function DataSourceDropdown(props: DataSourceDrawerProps) {
|
||||
onClose={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
current={current}
|
||||
current={currentDataSourceInstanceSettings}
|
||||
style={popper.styles.popper}
|
||||
ref={setSelectorElement}
|
||||
{...restProps}
|
||||
@@ -90,10 +97,10 @@ export function DataSourceDropdown(props: DataSourceDrawerProps) {
|
||||
}}
|
||||
>
|
||||
<Input
|
||||
className={styles.markerInput}
|
||||
prefix={<DataSourceLogo dataSource={current} />}
|
||||
className={styles.input}
|
||||
prefix={<DataSourceLogo dataSource={currentDataSourceInstanceSettings} />}
|
||||
suffix={<Icon name="angle-down" />}
|
||||
value={dataSourceLabel(current)}
|
||||
value={dataSourceLabel(currentDataSourceInstanceSettings)}
|
||||
onFocus={() => {
|
||||
setOpen(true);
|
||||
}}
|
||||
@@ -113,11 +120,6 @@ function getStylesDropdown(theme: GrafanaTheme2) {
|
||||
cursor: pointer;
|
||||
`,
|
||||
input: css`
|
||||
input:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
`,
|
||||
markerInput: css`
|
||||
input {
|
||||
cursor: pointer;
|
||||
}
|
||||
@@ -149,7 +151,7 @@ const PickerContent = React.forwardRef<HTMLDivElement, PickerContentProps>((prop
|
||||
{...props}
|
||||
current={current}
|
||||
onChange={changeCallback}
|
||||
filter={(ds) => ds.name.includes(filterTerm ?? '')}
|
||||
filter={(ds) => ds.name.toLowerCase().includes(filterTerm?.toLowerCase() ?? '')}
|
||||
></DataSourceList>
|
||||
</CustomScrollbar>
|
||||
</div>
|
||||
@@ -169,8 +171,6 @@ const PickerContent = React.forwardRef<HTMLDivElement, PickerContentProps>((prop
|
||||
onClick={() => {
|
||||
onClose();
|
||||
showModal(DataSourceModal, {
|
||||
datasources: props.datasources,
|
||||
recentlyUsed: props.recentlyUsed,
|
||||
enableFileUpload: props.enableFileUpload,
|
||||
fileUploadOptions: props.fileUploadOptions,
|
||||
current,
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { DataSourceInstanceSettings, DataSourceRef } from '@grafana/data';
|
||||
import { getDataSourceSrv } from '@grafana/runtime';
|
||||
|
||||
import { DataSourceCard } from './DataSourceCard';
|
||||
import { isDataSourceMatch } from './utils';
|
||||
import { isDataSourceMatch, useGetDatasources } from './utils';
|
||||
|
||||
/**
|
||||
* Component props description for the {@link DataSourceList}
|
||||
@@ -14,7 +13,8 @@ import { isDataSourceMatch } from './utils';
|
||||
export interface DataSourceListProps {
|
||||
className?: string;
|
||||
onChange: (ds: DataSourceInstanceSettings) => void;
|
||||
current: DataSourceRef | string | null; // uid
|
||||
current: DataSourceRef | DataSourceInstanceSettings | string | null | undefined;
|
||||
/** Would be nicer if these parameters were part of a filtering object */
|
||||
tracing?: boolean;
|
||||
mixed?: boolean;
|
||||
dashboard?: boolean;
|
||||
@@ -32,88 +32,34 @@ export interface DataSourceListProps {
|
||||
onClear?: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component state description for the {@link DataSourceList}
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export interface DataSourceListState {
|
||||
error?: string;
|
||||
}
|
||||
export function DataSourceList(props: DataSourceListProps) {
|
||||
const { className, current, onChange } = props;
|
||||
// QUESTION: Should we use data from the Redux store as admin DS view does?
|
||||
const dataSources = useGetDatasources({
|
||||
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,
|
||||
});
|
||||
|
||||
/**
|
||||
* Component to be able to select a datasource from the list of installed and enabled
|
||||
* datasources in the current Grafana instance.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export class DataSourceList extends PureComponent<DataSourceListProps, DataSourceListState> {
|
||||
dataSourceSrv = getDataSourceSrv();
|
||||
|
||||
static defaultProps: Partial<DataSourceListProps> = {
|
||||
filter: () => true,
|
||||
};
|
||||
|
||||
state: DataSourceListState = {};
|
||||
|
||||
constructor(props: DataSourceListProps) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { current } = this.props;
|
||||
const dsSettings = this.dataSourceSrv.getInstanceSettings(current);
|
||||
if (!dsSettings) {
|
||||
this.setState({ error: 'Could not find data source ' + current });
|
||||
}
|
||||
}
|
||||
|
||||
onChange = (item: DataSourceInstanceSettings) => {
|
||||
const dsSettings = this.dataSourceSrv.getInstanceSettings(item);
|
||||
|
||||
if (dsSettings) {
|
||||
this.props.onChange(dsSettings);
|
||||
this.setState({ error: undefined });
|
||||
}
|
||||
};
|
||||
|
||||
getDataSourceOptions() {
|
||||
const { alerting, tracing, metrics, mixed, dashboard, variables, annotations, pluginId, type, filter, logs } =
|
||||
this.props;
|
||||
|
||||
const options = this.dataSourceSrv.getList({
|
||||
alerting,
|
||||
tracing,
|
||||
metrics,
|
||||
logs,
|
||||
dashboard,
|
||||
mixed,
|
||||
variables,
|
||||
annotations,
|
||||
pluginId,
|
||||
filter,
|
||||
type,
|
||||
});
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { className, current } = this.props;
|
||||
// QUESTION: Should we use data from the Redux store as admin DS view does?
|
||||
const options = this.getDataSourceOptions();
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{options.map((ds) => (
|
||||
return (
|
||||
<div className={className}>
|
||||
{dataSources
|
||||
.filter((ds) => (props.filter ? props.filter(ds) : true))
|
||||
.map((ds) => (
|
||||
<DataSourceCard
|
||||
key={ds.uid}
|
||||
ds={ds}
|
||||
onClick={this.onChange.bind(this, ds)}
|
||||
onClick={() => onChange(ds)}
|
||||
selected={!!isDataSourceMatch(ds, current)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2,11 +2,10 @@ import { css } from '@emotion/css';
|
||||
import React from 'react';
|
||||
|
||||
import { DataSourceInstanceSettings, DataSourceJsonData, GrafanaTheme2 } from '@grafana/data';
|
||||
import { DataSourceRef } from '@grafana/schema';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
|
||||
export interface DataSourceLogoProps {
|
||||
dataSource: DataSourceInstanceSettings<DataSourceJsonData> | string | DataSourceRef | null | undefined;
|
||||
dataSource: DataSourceInstanceSettings<DataSourceJsonData> | undefined;
|
||||
}
|
||||
|
||||
export function DataSourceLogo(props: DataSourceLogoProps) {
|
||||
@@ -14,24 +13,16 @@ export function DataSourceLogo(props: DataSourceLogoProps) {
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
if (!dataSource) {
|
||||
return null;
|
||||
return DataSourceLogoPlaceHolder();
|
||||
}
|
||||
|
||||
if (typeof dataSource === 'string') {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ('name' in dataSource) {
|
||||
return (
|
||||
<img
|
||||
className={styles.pickerDSLogo}
|
||||
alt={`${dataSource.meta.name} logo`}
|
||||
src={dataSource.meta.info.logos.small}
|
||||
></img>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
return (
|
||||
<img
|
||||
className={styles.pickerDSLogo}
|
||||
alt={`${dataSource.meta.name} logo`}
|
||||
src={dataSource.meta.info.logos.small}
|
||||
></img>
|
||||
);
|
||||
}
|
||||
|
||||
export function DataSourceLogoPlaceHolder() {
|
||||
|
||||
@@ -21,7 +21,6 @@ interface DataSourceModalProps {
|
||||
onChange: (ds: DataSourceInstanceSettings) => void;
|
||||
current: DataSourceRef | string | null | undefined;
|
||||
onDismiss: () => void;
|
||||
datasources: DataSourceInstanceSettings[];
|
||||
recentlyUsed?: string[];
|
||||
enableFileUpload?: boolean;
|
||||
fileUploadOptions?: DropzoneOptions;
|
||||
@@ -62,7 +61,7 @@ export function DataSourceModal({
|
||||
mixed={false}
|
||||
variables
|
||||
// FIXME: Filter out the grafana data source in a hacky way
|
||||
filter={(ds) => ds.name.includes(search) && ds.name !== '-- Grafana --'}
|
||||
filter={(ds) => ds.name.toLowerCase().includes(search.toLowerCase()) && ds.name !== '-- Grafana --'}
|
||||
onChange={onChange}
|
||||
current={current}
|
||||
/>
|
||||
|
||||
@@ -6,10 +6,10 @@ import {
|
||||
} from '@grafana/runtime';
|
||||
import { config } from 'app/core/config';
|
||||
|
||||
import { DataSourcePickerWithHistory } from './DataSourcePickerWithHistory';
|
||||
import { DataSourcePickerWithHistoryProps } from './types';
|
||||
import { DataSourceDropdown } from './DataSourceDropdown';
|
||||
import { DataSourceDropdownProps } from './types';
|
||||
|
||||
type DataSourcePickerProps = DeprecatedDataSourcePickerProps | DataSourcePickerWithHistoryProps;
|
||||
type DataSourcePickerProps = DeprecatedDataSourcePickerProps | DataSourceDropdownProps;
|
||||
|
||||
/**
|
||||
* DataSourcePicker is a wrapper around the old DataSourcePicker and the new one.
|
||||
@@ -20,6 +20,6 @@ export function DataSourcePicker(props: DataSourcePickerProps) {
|
||||
return !config.featureToggles.advancedDataSourcePicker ? (
|
||||
<DeprecatedDataSourcePicker {...props} />
|
||||
) : (
|
||||
<DataSourcePickerWithHistory {...props} />
|
||||
<DataSourceDropdown {...props} />
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
// Components
|
||||
|
||||
import { DataSourceInstanceSettings, DataSourceRef, getDataSourceUID } from '@grafana/data';
|
||||
import { getDataSourceSrv } from '@grafana/runtime';
|
||||
import { DataSourceJsonData } from '@grafana/schema';
|
||||
|
||||
import { DataSourceDropdown } from './DataSourceDropdown';
|
||||
import { DataSourcePickerProps } from './types';
|
||||
|
||||
/**
|
||||
* Component state description for the {@link DataSourcePicker}
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export interface DataSourcePickerState {
|
||||
error?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Component to be able to select a datasource from the list of installed and enabled
|
||||
* datasources in the current Grafana instance.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export class DataSourcePicker extends PureComponent<DataSourcePickerProps, DataSourcePickerState> {
|
||||
dataSourceSrv = getDataSourceSrv();
|
||||
|
||||
state: DataSourcePickerState = {};
|
||||
|
||||
componentDidMount() {
|
||||
const { current } = this.props;
|
||||
const dsSettings = this.dataSourceSrv.getInstanceSettings(current);
|
||||
if (!dsSettings) {
|
||||
this.setState({ error: 'Could not find data source ' + current });
|
||||
}
|
||||
}
|
||||
|
||||
onChange = (ds: DataSourceInstanceSettings<DataSourceJsonData>) => {
|
||||
this.props.onChange(ds);
|
||||
this.setState({ error: undefined });
|
||||
};
|
||||
|
||||
private getCurrentDs(): DataSourceInstanceSettings<DataSourceJsonData> | string | DataSourceRef | null | undefined {
|
||||
const { current, noDefault } = this.props;
|
||||
if (!current && noDefault) {
|
||||
return;
|
||||
}
|
||||
|
||||
const ds = this.dataSourceSrv.getInstanceSettings(current);
|
||||
if (ds) {
|
||||
return ds;
|
||||
}
|
||||
|
||||
return getDataSourceUID(current);
|
||||
}
|
||||
|
||||
getDatasources() {
|
||||
const { alerting, tracing, metrics, mixed, dashboard, variables, annotations, pluginId, type, filter, logs } =
|
||||
this.props;
|
||||
|
||||
return this.dataSourceSrv.getList({
|
||||
alerting,
|
||||
tracing,
|
||||
metrics,
|
||||
logs,
|
||||
dashboard,
|
||||
mixed,
|
||||
variables,
|
||||
annotations,
|
||||
pluginId,
|
||||
filter,
|
||||
type,
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const { recentlyUsed, fileUploadOptions, enableFileUpload, onClickAddCSV } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<DataSourceDropdown
|
||||
{...this.props}
|
||||
datasources={this.getDatasources()}
|
||||
onChange={this.onChange}
|
||||
recentlyUsed={recentlyUsed}
|
||||
current={this.getCurrentDs()}
|
||||
fileUploadOptions={fileUploadOptions}
|
||||
enableFileUpload={enableFileUpload}
|
||||
onClickAddCSV={onClickAddCSV}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import { updateHistory } from './DataSourcePickerWithHistory';
|
||||
|
||||
describe('DataSourcePickerWithHistory', () => {
|
||||
describe('updateHistory', () => {
|
||||
const early = { uid: 'b', lastUse: '2023-02-27T13:39:08.318Z' };
|
||||
const later = { uid: 'a', lastUse: '2023-02-28T13:39:08.318Z' };
|
||||
|
||||
it('should add an item to the history', () => {
|
||||
expect(updateHistory([], early)).toEqual([early]);
|
||||
});
|
||||
|
||||
it('should sort later entries first', () => {
|
||||
expect(updateHistory([early], later)).toEqual([later, early]);
|
||||
});
|
||||
|
||||
it('should update an already existing history item with the new lastUsed date', () => {
|
||||
const laterB = { uid: early.uid, lastUse: later.lastUse };
|
||||
expect(updateHistory([early], laterB)).toEqual([laterB]);
|
||||
});
|
||||
|
||||
it('should keep the three latest items in history', () => {
|
||||
const evenLater = { uid: 'c', lastUse: '2023-03-01T13:39:08.318Z' };
|
||||
const latest = { uid: 'd', lastUse: '2023-03-02T13:39:08.318Z' };
|
||||
expect(updateHistory([early, later, evenLater], latest)).toEqual([latest, evenLater, later]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,55 +0,0 @@
|
||||
import React from 'react';
|
||||
|
||||
import { dateTime } from '@grafana/data';
|
||||
import { LocalStorageValueProvider } from 'app/core/components/LocalStorageValueProvider';
|
||||
|
||||
import { DataSourcePicker } from './DataSourcePickerNG';
|
||||
import { DataSourcePickerHistoryItem, DataSourcePickerWithHistoryProps } from './types';
|
||||
|
||||
const DS_PICKER_STORAGE_KEY = 'DATASOURCE_PICKER';
|
||||
|
||||
export const DataSourcePickerWithHistory = (props: DataSourcePickerWithHistoryProps) => {
|
||||
return (
|
||||
<LocalStorageValueProvider<DataSourcePickerHistoryItem[]>
|
||||
defaultValue={[]}
|
||||
storageKey={props.localStorageKey ?? DS_PICKER_STORAGE_KEY}
|
||||
>
|
||||
{(rawValues, onSaveToStore) => {
|
||||
return (
|
||||
<DataSourcePicker
|
||||
{...props}
|
||||
recentlyUsed={rawValues.map((dsi) => dsi.uid)} //Filter recently to have a time cutoff
|
||||
onChange={(ds) => {
|
||||
onSaveToStore(updateHistory(rawValues, { uid: ds.uid, lastUse: dateTime(new Date()).toISOString() }));
|
||||
props.onChange(ds);
|
||||
}}
|
||||
></DataSourcePicker>
|
||||
);
|
||||
}}
|
||||
</LocalStorageValueProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export function updateHistory(values: DataSourcePickerHistoryItem[], newValue: DataSourcePickerHistoryItem) {
|
||||
const newHistory = values;
|
||||
const existingIndex = newHistory.findIndex((dpi) => dpi.uid === newValue.uid);
|
||||
if (existingIndex !== -1) {
|
||||
newHistory[existingIndex] = newValue;
|
||||
} else {
|
||||
newHistory.push(newValue);
|
||||
}
|
||||
|
||||
newHistory.sort((a, b) => {
|
||||
const al = dateTime(a.lastUse);
|
||||
const bl = dateTime(b.lastUse);
|
||||
if (al.isBefore(bl)) {
|
||||
return 1;
|
||||
} else if (bl.isBefore(al)) {
|
||||
return -1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
return newHistory.slice(0, 3);
|
||||
}
|
||||
@@ -4,8 +4,7 @@ import { DropzoneOptions } from 'react-dropzone';
|
||||
import { DataSourceInstanceSettings } from '@grafana/data';
|
||||
import { DataSourceJsonData, DataSourceRef } from '@grafana/schema';
|
||||
|
||||
export interface DataSourceDrawerProps {
|
||||
datasources: Array<DataSourceInstanceSettings<DataSourceJsonData>>;
|
||||
export interface DataSourceDropdownProps {
|
||||
onChange: (ds: DataSourceInstanceSettings<DataSourceJsonData>) => void;
|
||||
current: DataSourceInstanceSettings<DataSourceJsonData> | string | DataSourceRef | null | undefined;
|
||||
enableFileUpload?: boolean;
|
||||
@@ -14,44 +13,9 @@ export interface DataSourceDrawerProps {
|
||||
recentlyUsed?: string[];
|
||||
}
|
||||
|
||||
export interface PickerContentProps extends DataSourceDrawerProps {
|
||||
export interface PickerContentProps extends DataSourceDropdownProps {
|
||||
style: React.CSSProperties;
|
||||
filterTerm?: string;
|
||||
onClose: () => void;
|
||||
onDismiss: () => void;
|
||||
}
|
||||
|
||||
export interface DataSourcePickerProps {
|
||||
onChange: (ds: DataSourceInstanceSettings) => void;
|
||||
current: DataSourceRef | string | null; // uid
|
||||
tracing?: boolean;
|
||||
recentlyUsed?: string[];
|
||||
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;
|
||||
// Does not set the default data source if there is no value.
|
||||
noDefault?: boolean;
|
||||
inputId?: string;
|
||||
filter?: (dataSource: DataSourceInstanceSettings) => boolean;
|
||||
onClear?: () => void;
|
||||
disabled?: boolean;
|
||||
enableFileUpload?: boolean;
|
||||
fileUploadOptions?: DropzoneOptions;
|
||||
onClickAddCSV?: () => void;
|
||||
}
|
||||
|
||||
export interface DataSourcePickerWithHistoryProps extends Omit<DataSourcePickerProps, 'recentlyUsed'> {
|
||||
localStorageKey?: string;
|
||||
}
|
||||
|
||||
export interface DataSourcePickerHistoryItem {
|
||||
lastUse: string;
|
||||
uid: string;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { DataSourceInstanceSettings, DataSourceJsonData, DataSourceRef } from '@grafana/data';
|
||||
import { GetDataSourceListFilters, getDataSourceSrv } from '@grafana/runtime';
|
||||
|
||||
export function isDataSourceMatch(
|
||||
ds: DataSourceInstanceSettings | undefined,
|
||||
@@ -16,7 +17,7 @@ export function isDataSourceMatch(
|
||||
return ds.uid === current.uid;
|
||||
}
|
||||
|
||||
export function dataSourceName(
|
||||
export function dataSourceLabel(
|
||||
dataSource: DataSourceInstanceSettings<DataSourceJsonData> | string | DataSourceRef | null | undefined
|
||||
) {
|
||||
if (!dataSource) {
|
||||
@@ -37,3 +38,23 @@ export function dataSourceName(
|
||||
|
||||
return 'Unknown';
|
||||
}
|
||||
|
||||
export function useGetDatasources(filters: GetDataSourceListFilters) {
|
||||
const dataSourceSrv = getDataSourceSrv();
|
||||
|
||||
return dataSourceSrv.getList(filters);
|
||||
}
|
||||
|
||||
export function useGetDatasource(dataSource: string | DataSourceRef | DataSourceInstanceSettings | null | undefined) {
|
||||
const dataSourceSrv = getDataSourceSrv();
|
||||
|
||||
if (!dataSource) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (typeof dataSource === 'string') {
|
||||
return dataSourceSrv.getInstanceSettings(dataSource);
|
||||
}
|
||||
|
||||
return dataSourceSrv.getInstanceSettings(dataSource);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user