Skip to content

Commit

Permalink
Allow dynamic list of key/value parameters
Browse files Browse the repository at this point in the history
Addressingg the review comments from grafana/grafana-plugin-repository#658
allowing for a unlimited number of key/value pairs for Header/Query parameters
  • Loading branch information
derjust committed Jun 24, 2020
1 parent 4245d42 commit 35f29c7
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 21 deletions.
14 changes: 8 additions & 6 deletions src/ButtonPanel.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import React, { PureComponent } from 'react';
import { Button } from '@grafana/ui';
import { Button, IconName } from '@grafana/ui';
import { PanelProps } from '@grafana/data';
import { ButtonPanelOptions, ButtonPanelState } from 'types';
import { IconName } from '@grafana/ui';

interface Props extends PanelProps<ButtonPanelOptions> {}

Expand All @@ -28,7 +27,7 @@ export class ButtonPanel extends PureComponent<Props, ButtonPanelState> {
};
const exeucte = () => {
this.setState({ api_call: 'IN_PROGRESS' });
console.log(options.method, ' to ', options.url, ' with key as ', options.type?.value);
console.log(options.method?.value, ' to ', options.url, ' with key as ', options.type?.value);

const url = new URL(options.url);

Expand All @@ -46,11 +45,14 @@ export class ButtonPanel extends PureComponent<Props, ButtonPanelState> {
//referrerPolicy: 'no-referrer', // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
};

debugger;
if (options.type?.value === 'HEADER') {
requestHeaders.set('X-API-Key', options.key);
options.params.forEach(e => {
requestHeaders.set(e[0], e[1]);
});
} else if (options.type?.value === 'QUERY') {
url.searchParams.append('api-key', options.key);
options.params.forEach(e => {
url.searchParams.append(e[0], e[1]);
});
} else {
console.error('Unknown api key type', options.type);
}
Expand Down
64 changes: 51 additions & 13 deletions src/ButtonPanelEditor.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,33 @@
import React, { PureComponent } from 'react';
import { Select } from '@grafana/ui';
import { Field, Input } from '@grafana/ui';
import { PanelEditorProps } from '@grafana/data';
import { Field, IconButton, Input, Select, HorizontalGroup, VerticalGroup } from '@grafana/ui';
import { DataFrame, FieldType, MutableDataFrame, PanelEditorProps } from '@grafana/data';
import { ButtonPanelOptions } from './types';

export class ButtonPanelEditor extends PureComponent<PanelEditorProps<ButtonPanelOptions>> {
onParamRemove = (key: string) => ({ target }: any) => {
let newParams = this.props.options.params.filter(e => e[0] !== key);
this.props.onOptionsChange({ ...this.props.options, params: newParams });
};
onParamAdd = ({ target }: any) => {
const key = this.props.options.newParamName;
let newParams = this.props.options.params.filter(e => e[0] !== key);
newParams.push([key, this.props.options.newParamValue]);
newParams.sort((a, b) => a[0].localeCompare(b[0]));
const msg = { ...this.props.options, newParamName: '', newParamValue: '', params: newParams };
this.props.onOptionsChange(msg);
};
onNewParamNameChanged = ({ target }: any) => {
this.props.onOptionsChange({ ...this.props.options, newParamName: target.value });
};
onNewParamValueChanged = ({ target }: any) => {
this.props.onOptionsChange({ ...this.props.options, newParamValue: target.value });
};
onTextChanged = ({ target }: any) => {
this.props.onOptionsChange({ ...this.props.options, text: target.value });
};
onURLChanged = ({ target }: any) => {
this.props.onOptionsChange({ ...this.props.options, url: target.value });
};
onKeyChanged = ({ target }: any) => {
this.props.onOptionsChange({ ...this.props.options, key: target.value });
};
onMethodChanged = ({ label, value, target }: any) => {
this.props.onOptionsChange({
...this.props.options,
Expand Down Expand Up @@ -42,14 +56,23 @@ export class ButtonPanelEditor extends PureComponent<PanelEditorProps<ButtonPane
});
};

paramsModel = (): DataFrame => {
return new MutableDataFrame({
fields: [
{ name: 'Name', type: FieldType.string, values: Array.from(this.props.options.params.keys()) },
{ name: 'Value', type: FieldType.string, values: Array.from(this.props.options.params.values()) },
],
});
};

render() {
const { options } = this.props;

return (
<div className="section gf-form-group">
<h5 className="section-heading">Settings</h5>

<Field label="HTTP method" description="HTTP method used to communicate with the remote site">
<Field label="Method" description="HTTP method used to communicate with the remote site">
<Select
allowCustomValue
onChange={this.onMethodChanged}
Expand All @@ -61,23 +84,38 @@ export class ButtonPanelEditor extends PureComponent<PanelEditorProps<ButtonPane
/>
</Field>

<Field label="URL" description="The URL to trigger">
<Field label="URL" description="The URL to call">
<Input required onChange={this.onURLChanged} value={options.url || ''} />
</Field>

<Field label="Type" description="Type defining how the options are sent to the server">
<Field label="Type" description="Defines how the parameters are sent to the server">
<Select
onChange={this.onTypeChanged}
value={options.type}
options={[
{ label: 'Header', value: 'HEADER', description: 'Send the API key as `X-API-Key` request HTTP header' },
{ label: 'Query', value: 'QUERY', description: 'Send the API key as `?api-key=...` query parameter' },
{ label: 'Header', value: 'HEADER', description: 'Send the parameters as request HTTP headers' },
{ label: 'Query', value: 'QUERY', description: 'Send the parameters as `key=value` query parameter' },
]}
/>
</Field>

<Field label="API Key" description="The API key sent with the request">
<Input onChange={this.onKeyChanged} value={options.key || ''} />
<Field label="Parameters" description="The parameters sent with the request">
<div className="panel-container" style={{ width: 'auto' }}>
<HorizontalGroup>
<Input placeholder="Name" onChange={this.onNewParamNameChanged} value={options.newParamName || ''} />
<Input placeholder="Value" onChange={this.onNewParamValueChanged} value={options.newParamValue || ''} />
<IconButton onClick={this.onParamAdd} name="plus" />
</HorizontalGroup>
<VerticalGroup>
{Array.from(options.params.entries()).map(entry => (
<HorizontalGroup>
<Input disabled value={entry[1][0]} />
<Input disabled value={entry[1][1]} />
<IconButton onClick={this.onParamRemove(entry[1][0])} name="minus" />
</HorizontalGroup>
))}
</VerticalGroup>
</div>
</Field>

<Field label="Variant" description="Button variant used to render">
Expand Down
9 changes: 7 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,23 @@ import { ButtonVariant } from '@grafana/ui';
export interface ButtonPanelOptions {
text: string;
url: string;
key: string;
params: Array<[string, string]>;
newParamName: string;
newParamValue: string;

method?: SelectableValue<string>;
type?: SelectableValue<string>;
variant?: SelectableValue<ButtonVariant>;
}

export const defaults: ButtonPanelOptions = {
key: 'abc1234',
text: 'The default button label',
url: 'http://api.example.com/',
method: undefined,
type: undefined,
params: [],
newParamName: '',
newParamValue: '',
variant: undefined,
};

Expand Down

0 comments on commit 35f29c7

Please sign in to comment.