Skip to content

Commit f01679e

Browse files
committed
Clean up and document
1 parent 7864620 commit f01679e

File tree

3 files changed

+53
-15
lines changed

3 files changed

+53
-15
lines changed

src/ConfigEditor.tsx

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,43 @@
11
import React, { ChangeEvent } from 'react';
2-
import { LegacyForms, DataSourceHttpSettings } from '@grafana/ui';
32

3+
import { LegacyForms, DataSourceHttpSettings } from '@grafana/ui';
44
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
55
import { JsonApiDataSourceOptions } from './types';
6+
67
import {} from '@emotion/core';
78

89
const { Input, FormField } = LegacyForms;
910

1011
interface Props extends DataSourcePluginOptionsEditorProps<JsonApiDataSourceOptions> {}
1112

13+
/**
14+
* ConfigEditor lets the user configure connection details like the URL or
15+
* authentication.
16+
*/
1217
export const ConfigEditor: React.FC<Props> = ({ options, onOptionsChange }) => {
1318
const onParamsChange = (e: ChangeEvent<HTMLInputElement>) => {
14-
onOptionsChange({ ...options, jsonData: { ...options.jsonData, queryParams: e.currentTarget.value } });
19+
onOptionsChange({
20+
...options,
21+
jsonData: {
22+
...options.jsonData,
23+
queryParams: e.currentTarget.value,
24+
},
25+
});
1526
};
1627

1728
return (
1829
<>
30+
{/* DataSourceHttpSettings handles most the settings for connecting over
31+
HTTP. */}
1932
<DataSourceHttpSettings
2033
defaultUrl="http://localhost:8080"
2134
dataSourceConfig={options}
2235
onChange={onOptionsChange}
2336
/>
37+
38+
{/* The Grafana proxy strips query parameters from the URL set in
39+
DataSourceHttpSettings. To support custom query parameters, the user need
40+
to set them explicitly. */}
2441
<h3 className="page-heading">Misc</h3>
2542
<div className="gf-form-group">
2643
<div className="gf-form-inline">

src/DataSource.ts

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,25 @@ export class DataSource extends DataSourceApi<JsonApiQuery, JsonApiDataSourceOpt
3131
.filter(field => field.jsonPath)
3232
.map(field => {
3333
const values = JSONPath({ path: field.jsonPath, json: response });
34+
const [type, newvals] = detectFieldType(values);
3435

3536
// Get the path for automatic setting of the field name.
3637
//
3738
// Casted to any due to typing issues with JSONPath-Plus
3839
const paths = (JSONPath as any).toPathArray(field.jsonPath);
39-
40-
const [type, newvals] = detectFieldType(values);
40+
const propertyName = paths[paths.length - 1];
4141

4242
return {
43-
name: field.name || paths[paths.length - 1],
43+
name: field.name || propertyName,
4444
type: type,
4545
values: newvals,
4646
};
4747
});
4848

49-
if (Array.from(new Set(fields.map(field => field.values.length))).length > 1) {
49+
const fieldLengths = fields.map(field => field.values.length);
50+
51+
// All fields need to have the same length for the data frame to be valid.
52+
if (Array.from(new Set(fieldLengths)).length > 1) {
5053
throw new Error('Fields have different lengths');
5154
}
5255

@@ -56,6 +59,7 @@ export class DataSource extends DataSourceApi<JsonApiQuery, JsonApiDataSourceOpt
5659
});
5760
});
5861

62+
// Wait for all queries to finish before returning the result.
5963
return Promise.all(promises).then(data => ({ data }));
6064
}
6165

@@ -68,9 +72,13 @@ export class DataSource extends DataSourceApi<JsonApiQuery, JsonApiDataSourceOpt
6872
if (!query.jsonPath) {
6973
return [];
7074
}
71-
return JSONPath({ path: query.jsonPath, json: await this.api.get() }).map((_: any) => ({
72-
text: _,
73-
}));
75+
76+
const response = await this.api.get();
77+
78+
return JSONPath({
79+
path: query.jsonPath,
80+
json: response,
81+
}).map((_: any) => ({ text: _ }));
7482
}
7583

7684
/**
@@ -81,6 +89,7 @@ export class DataSource extends DataSourceApi<JsonApiQuery, JsonApiDataSourceOpt
8189

8290
try {
8391
const response = await this.api.test();
92+
8493
if (response.status === 200) {
8594
return {
8695
status: 'success',
@@ -118,8 +127,10 @@ export class DataSource extends DataSourceApi<JsonApiQuery, JsonApiDataSourceOpt
118127
* Detects the type of the values, and converts values if necessary.
119128
*
120129
* @param values - The field values.
130+
* @returns the detected field type and potentially converted values.
121131
*/
122132
const detectFieldType = (values: any[]): [FieldType, any[]] => {
133+
// If all values are valid ISO 8601, the assume that it's a time field.
123134
const isValidISO = values.every(value => isValid(parseISO(value)));
124135
if (isValidISO) {
125136
return [FieldType.time, values.map(_ => parseISO(_).valueOf())];
@@ -128,13 +139,20 @@ const detectFieldType = (values: any[]): [FieldType, any[]] => {
128139
const isNumber = values.every(value => typeof value === 'number');
129140
if (isNumber) {
130141
const uniqueLengths = Array.from(new Set(values.map(value => value.toString().length)));
131-
132-
if (uniqueLengths.length === 1 && uniqueLengths[0] === 13) {
133-
return [FieldType.time, values];
134-
}
135-
if (uniqueLengths.length === 1 && uniqueLengths[0] === 10) {
136-
return [FieldType.time, values.map(_ => _ * 1000.0)];
142+
const hasSameLength = uniqueLengths.length === 1;
143+
144+
// If all the values have the same length of either 10 (seconds) or 13
145+
// (milliseconds), assume it's a time field. This is not always true, so we
146+
// might need to add an option to disable detection of time fields.
147+
if (hasSameLength) {
148+
if (uniqueLengths[0] === 13) {
149+
return [FieldType.time, values];
150+
}
151+
if (uniqueLengths[0] === 10) {
152+
return [FieldType.time, values.map(_ => _ * 1000.0)];
153+
}
137154
}
155+
138156
return [FieldType.number, values];
139157
}
140158

src/JsonPathQueryField.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ interface Props {
88
onChange: (v: string) => void;
99
}
1010

11+
/**
12+
* JsonPathQueryField is an editor for JSON Path.
13+
*/
1114
export const JsonPathQueryField: React.FC<Props> = ({ query, onBlur, onChange }) => {
1215
return (
1316
<div style={{ marginRight: '4px', width: '100%' }}>

0 commit comments

Comments
 (0)