mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
InfluxDB: Use database input for SQL configuration instead of metadata (#79579)
* introduce constants file * update frontend to use database field * use dbName field instead of metadata * use secureGrpc * betterer
This commit is contained in:
parent
d89a8a3a82
commit
2edcf0edbd
@ -7400,10 +7400,6 @@ exports[`no gf-form usage`] = {
|
|||||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
|
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
|
||||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"]
|
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"]
|
||||||
],
|
],
|
||||||
"public/app/plugins/datasource/influxdb/components/editor/config/InfluxSQLConfig.tsx:5381": [
|
|
||||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"],
|
|
||||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"]
|
|
||||||
],
|
|
||||||
"public/app/plugins/datasource/influxdb/components/editor/query/QueryEditor.tsx:5381": [
|
"public/app/plugins/datasource/influxdb/components/editor/query/QueryEditor.tsx:5381": [
|
||||||
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"]
|
[0, 0, 0, "gf-form usage has been deprecated. Use a component from @grafana/ui or custom CSS instead.", "5381"]
|
||||||
],
|
],
|
||||||
|
@ -98,17 +98,9 @@ func runnerFromDataSource(dsInfo *models.DatasourceInfo) (*runner, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
md := metadata.MD{}
|
md := metadata.MD{}
|
||||||
for _, m := range dsInfo.Metadata {
|
if dsInfo.DbName != "" {
|
||||||
for k, v := range m {
|
md.Set("database", dsInfo.DbName)
|
||||||
if _, ok := md[k]; ok {
|
|
||||||
return nil, fmt.Errorf("metadata: duplicate key: %s", k)
|
|
||||||
}
|
|
||||||
if k != "" {
|
|
||||||
md.Set(k, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if dsInfo.Token != "" {
|
if dsInfo.Token != "" {
|
||||||
md.Set("Authorization", fmt.Sprintf("Bearer %s", dsInfo.Token))
|
md.Set("Authorization", fmt.Sprintf("Bearer %s", dsInfo.Token))
|
||||||
}
|
}
|
||||||
|
@ -63,11 +63,6 @@ func (suite *FSQLTestSuite) TestIntegration_QueryData() {
|
|||||||
DbName: "influxdb",
|
DbName: "influxdb",
|
||||||
Version: "test",
|
Version: "test",
|
||||||
HTTPMode: "proxy",
|
HTTPMode: "proxy",
|
||||||
Metadata: []map[string]string{
|
|
||||||
{
|
|
||||||
"bucket": "bucket",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
SecureGrpc: false,
|
SecureGrpc: false,
|
||||||
},
|
},
|
||||||
backend.QueryDataRequest{
|
backend.QueryDataRequest{
|
@ -81,7 +81,6 @@ func newInstanceSettings(httpClientProvider httpclient.Provider) datasource.Inst
|
|||||||
TimeInterval: jsonData.TimeInterval,
|
TimeInterval: jsonData.TimeInterval,
|
||||||
DefaultBucket: jsonData.DefaultBucket,
|
DefaultBucket: jsonData.DefaultBucket,
|
||||||
Organization: jsonData.Organization,
|
Organization: jsonData.Organization,
|
||||||
Metadata: jsonData.Metadata,
|
|
||||||
MaxSeries: maxSeries,
|
MaxSeries: maxSeries,
|
||||||
SecureGrpc: true,
|
SecureGrpc: true,
|
||||||
Token: settings.DecryptedSecureJSONData["token"],
|
Token: settings.DecryptedSecureJSONData["token"],
|
||||||
|
@ -18,8 +18,6 @@ type DatasourceInfo struct {
|
|||||||
Organization string `json:"organization"`
|
Organization string `json:"organization"`
|
||||||
MaxSeries int `json:"maxSeries"`
|
MaxSeries int `json:"maxSeries"`
|
||||||
|
|
||||||
// Flight SQL metadata
|
|
||||||
Metadata []map[string]string `json:"metadata"`
|
|
||||||
// FlightSQL grpc connection
|
// FlightSQL grpc connection
|
||||||
SecureGrpc bool `json:"secureGrpc"`
|
SecureGrpc bool `json:"secureGrpc"`
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ import { InlineField, InlineFieldRow, Input, SecretInput } from '@grafana/ui';
|
|||||||
|
|
||||||
import { InfluxOptions, InfluxSecureJsonData } from '../../../types';
|
import { InfluxOptions, InfluxSecureJsonData } from '../../../types';
|
||||||
|
|
||||||
const WIDTH_SHORT = 20;
|
import { WIDTH_SHORT } from './constants';
|
||||||
|
|
||||||
export type Props = DataSourcePluginOptionsEditorProps<InfluxOptions, InfluxSecureJsonData>;
|
export type Props = DataSourcePluginOptionsEditorProps<InfluxOptions, InfluxSecureJsonData>;
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ import React from 'react';
|
|||||||
|
|
||||||
import {
|
import {
|
||||||
DataSourcePluginOptionsEditorProps,
|
DataSourcePluginOptionsEditorProps,
|
||||||
|
GrafanaTheme2,
|
||||||
onUpdateDatasourceJsonDataOption,
|
onUpdateDatasourceJsonDataOption,
|
||||||
onUpdateDatasourceJsonDataOptionSelect,
|
onUpdateDatasourceJsonDataOptionSelect,
|
||||||
onUpdateDatasourceOption,
|
onUpdateDatasourceOption,
|
||||||
@ -11,18 +12,17 @@ import {
|
|||||||
SelectableValue,
|
SelectableValue,
|
||||||
updateDatasourcePluginResetOption,
|
updateDatasourcePluginResetOption,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { GrafanaTheme2 } from '@grafana/data/src/themes';
|
|
||||||
import { Alert, Field, InlineLabel, Input, SecretInput, Select, useStyles2 } from '@grafana/ui';
|
import { Alert, Field, InlineLabel, Input, SecretInput, Select, useStyles2 } from '@grafana/ui';
|
||||||
|
|
||||||
import { InfluxOptions, InfluxSecureJsonData } from '../../../types';
|
import { InfluxOptions, InfluxSecureJsonData } from '../../../types';
|
||||||
|
|
||||||
|
import { WIDTH_SHORT } from './constants';
|
||||||
|
|
||||||
const httpModes: SelectableValue[] = [
|
const httpModes: SelectableValue[] = [
|
||||||
{ label: 'GET', value: 'GET' },
|
{ label: 'GET', value: 'GET' },
|
||||||
{ label: 'POST', value: 'POST' },
|
{ label: 'POST', value: 'POST' },
|
||||||
];
|
];
|
||||||
|
|
||||||
const WIDTH_SHORT = 20;
|
|
||||||
|
|
||||||
export type Props = DataSourcePluginOptionsEditorProps<InfluxOptions, InfluxSecureJsonData>;
|
export type Props = DataSourcePluginOptionsEditorProps<InfluxOptions, InfluxSecureJsonData>;
|
||||||
|
|
||||||
export const InfluxInfluxQLConfig = (props: Props) => {
|
export const InfluxInfluxQLConfig = (props: Props) => {
|
||||||
|
@ -1,138 +1,69 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import { css } from '@emotion/css';
|
||||||
|
import { uniqueId } from 'lodash';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DataSourcePluginOptionsEditorProps,
|
DataSourcePluginOptionsEditorProps,
|
||||||
|
GrafanaTheme2,
|
||||||
onUpdateDatasourceSecureJsonDataOption,
|
onUpdateDatasourceSecureJsonDataOption,
|
||||||
updateDatasourcePluginResetOption,
|
updateDatasourcePluginResetOption,
|
||||||
} from '@grafana/data';
|
} from '@grafana/data';
|
||||||
import { InlineField, SecretInput, Input, InlineFieldRow, InlineLabel } from '@grafana/ui';
|
import { Field, InlineLabel, Input, SecretInput, useStyles2 } from '@grafana/ui';
|
||||||
|
|
||||||
import { InfluxOptions, InfluxSecureJsonData } from '../../../types';
|
import { InfluxOptions, InfluxSecureJsonData } from '../../../types';
|
||||||
|
|
||||||
|
import { WIDTH_SHORT } from './constants';
|
||||||
|
|
||||||
export type Props = DataSourcePluginOptionsEditorProps<InfluxOptions, InfluxSecureJsonData>;
|
export type Props = DataSourcePluginOptionsEditorProps<InfluxOptions, InfluxSecureJsonData>;
|
||||||
|
|
||||||
type MetadataState = Array<{ key: string; value: string }>;
|
|
||||||
|
|
||||||
export const addMetaData = (setMetaData: (val: MetadataState) => void, metaDataArr: MetadataState) => {
|
|
||||||
setMetaData([...metaDataArr, { key: '', value: '' }]);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const removeMetaData = (i: number, setMetaData: (val: MetadataState) => void, metaDataArr: MetadataState) => {
|
|
||||||
const newMetaValues = [...metaDataArr];
|
|
||||||
newMetaValues.splice(i, 1);
|
|
||||||
setMetaData(newMetaValues);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const onKeyChange = (
|
|
||||||
key: string,
|
|
||||||
metaDataArr: MetadataState,
|
|
||||||
index: number,
|
|
||||||
setMetaData: (val: MetadataState) => void
|
|
||||||
) => {
|
|
||||||
const newMetaValues = [...metaDataArr];
|
|
||||||
newMetaValues[index]['key'] = key;
|
|
||||||
setMetaData(newMetaValues);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const onValueChange = (
|
|
||||||
value: string,
|
|
||||||
metaDataArr: MetadataState,
|
|
||||||
index: number,
|
|
||||||
setMetaData: (val: MetadataState) => void
|
|
||||||
) => {
|
|
||||||
const newMetaValues = [...metaDataArr];
|
|
||||||
newMetaValues[index]['value'] = value;
|
|
||||||
setMetaData(newMetaValues);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const InfluxSqlConfig = (props: Props) => {
|
export const InfluxSqlConfig = (props: Props) => {
|
||||||
const {
|
const { options, onOptionsChange } = props;
|
||||||
options: { jsonData, secureJsonData, secureJsonFields },
|
const { jsonData, secureJsonData, secureJsonFields } = options;
|
||||||
} = props;
|
const styles = useStyles2(getStyles);
|
||||||
|
const htmlPrefix = uniqueId('influxdb-sql-config');
|
||||||
const existingMetadata: MetadataState = jsonData?.metadata?.length
|
|
||||||
? jsonData?.metadata?.map((md) => ({ key: Object.keys(md)[0], value: Object.values(md)[0] }))
|
|
||||||
: [{ key: '', value: '' }];
|
|
||||||
const [metaDataArr, setMetaData] = useState<MetadataState>(existingMetadata);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const { onOptionsChange, options } = props;
|
|
||||||
const mapData = metaDataArr?.map((m) => ({ [m.key]: m.value }));
|
|
||||||
const jsonData = {
|
|
||||||
...options.jsonData,
|
|
||||||
metadata: mapData,
|
|
||||||
};
|
|
||||||
onOptionsChange({
|
|
||||||
...options,
|
|
||||||
jsonData,
|
|
||||||
});
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, [metaDataArr]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="gf-form">
|
<Field
|
||||||
<h6>Token</h6>
|
horizontal
|
||||||
</div>
|
label={<InlineLabel width={WIDTH_SHORT}>Database</InlineLabel>}
|
||||||
<div>
|
className={styles.horizontalField}
|
||||||
<InlineField labelWidth={20} label="Token">
|
htmlFor={`${htmlPrefix}-dbName`}
|
||||||
<SecretInput
|
>
|
||||||
width={40}
|
<Input
|
||||||
name="token"
|
id={`${htmlPrefix}-dbName`}
|
||||||
type="text"
|
className="width-20"
|
||||||
value={secureJsonData?.token || ''}
|
aria-label="Database or bucket name"
|
||||||
onReset={() => updateDatasourcePluginResetOption(props, 'token')}
|
value={jsonData.dbName}
|
||||||
onChange={onUpdateDatasourceSecureJsonDataOption(props, 'token')}
|
onChange={(event) => {
|
||||||
isConfigured={secureJsonFields?.token}
|
onOptionsChange({
|
||||||
/>
|
...options,
|
||||||
</InlineField>
|
jsonData: {
|
||||||
</div>
|
...jsonData,
|
||||||
<div>
|
dbName: event.currentTarget.value,
|
||||||
<div className="gf-form">
|
},
|
||||||
<h6>MetaData</h6>
|
});
|
||||||
</div>
|
}}
|
||||||
{metaDataArr?.map((_, i) => (
|
/>
|
||||||
<InlineFieldRow key={i} style={{ flexFlow: 'row' }}>
|
</Field>
|
||||||
<InlineField labelWidth={20} label="Key">
|
<Field horizontal label={<InlineLabel width={WIDTH_SHORT}>Token</InlineLabel>} className={styles.horizontalField}>
|
||||||
<Input
|
<SecretInput
|
||||||
key={i}
|
label="Token"
|
||||||
width={40}
|
aria-label="Token"
|
||||||
name="key"
|
className="width-20"
|
||||||
type="text"
|
value={secureJsonData?.token || ''}
|
||||||
value={metaDataArr[i]?.key || ''}
|
onReset={() => updateDatasourcePluginResetOption(props, 'token')}
|
||||||
placeholder="key"
|
onChange={onUpdateDatasourceSecureJsonDataOption(props, 'token')}
|
||||||
onChange={(e) => onKeyChange(e.currentTarget.value.trim(), metaDataArr, i, setMetaData)}
|
isConfigured={Boolean(secureJsonFields && secureJsonFields.token)}
|
||||||
></Input>
|
/>
|
||||||
</InlineField>
|
</Field>
|
||||||
<InlineField labelWidth={20} label="Value">
|
|
||||||
<Input
|
|
||||||
key={i}
|
|
||||||
width={40}
|
|
||||||
name="value"
|
|
||||||
type="text"
|
|
||||||
value={metaDataArr[i]?.value?.toString() ?? ''}
|
|
||||||
placeholder="value"
|
|
||||||
onChange={(e) => onValueChange(e.currentTarget.value.trim(), metaDataArr, i, setMetaData)}
|
|
||||||
></Input>
|
|
||||||
</InlineField>
|
|
||||||
{i + 1 >= metaDataArr.length && (
|
|
||||||
<InlineLabel as="button" className="" onClick={() => addMetaData(setMetaData, metaDataArr)} width="auto">
|
|
||||||
+
|
|
||||||
</InlineLabel>
|
|
||||||
)}
|
|
||||||
{i > 0 && (
|
|
||||||
<InlineLabel
|
|
||||||
as="button"
|
|
||||||
className=""
|
|
||||||
width="auto"
|
|
||||||
onClick={() => removeMetaData(i, setMetaData, metaDataArr)}
|
|
||||||
>
|
|
||||||
-
|
|
||||||
</InlineLabel>
|
|
||||||
)}
|
|
||||||
</InlineFieldRow>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getStyles = (theme: GrafanaTheme2) => ({
|
||||||
|
horizontalField: css({
|
||||||
|
justifyContent: 'initial',
|
||||||
|
margin: `0 ${theme.spacing(0.5)} ${theme.spacing(0.5)} 0`,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
export const WIDTH_SHORT = 20;
|
Loading…
Reference in New Issue
Block a user