mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Provisioning: Allows specifying uid for datasource and use that in derived fields (#23585)
* Add uid to datasource * Fix uid passing when provisioning * Better error handling and Uid column type change * Fix test and strict null error counts * Add backend tests * Add tests * Fix strict null checks * Update test * Improve tests * Update pkg/services/sqlstore/datasource.go Co-Authored-By: Arve Knudsen <arve.knudsen@gmail.com> * Variable rename Co-authored-by: Arve Knudsen <arve.knudsen@gmail.com>
This commit is contained in:
@@ -39,7 +39,7 @@ export const ConfigEditor = (props: Props) => {
|
||||
<div className="gf-form-inline">
|
||||
<div className="gf-form">
|
||||
<MaxLinesField
|
||||
value={options.jsonData.maxLines}
|
||||
value={options.jsonData.maxLines || ''}
|
||||
onChange={value => onOptionsChange(setMaxLines(options, value))}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import { DerivedField } from './DerivedField';
|
||||
import DataSourcePicker from '../../../../core/components/Select/DataSourcePicker';
|
||||
|
||||
jest.mock('app/core/config', () => ({
|
||||
config: {
|
||||
featureToggles: {
|
||||
tracingIntegration: true,
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('app/features/plugins/datasource_srv', () => ({
|
||||
getDatasourceSrv() {
|
||||
return {
|
||||
getExternal(): any[] {
|
||||
return [];
|
||||
},
|
||||
};
|
||||
},
|
||||
}));
|
||||
|
||||
describe('DerivedField', () => {
|
||||
it('shows internal link if uid is set', () => {
|
||||
const value = {
|
||||
matcherRegex: '',
|
||||
name: '',
|
||||
datasourceUid: 'test',
|
||||
};
|
||||
const wrapper = shallow(<DerivedField value={value} onChange={() => {}} onDelete={() => {}} suggestions={[]} />);
|
||||
|
||||
expect(
|
||||
wrapper
|
||||
.find('DataSourceSection')
|
||||
.dive()
|
||||
.find(DataSourcePicker).length
|
||||
).toBe(1);
|
||||
});
|
||||
|
||||
it('shows url link if uid is not set', () => {
|
||||
const value = {
|
||||
matcherRegex: '',
|
||||
name: '',
|
||||
url: 'test',
|
||||
};
|
||||
const wrapper = shallow(<DerivedField value={value} onChange={() => {}} onDelete={() => {}} suggestions={[]} />);
|
||||
expect(wrapper.find('DataSourceSection').length).toBe(0);
|
||||
});
|
||||
});
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { css } from 'emotion';
|
||||
import { Button, FormField, DataLinkInput, stylesFactory, LegacyForms } from '@grafana/ui';
|
||||
const { Switch } = LegacyForms;
|
||||
@@ -9,6 +9,7 @@ import { DerivedFieldConfig } from '../types';
|
||||
import DataSourcePicker from 'app/core/components/Select/DataSourcePicker';
|
||||
import { getDatasourceSrv } from 'app/features/plugins/datasource_srv';
|
||||
import { config } from 'app/core/config';
|
||||
import { usePrevious } from 'react-use';
|
||||
|
||||
const getStyles = stylesFactory(() => ({
|
||||
row: css`
|
||||
@@ -33,7 +34,18 @@ type Props = {
|
||||
export const DerivedField = (props: Props) => {
|
||||
const { value, onChange, onDelete, suggestions, className } = props;
|
||||
const styles = getStyles();
|
||||
const [hasIntenalLink, setHasInternalLink] = useState(!!value.datasourceName);
|
||||
const [showInternalLink, setShowInternalLink] = useState(!!value.datasourceUid);
|
||||
const previousUid = usePrevious(value.datasourceUid);
|
||||
|
||||
// Force internal link visibility change if uid changed outside of this component.
|
||||
useEffect(() => {
|
||||
if (!previousUid && value.datasourceUid && !showInternalLink) {
|
||||
setShowInternalLink(true);
|
||||
}
|
||||
if (previousUid && !value.datasourceUid && showInternalLink) {
|
||||
setShowInternalLink(false);
|
||||
}
|
||||
}, [previousUid, value.datasourceUid, showInternalLink]);
|
||||
|
||||
const handleChange = (field: keyof typeof value) => (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
onChange({
|
||||
@@ -81,11 +93,11 @@ export const DerivedField = (props: Props) => {
|
||||
</div>
|
||||
|
||||
<FormField
|
||||
label="URL"
|
||||
label={showInternalLink ? 'Query' : 'URL'}
|
||||
labelWidth={5}
|
||||
inputEl={
|
||||
<DataLinkInput
|
||||
placeholder={'http://example.com/${__value.raw}'}
|
||||
placeholder={showInternalLink ? '${__value.raw}' : 'http://example.com/${__value.raw}'}
|
||||
value={value.url || ''}
|
||||
onChange={newValue =>
|
||||
onChange({
|
||||
@@ -105,27 +117,27 @@ export const DerivedField = (props: Props) => {
|
||||
<div className={styles.row}>
|
||||
<Switch
|
||||
label="Internal link"
|
||||
checked={hasIntenalLink}
|
||||
checked={showInternalLink}
|
||||
onChange={() => {
|
||||
if (hasIntenalLink) {
|
||||
if (showInternalLink) {
|
||||
onChange({
|
||||
...value,
|
||||
datasourceName: undefined,
|
||||
datasourceUid: undefined,
|
||||
});
|
||||
}
|
||||
setHasInternalLink(!hasIntenalLink);
|
||||
setShowInternalLink(!showInternalLink);
|
||||
}}
|
||||
/>
|
||||
|
||||
{hasIntenalLink && (
|
||||
{showInternalLink && (
|
||||
<DataSourceSection
|
||||
onChange={datasourceName => {
|
||||
onChange={datasourceUid => {
|
||||
onChange({
|
||||
...value,
|
||||
datasourceName,
|
||||
datasourceUid,
|
||||
});
|
||||
}}
|
||||
datasourceName={value.datasourceName}
|
||||
datasourceUid={value.datasourceUid}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
@@ -135,29 +147,30 @@ export const DerivedField = (props: Props) => {
|
||||
};
|
||||
|
||||
type DataSourceSectionProps = {
|
||||
datasourceName?: string;
|
||||
onChange: (name: string) => void;
|
||||
datasourceUid?: string;
|
||||
onChange: (uid: string) => void;
|
||||
};
|
||||
|
||||
const DataSourceSection = (props: DataSourceSectionProps) => {
|
||||
const { datasourceName, onChange } = props;
|
||||
const { datasourceUid, onChange } = props;
|
||||
const datasources: DataSourceSelectItem[] = getDatasourceSrv()
|
||||
.getExternal()
|
||||
.map(
|
||||
(ds: any) =>
|
||||
ds =>
|
||||
({
|
||||
value: ds.name,
|
||||
value: ds.uid,
|
||||
name: ds.name,
|
||||
meta: ds.meta,
|
||||
} as DataSourceSelectItem)
|
||||
);
|
||||
const selectedDatasource = datasourceName && datasources.find(d => d.name === datasourceName);
|
||||
|
||||
let selectedDatasource = datasourceUid && datasources.find(d => d.value === datasourceUid);
|
||||
return (
|
||||
<DataSourcePicker
|
||||
onChange={newValue => {
|
||||
onChange(newValue.name);
|
||||
}}
|
||||
// Uid and value should be always set in the db and so in the items.
|
||||
onChange={ds => onChange(ds.value!)}
|
||||
datasources={datasources}
|
||||
current={selectedDatasource}
|
||||
current={selectedDatasource || undefined}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user