Skip to content

Commit f69259a

Browse files
committed
editor
1 parent f8c821a commit f69259a

File tree

4 files changed

+121
-62
lines changed

4 files changed

+121
-62
lines changed

.prettierrc.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
module.exports = {
2-
...require("./node_modules/@grafana/toolkit/src/config/prettier.plugin.config.json"),
2+
...require('./node_modules/@grafana/toolkit/src/config/prettier.plugin.config.json'),
3+
printWidth: 80,
34
};

src/buttonPanel.tsx

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,32 @@
11
import { PanelProps } from '@grafana/data';
2-
import { Button, HorizontalGroup } from '@grafana/ui';
2+
import { Button, HorizontalGroup, VerticalGroup } from '@grafana/ui';
33
import React from 'react';
44
import { ButtonOptions, Options } from 'types';
55

66
interface Props extends PanelProps<Options> {}
77

8-
export const ButtonPanel: React.FC<Props> = ({ options }) => {
8+
const Buttons: React.FC<Options> = ({ buttons }) => {
99
return (
10-
<HorizontalGroup justify="center">
11-
{options.buttons.map((b: ButtonOptions, index: number) => (
12-
<Button key={index} variant="primary">
10+
<React.Fragment>
11+
{buttons.map((b: ButtonOptions, index: number) => (
12+
<Button key={index} variant={b.variant}>
1313
{b.text || 'Button'}
1414
</Button>
1515
))}
16-
</HorizontalGroup>
16+
</React.Fragment>
17+
);
18+
};
19+
20+
export const ButtonPanel: React.FC<Props> = ({ options }) => {
21+
return (
22+
(options.orientation === 'vertical' && (
23+
<VerticalGroup justify="center" align="center">
24+
<Buttons {...options} />
25+
</VerticalGroup>
26+
)) || (
27+
<HorizontalGroup justify="center" align="center">
28+
<Buttons {...options} />
29+
</HorizontalGroup>
30+
)
1731
);
1832
};

src/editor.tsx

Lines changed: 92 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
import { PanelOptionsEditorBuilder, SelectableValue } from '@grafana/data';
22
import { getBackendSrv } from '@grafana/runtime';
3-
import { Button, Collapse, Field, Input, Select } from '@grafana/ui';
3+
import {
4+
Button,
5+
Collapse,
6+
Field,
7+
Input,
8+
RadioButtonGroup,
9+
Select,
10+
} from '@grafana/ui';
411
import React from 'react';
512
import { ButtonOptions, Options } from 'types';
613

@@ -11,83 +18,101 @@ interface EditorProps {
1118

1219
const Editor: React.FC<EditorProps> = ({ buttons, onChange }) => {
1320
const [elems, setElems] = React.useState<SelectableValue<string>[]>();
14-
const [isOpen, setOpen] = React.useState<boolean>(true);
21+
const [isOpen, setOpen] = React.useState<boolean[]>([true]);
1522
React.useEffect(() => {
16-
let isSubscribed = true;
23+
let cancel = false;
1724
const fetchData = async () => {
1825
const ds = await getBackendSrv().get('/api/datasources');
19-
if (isSubscribed)
26+
if (!cancel)
2027
setElems(
21-
ds.map((i: any) => ({
22-
label: i.name,
23-
value: i.name,
24-
name: i.name,
25-
}))
28+
ds.map((i: any) => ({ label: i.name, value: i.name, name: i.name }))
2629
);
2730
};
2831
fetchData();
2932
return (): void => {
30-
isSubscribed = false;
33+
cancel = true;
3134
};
3235
}, []);
36+
37+
const updateButtons = (index: number, newButton: ButtonOptions) => {
38+
let currentButton = { ...buttons[index] };
39+
onChange([
40+
...buttons.slice(0, index),
41+
{
42+
text: newButton.text || currentButton.text,
43+
datasource: newButton.datasource || currentButton.datasource,
44+
query: newButton.query || currentButton.query,
45+
variant: newButton.variant || currentButton.variant,
46+
},
47+
...buttons.slice(index + 1),
48+
]);
49+
};
50+
3351
return (
3452
<React.Fragment>
35-
{buttons.map((b: ButtonOptions, index: number) => (
53+
{buttons.map((b: ButtonOptions, i: number) => (
3654
<Collapse
37-
label={'Button ' + (index + 1).toString()}
38-
isOpen={isOpen}
55+
label={'Button ' + (i + 1).toString()}
56+
isOpen={isOpen[i]}
3957
collapsible
40-
onToggle={() => setOpen(!isOpen)}
58+
onToggle={() =>
59+
setOpen([...isOpen.slice(0, i), !isOpen[i], ...isOpen.slice(i + 1)])
60+
}
4161
>
4262
<Field label="Text" description="Text to be displayed on the button">
4363
<Input
44-
id={'t-' + index.toString()}
64+
id={'t-' + i.toString()}
4565
value={b.text}
4666
placeholder="Button"
47-
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
48-
let button = { ...buttons[index] };
49-
onChange([
50-
...buttons.slice(0, index),
51-
{ text: e.target.value, datasource: button.datasource, query: button.query },
52-
...buttons.slice(index + 1),
53-
]);
54-
}}
67+
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
68+
updateButtons(i, { text: e.target.value })
69+
}
5570
/>
5671
</Field>
57-
<Field label="Datasource" description="Select Datasource for the query">
72+
<Field
73+
label="Datasource"
74+
description="Choose the Datasource for the query"
75+
>
5876
<Select
59-
onChange={(e: SelectableValue<string>) => {
60-
let button = { ...buttons[index] };
61-
onChange([
62-
...buttons.slice(0, index),
63-
{ text: button.text, datasource: e.value || '', query: button.query },
64-
...buttons.slice(index + 1),
65-
]);
66-
}}
77+
onChange={(e: SelectableValue<string>) =>
78+
updateButtons(i, { datasource: e.value })
79+
}
6780
options={elems}
6881
/>
6982
</Field>
70-
<Field label="Query" description="Query to be triggered on Button Click">
83+
<Field
84+
label="Query"
85+
description="Query to be triggered on Button Click"
86+
>
7187
<Input
72-
id={'q-' + index.toString()}
88+
id={'q-' + i.toString()}
7389
value={b.query}
74-
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
75-
let button = { ...buttons[index] };
76-
onChange([
77-
...buttons.slice(0, index),
78-
{ text: button.text, datasource: button.datasource, query: e.target.value },
79-
...buttons.slice(index + 1),
80-
]);
81-
}}
90+
placeholder="Query"
91+
onChange={(e: React.ChangeEvent<HTMLInputElement>) =>
92+
updateButtons(i, { query: e.target.value })
93+
}
8294
/>
8395
</Field>
96+
<Field label="Color" description="Color of the button">
97+
<RadioButtonGroup
98+
options={[
99+
{ label: 'Primary', value: 'primary' },
100+
{ label: 'Secondary', value: 'secondary' },
101+
{ label: 'Destructive', value: 'destructive' },
102+
{ label: 'Link', value: 'link' },
103+
]}
104+
value={b.variant || 'primary'}
105+
fullWidth
106+
onChange={(e: any) => updateButtons(i, { variant: e })}
107+
></RadioButtonGroup>
108+
</Field>
84109
<Field>
85110
<Button
86111
icon="trash-alt"
87112
variant="destructive"
88-
onClick={() => {
89-
console.log('trash');
90-
}}
113+
onClick={() =>
114+
onChange([...buttons.slice(0, i), ...buttons.slice(i + 1)])
115+
}
91116
>
92117
Delete
93118
</Button>
@@ -111,11 +136,26 @@ const Editor: React.FC<EditorProps> = ({ buttons, onChange }) => {
111136
};
112137

113138
export function addEditor(builder: PanelOptionsEditorBuilder<Options>) {
114-
builder.addCustomEditor({
115-
id: 'buttons',
116-
path: 'buttons',
117-
name: '',
118-
defaultValue: [{ text: '', datasource: '', query: '' }],
119-
editor: props => <Editor buttons={props.value} onChange={props.onChange} />,
120-
});
139+
builder
140+
.addRadio({
141+
path: 'orientation',
142+
name: 'Orientation',
143+
description: 'Stacking direction in case of multiple buttons',
144+
defaultValue: 'horizontal',
145+
settings: {
146+
options: [
147+
{ value: 'horizontal', label: 'Horizontal' },
148+
{ value: 'vertical', label: 'Vertical' },
149+
],
150+
},
151+
})
152+
.addCustomEditor({
153+
id: 'buttons',
154+
path: 'buttons',
155+
name: 'Button Configuration',
156+
defaultValue: [{ text: '', datasource: '', query: '' }],
157+
editor: props => (
158+
<Editor buttons={props.value} onChange={props.onChange} />
159+
),
160+
});
121161
}

src/types.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
import { ButtonVariant } from '@grafana/ui';
2+
13
export interface ButtonOptions {
2-
text: string;
3-
query: string;
4-
datasource: string;
4+
text?: string;
5+
query?: string;
6+
datasource?: string;
7+
variant?: ButtonVariant;
58
}
69

710
export interface Options {
811
buttons: ButtonOptions[];
12+
orientation: string;
913
}

0 commit comments

Comments
 (0)