Skip to content

Commit 60d5d58

Browse files
committed
Extract FieldEditor
1 parent c926cd6 commit 60d5d58

File tree

2 files changed

+108
-95
lines changed

2 files changed

+108
-95
lines changed

src/components/FieldEditor.tsx

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import React from 'react';
2+
3+
import { SelectableValue, FieldType } from '@grafana/data';
4+
import { Icon, InlineFieldRow, InlineField, Select } from '@grafana/ui';
5+
6+
import { JsonPathQueryField } from './JsonPathQueryField';
7+
8+
interface Props {
9+
limit?: number;
10+
onChange: (value: any) => void;
11+
onComplete: () => Promise<any>;
12+
value: any[];
13+
}
14+
15+
export const FieldEditor = ({ value, onChange, limit, onComplete }: Props) => {
16+
const onChangePath = (i: number) => (e: string) => {
17+
onChange(value.map((field, n) => (i === n ? { ...value[i], jsonPath: e } : field)));
18+
};
19+
20+
const onChangeType = (i: number) => (e: SelectableValue<string>) => {
21+
onChange(
22+
value.map((field, n) =>
23+
i === n ? { ...value[i], type: (e.value === 'auto' ? undefined : e.value) as FieldType } : field
24+
)
25+
);
26+
};
27+
28+
const addField = (i: number) => () => {
29+
if (!limit || value.length < limit) {
30+
onChange({
31+
fields: [...value.slice(0, i + 1), { name: '', jsonPath: '' }, ...value.slice(i + 1)],
32+
});
33+
}
34+
};
35+
36+
const removeField = (i: number) => () => {
37+
onChange({
38+
fields: [...value.slice(0, i), ...value.slice(i + 1)],
39+
});
40+
};
41+
42+
return (
43+
<>
44+
{value.map((field, index) => (
45+
<InlineFieldRow key={index}>
46+
<InlineField
47+
label="Field"
48+
tooltip={
49+
<div>
50+
A <a href="https://goessner.net/articles/JsonPath/">JSON Path</a> query that selects one or more values
51+
from a JSON object.
52+
</div>
53+
}
54+
grow
55+
>
56+
<JsonPathQueryField
57+
onBlur={() => {
58+
onChange(value);
59+
}}
60+
onChange={onChangePath(index)}
61+
query={field.jsonPath}
62+
onData={onComplete}
63+
/>
64+
</InlineField>
65+
<InlineField label="Type" tooltip="If Auto is set, the JSON property type is used to detect the field type.">
66+
<Select
67+
value={field.type ?? 'auto'}
68+
width={12}
69+
onChange={onChangeType(index)}
70+
options={[
71+
{ label: 'Auto', value: 'auto' },
72+
{ label: 'String', value: 'string' },
73+
{ label: 'Number', value: 'number' },
74+
{ label: 'Time', value: 'time' },
75+
{ label: 'Boolean', value: 'boolean' },
76+
]}
77+
/>
78+
</InlineField>
79+
80+
{(!limit || value.length < limit) && (
81+
<a className="gf-form-label" onClick={addField(index)}>
82+
<Icon name="plus" />
83+
</a>
84+
)}
85+
86+
{value.length > 1 ? (
87+
<a className="gf-form-label" onClick={removeField(index)}>
88+
<Icon name="minus" />
89+
</a>
90+
) : null}
91+
</InlineFieldRow>
92+
))}
93+
</>
94+
);
95+
};

src/components/QueryEditor.tsx

Lines changed: 13 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import defaults from 'lodash/defaults';
22
import React, { useState } from 'react';
33
import {
4-
Icon,
54
InlineFieldRow,
65
InlineField,
76
Segment,
@@ -12,14 +11,14 @@ import {
1211
useTheme,
1312
InfoBox,
1413
} from '@grafana/ui';
15-
import { SelectableValue, FieldType, QueryEditorProps } from '@grafana/data';
14+
import { QueryEditorProps } from '@grafana/data';
1615
import { JsonApiQuery, JsonApiDataSourceOptions, defaultQuery } from '../types';
17-
import { JsonPathQueryField } from './JsonPathQueryField';
1816
import { KeyValueEditor } from './KeyValueEditor';
1917
import AutoSizer from 'react-virtualized-auto-sizer';
2018
import { css } from 'emotion';
2119
import { Pair } from '../types';
2220
import { JsonDataSource } from 'datasource';
21+
import { FieldEditor } from './FieldEditor';
2322

2423
// Display a warning message when user adds any of the following headers.
2524
const sensitiveHeaders = ['authorization', 'proxy-authorization', 'x-api-key'];
@@ -55,101 +54,20 @@ export const QueryEditor: React.FC<Props> = ({ onRunQuery, onChange, limitFields
5554
onRunQuery();
5655
};
5756

58-
const onChangePath = (i: number) => (e: string) => {
59-
const { fields } = query;
60-
onChange({
61-
...query,
62-
fields: fields.map((field, n) => (i === n ? { ...fields[i], jsonPath: e } : field)),
63-
});
64-
onRunQuery();
65-
};
66-
67-
const onChangeType = (i: number) => (e: SelectableValue<string>) => {
68-
const { fields } = query;
69-
onChange({
70-
...query,
71-
fields: fields.map((field, n) =>
72-
i === n ? { ...fields[i], type: (e.value === 'auto' ? undefined : e.value) as FieldType } : field
73-
),
74-
});
75-
onRunQuery();
76-
};
77-
78-
const addField = (i: number) => () => {
79-
const { fields } = query;
80-
if (!limitFields || fields.length < limitFields) {
81-
onChange({
82-
...query,
83-
fields: [...fields.slice(0, i + 1), { name: '', jsonPath: '' }, ...fields.slice(i + 1)],
84-
});
85-
onRunQuery();
86-
}
87-
};
88-
89-
const removeField = (i: number) => () => {
90-
const { fields } = query;
91-
onChange({
92-
...query,
93-
fields: [...fields.slice(0, i), ...fields.slice(i + 1)],
94-
});
95-
onRunQuery();
96-
};
97-
9857
const tabs = [
9958
{
10059
title: 'Fields',
101-
content: query.fields
102-
? query.fields.map((field, index) => (
103-
<InlineFieldRow key={index}>
104-
<InlineField
105-
label="Field"
106-
tooltip={
107-
<div>
108-
A <a href="https://goessner.net/articles/JsonPath/">JSON Path</a> query that selects one or more
109-
values from a JSON object.
110-
</div>
111-
}
112-
grow
113-
>
114-
<JsonPathQueryField
115-
onBlur={onRunQuery}
116-
onChange={onChangePath(index)}
117-
query={field.jsonPath}
118-
onData={() => datasource.metadataRequest(query, range)}
119-
/>
120-
</InlineField>
121-
<InlineField
122-
label="Type"
123-
tooltip="If Auto is set, the JSON property type is used to detect the field type."
124-
>
125-
<Select
126-
value={field.type ?? 'auto'}
127-
width={12}
128-
onChange={onChangeType(index)}
129-
options={[
130-
{ label: 'Auto', value: 'auto' },
131-
{ label: 'String', value: 'string' },
132-
{ label: 'Number', value: 'number' },
133-
{ label: 'Time', value: 'time' },
134-
{ label: 'Boolean', value: 'boolean' },
135-
]}
136-
/>
137-
</InlineField>
138-
139-
{(!limitFields || query.fields.length < limitFields) && (
140-
<a className="gf-form-label" onClick={addField(index)}>
141-
<Icon name="plus" />
142-
</a>
143-
)}
144-
145-
{query.fields.length > 1 ? (
146-
<a className="gf-form-label" onClick={removeField(index)}>
147-
<Icon name="minus" />
148-
</a>
149-
) : null}
150-
</InlineFieldRow>
151-
))
152-
: null,
60+
content: query.fields && (
61+
<FieldEditor
62+
value={query.fields}
63+
onChange={(value) => {
64+
onChange({ ...query, fields: value });
65+
onRunQuery();
66+
}}
67+
limit={limitFields}
68+
onComplete={() => datasource.metadataRequest(query, range)}
69+
/>
70+
),
15371
},
15472
{
15573
title: 'Path',

0 commit comments

Comments
 (0)