Skip to content

Commit 3c729d2

Browse files
committed
update event handler function
1 parent c47f878 commit 3c729d2

File tree

7 files changed

+65
-63
lines changed

7 files changed

+65
-63
lines changed

src/ConfigEditor.tsx

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,35 @@
1-
import React, { useState, useEffect } from 'react';
1+
import React, { ChangeEvent } from 'react';
22
import { Form, Field, FieldSet, Input } from '@grafana/ui';
33
import { DataSourcePluginOptionsEditorProps } from '@grafana/data';
44
import { MqttDataSourceOptions, MqttSecureJsonData } from './types';
5-
import { handleEvent } from './handleEvent';
5+
import { handlerFactory } from './handleEvent';
66

77
interface Props extends DataSourcePluginOptionsEditorProps<MqttDataSourceOptions> {}
88

99
export const ConfigEditor = (props: Props) => {
1010
const {
11-
options,
12-
options: { jsonData, secureJsonFields, secureJsonData },
1311
onOptionsChange,
12+
options,
13+
options: { jsonData, secureJsonData },
1414
} = props;
15-
const secureData = (secureJsonData ?? {}) as MqttSecureJsonData;
16-
const [host, setHost] = useState(jsonData.host ?? 'localhost');
17-
const [port, setPort] = useState<number>(jsonData.port ?? 1883);
18-
const [username, setUsername] = useState(jsonData.username ?? '');
19-
const [password, setPassword] = useState(secureData.password ?? '');
20-
21-
useEffect(() => {
22-
onOptionsChange({
23-
...options,
24-
jsonData: {
25-
...jsonData,
26-
host,
27-
port,
28-
username,
29-
},
30-
secureJsonData: {
31-
...secureData,
32-
password,
33-
},
34-
secureJsonFields: {
35-
...secureJsonFields,
36-
password: Boolean(password),
37-
},
38-
});
39-
}, [host, port, username, password]);
15+
const { host, port, username } = jsonData;
16+
const { password } = (secureJsonData ?? {}) as MqttSecureJsonData;
17+
const handleChange = handlerFactory(options, onOptionsChange);
4018

4119
return (
4220
<Form onSubmit={() => {}}>
4321
{() => (
4422
<>
4523
<FieldSet label="Connection">
4624
<Field label="Host">
47-
<Input name="host" required value={host} css="" autoComplete="off" onChange={handleEvent(setHost)} />
25+
<Input
26+
name="host"
27+
required
28+
value={host}
29+
css=""
30+
autoComplete="off"
31+
onChange={handleChange('jsonData.host')}
32+
/>
4833
</Field>
4934
<Field label="Port">
5035
<Input
@@ -54,14 +39,20 @@ export const ConfigEditor = (props: Props) => {
5439
value={port}
5540
css=""
5641
autoComplete="off"
57-
onChange={handleEvent(Number, setPort)}
42+
onChange={handleChange('jsonData.port', Number)}
5843
/>
5944
</Field>
6045
</FieldSet>
6146

6247
<FieldSet label="Authentication">
6348
<Field label="Username">
64-
<Input name="username" value={username} css="" autoComplete="off" onChange={handleEvent(setUsername)} />
49+
<Input
50+
name="username"
51+
value={username}
52+
css=""
53+
autoComplete="off"
54+
onChange={handleChange('jsonData.username')}
55+
/>
6556
</Field>
6657
<Field label="Password">
6758
<Input
@@ -71,7 +62,10 @@ export const ConfigEditor = (props: Props) => {
7162
autoComplete="off"
7263
placeholder="************************"
7364
value={password}
74-
onChange={handleEvent(setPassword)}
65+
onChange={(event: ChangeEvent<HTMLInputElement>) => {
66+
handleChange('secureJsonData.password')(event);
67+
handleChange('secureJsonFields.password', Boolean)(event);
68+
}}
7569
/>
7670
</Field>
7771
</FieldSet>

src/QueryEditor.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
1-
import React, { useState, useEffect } from 'react';
1+
import React from 'react';
22
import { Form, Field, Input } from '@grafana/ui';
33
import { QueryEditorProps } from '@grafana/data';
44
import { DataSource } from './datasource';
55
import { MqttDataSourceOptions, MqttQuery } from './types';
6-
import { handleEvent } from 'handleEvent';
6+
import { handlerFactory } from 'handleEvent';
77

88
type Props = QueryEditorProps<DataSource, MqttQuery, MqttDataSourceOptions>;
99

1010
export const QueryEditor = (props: Props) => {
1111
const { query, onChange } = props;
12-
const [queryText, setQueryText] = useState(query.queryText ?? '');
13-
useEffect(() => onChange({ ...query, queryText, stream: true }), [queryText]);
12+
const handleEvent = handlerFactory(query, onChange);
1413

1514
return (
1615
<Form onSubmit={() => {}}>
@@ -19,10 +18,10 @@ export const QueryEditor = (props: Props) => {
1918
<Input
2019
name="queryText"
2120
required
22-
value={queryText}
21+
value={query.queryText}
2322
css=""
2423
autoComplete="off"
25-
onChange={handleEvent(setQueryText)}
24+
onChange={handleEvent('queryText')}
2625
/>
2726
</Field>
2827
)}

src/handleEvent.test.ts

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,36 @@
11
import { ChangeEvent } from 'react';
2-
import { handleEvent } from './handleEvent';
2+
import { handlerFactory } from './handleEvent';
33

44
const changeEvent = {
55
currentTarget: {
66
value: 'test',
77
},
88
} as ChangeEvent<HTMLInputElement>;
99

10-
describe('handleEvent', () => {
10+
describe('handlerFactory', () => {
1111
it('returns value from event', () => {
12-
const handler = handleEvent();
13-
expect(handler(changeEvent)).toMatchInlineSnapshot(`"test"`);
12+
const cb = jest.fn();
13+
const handler = handlerFactory({ a: { b: 'c' } }, cb);
14+
handler('a.b')(changeEvent);
15+
expect(cb.mock.calls[0][0]).toMatchInlineSnapshot(`
16+
Object {
17+
"a": Object {
18+
"b": "test",
19+
},
20+
}
21+
`);
1422
});
1523

16-
it('calls the handler functions left to right', () => {
17-
const one = (v: string) => `${v}-1`;
18-
const two = (v: string) => `${v}-2`;
19-
const three = (v: string) => `${v}-3`;
20-
21-
const handler = handleEvent(one, two, three);
22-
expect(handler(changeEvent)).toMatchInlineSnapshot(`"test-1-2-3"`);
24+
it('calls the formatting function', () => {
25+
const cb = jest.fn();
26+
const handler = handlerFactory({ a: { b: 'c' } }, cb);
27+
handler('a.b', v => v.toUpperCase())(changeEvent);
28+
expect(cb.mock.calls[0][0]).toMatchInlineSnapshot(`
29+
Object {
30+
"a": Object {
31+
"b": "TEST",
32+
},
33+
}
34+
`);
2335
});
2436
});

src/handleEvent.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
import { ChangeEvent } from 'react';
2+
import _ from 'lodash';
23

3-
export type ReturnValue = string | number | boolean | null | void;
4-
export type EventHandler = (value: any) => ReturnValue;
5-
6-
/**
7-
* calls functions passed as args with `event?.currentTarget.value`
8-
* passed to the first function, and the return value of the preceeding function
9-
* for every function after the first.
10-
*/
11-
export const handleEvent = (...fns: EventHandler[]) => (event: ChangeEvent<HTMLInputElement>) =>
12-
fns.reduce((result: ReturnValue, fn: EventHandler) => fn.call(null, result), event?.currentTarget.value);
4+
export const handlerFactory = (original: object, onChange: (copy: any) => void) => (
5+
path: string,
6+
format: (value: string) => string | number | boolean | null = value => value
7+
) => (event: ChangeEvent<HTMLInputElement>): void => {
8+
const copy = _.cloneDeep(original);
9+
onChange(_.set(copy, path, format(event.currentTarget.value)));
10+
};

src/img/logo.jpg

64.8 KB
Loading

src/img/logo.svg

Lines changed: 0 additions & 1 deletion
This file was deleted.

src/plugin.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
"iot"
1818
],
1919
"logos": {
20-
"small": "img/logo.svg",
21-
"large": "img/logo.svg"
20+
"small": "img/logo.jpg",
21+
"large": "img/logo.jpg"
2222
},
2323
"links": [
2424
{

0 commit comments

Comments
 (0)