mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Canvas: Button API - Add support for GET requests (#74566)
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
import { PluginState } from '@grafana/data/src';
|
||||
import { TextDimensionConfig } from '@grafana/schema';
|
||||
import { TextDimensionConfig, TextDimensionMode } from '@grafana/schema';
|
||||
import { Button } from '@grafana/ui';
|
||||
import { DimensionContext } from 'app/features/dimensions/context';
|
||||
import { TextDimensionEditor } from 'app/features/dimensions/editors/TextDimensionEditor';
|
||||
import { APIEditor, APIEditorConfig, callApi } from 'app/plugins/panel/canvas/editor/element/APIEditor';
|
||||
import { HttpRequestMethod } from 'app/plugins/panel/canvas/panelcfg.gen';
|
||||
|
||||
import { CanvasElementItem, CanvasElementProps, defaultBgColor } from '../element';
|
||||
|
||||
@@ -19,6 +20,12 @@ interface ButtonConfig {
|
||||
api?: APIEditorConfig;
|
||||
}
|
||||
|
||||
export const defaultApiConfig: APIEditorConfig = {
|
||||
endpoint: '',
|
||||
method: HttpRequestMethod.POST,
|
||||
data: '{}',
|
||||
};
|
||||
|
||||
class ButtonDisplay extends PureComponent<CanvasElementProps<ButtonConfig, ButtonData>> {
|
||||
render() {
|
||||
const { data } = this.props;
|
||||
@@ -45,30 +52,44 @@ export const buttonItem: CanvasElementItem<ButtonConfig, ButtonData> = {
|
||||
display: ButtonDisplay,
|
||||
|
||||
defaultSize: {
|
||||
width: 32,
|
||||
width: 78,
|
||||
height: 32,
|
||||
},
|
||||
|
||||
getNewOptions: (options) => ({
|
||||
...options,
|
||||
config: {
|
||||
text: {
|
||||
mode: TextDimensionMode.Fixed,
|
||||
fixed: 'Button',
|
||||
},
|
||||
api: defaultApiConfig,
|
||||
},
|
||||
background: {
|
||||
color: {
|
||||
fixed: 'transparent',
|
||||
},
|
||||
},
|
||||
placement: {
|
||||
width: 32,
|
||||
height: 32,
|
||||
top: 0,
|
||||
left: 0,
|
||||
top: 100,
|
||||
left: 100,
|
||||
},
|
||||
}),
|
||||
|
||||
// Called when data changes
|
||||
prepareData: (ctx: DimensionContext, cfg: ButtonConfig) => {
|
||||
const getCfgApi = () => {
|
||||
if (cfg?.api) {
|
||||
cfg.api = { ...cfg.api, method: cfg.api.method ?? HttpRequestMethod.POST };
|
||||
return cfg.api;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
};
|
||||
|
||||
const data: ButtonData = {
|
||||
text: cfg?.text ? ctx.getText(cfg.text).value() : '',
|
||||
api: cfg?.api ?? undefined,
|
||||
api: getCfgApi(),
|
||||
};
|
||||
|
||||
return data;
|
||||
|
||||
@@ -2,11 +2,15 @@ import React, { useCallback } from 'react';
|
||||
|
||||
import { AppEvents, StandardEditorProps, StandardEditorsRegistryItem, StringFieldConfigSettings } from '@grafana/data';
|
||||
import { config, getBackendSrv } from '@grafana/runtime';
|
||||
import { Button, InlineField, InlineFieldRow, JSONFormatter } from '@grafana/ui';
|
||||
import { Button, InlineField, InlineFieldRow, JSONFormatter, RadioButtonGroup } from '@grafana/ui';
|
||||
import { StringValueEditor } from 'app/core/components/OptionsUI/string';
|
||||
import { appEvents } from 'app/core/core';
|
||||
import { defaultApiConfig } from 'app/features/canvas/elements/button';
|
||||
|
||||
import { HttpRequestMethod } from '../../panelcfg.gen';
|
||||
|
||||
export interface APIEditorConfig {
|
||||
method: string;
|
||||
endpoint: string;
|
||||
data?: string;
|
||||
}
|
||||
@@ -16,12 +20,12 @@ const dummyStringSettings = {
|
||||
} as StandardEditorsRegistryItem<string, StringFieldConfigSettings>;
|
||||
|
||||
export const callApi = (api: APIEditorConfig, isTest = false) => {
|
||||
if (api) {
|
||||
if (api && api.endpoint) {
|
||||
getBackendSrv()
|
||||
.fetch({
|
||||
url: api.endpoint!,
|
||||
method: 'POST',
|
||||
data: api.data ?? {},
|
||||
url: api.endpoint,
|
||||
method: api.method,
|
||||
data: getData(api),
|
||||
})
|
||||
.subscribe({
|
||||
error: (error) => {
|
||||
@@ -39,10 +43,28 @@ export const callApi = (api: APIEditorConfig, isTest = false) => {
|
||||
}
|
||||
};
|
||||
|
||||
const getData = (api: APIEditorConfig) => {
|
||||
let data: string | undefined = api.data ?? '{}';
|
||||
if (api.method === HttpRequestMethod.GET) {
|
||||
data = undefined;
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
type Props = StandardEditorProps<APIEditorConfig>;
|
||||
|
||||
const httpMethodOptions = [
|
||||
{ label: HttpRequestMethod.GET, value: HttpRequestMethod.GET },
|
||||
{ label: HttpRequestMethod.POST, value: HttpRequestMethod.POST },
|
||||
];
|
||||
|
||||
export function APIEditor({ value, context, onChange }: Props) {
|
||||
const labelWidth = 9;
|
||||
const LABEL_WIDTH = 9;
|
||||
|
||||
if (!value) {
|
||||
value = defaultApiConfig;
|
||||
}
|
||||
|
||||
const onEndpointChange = useCallback(
|
||||
(endpoint = '') => {
|
||||
@@ -64,6 +86,16 @@ export function APIEditor({ value, context, onChange }: Props) {
|
||||
[onChange, value]
|
||||
);
|
||||
|
||||
const onMethodChange = useCallback(
|
||||
(method: string) => {
|
||||
onChange({
|
||||
...value,
|
||||
method,
|
||||
});
|
||||
},
|
||||
[onChange, value]
|
||||
);
|
||||
|
||||
const renderJSON = (data: string) => {
|
||||
try {
|
||||
const json = JSON.parse(data);
|
||||
@@ -92,7 +124,12 @@ export function APIEditor({ value, context, onChange }: Props) {
|
||||
return config.disableSanitizeHtml ? (
|
||||
<>
|
||||
<InlineFieldRow>
|
||||
<InlineField label={'Endpoint'} labelWidth={labelWidth} grow={true}>
|
||||
<InlineField label="Method" labelWidth={LABEL_WIDTH} grow={true}>
|
||||
<RadioButtonGroup value={value?.method} options={httpMethodOptions} onChange={onMethodChange} fullWidth />
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
<InlineFieldRow>
|
||||
<InlineField label={'Endpoint'} labelWidth={LABEL_WIDTH} grow={true}>
|
||||
<StringValueEditor
|
||||
context={context}
|
||||
value={value?.endpoint}
|
||||
@@ -101,19 +138,21 @@ export function APIEditor({ value, context, onChange }: Props) {
|
||||
/>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
<InlineFieldRow>
|
||||
<InlineField label={'Data'} labelWidth={labelWidth} grow={true}>
|
||||
<StringValueEditor
|
||||
context={context}
|
||||
value={value?.data ?? '{}'}
|
||||
onChange={onDataChange}
|
||||
item={dummyStringSettings}
|
||||
/>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
{value?.method === HttpRequestMethod.POST && (
|
||||
<InlineFieldRow>
|
||||
<InlineField label={'Data'} labelWidth={LABEL_WIDTH} grow={true}>
|
||||
<StringValueEditor
|
||||
context={context}
|
||||
value={value?.data ?? '{}'}
|
||||
onChange={onDataChange}
|
||||
item={dummyStringSettings}
|
||||
/>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
)}
|
||||
{renderTestAPIButton(value)}
|
||||
<br />
|
||||
{renderJSON(value?.data ?? '{}')}
|
||||
{value?.method === HttpRequestMethod.POST && renderJSON(value?.data ?? '{}')}
|
||||
</>
|
||||
) : (
|
||||
<>Must enable disableSanitizeHtml feature flag to access</>
|
||||
|
||||
@@ -56,6 +56,8 @@ composableKinds: PanelCfg: {
|
||||
width?: float64
|
||||
} @cuetsy(kind="interface")
|
||||
|
||||
HttpRequestMethod: "GET" | "POST" @cuetsy(kind="enum", memberNames="GET|POST")
|
||||
|
||||
ConnectionCoordinates: {
|
||||
x: float64
|
||||
y: float64
|
||||
|
||||
@@ -59,6 +59,11 @@ export interface LineConfig {
|
||||
width?: number;
|
||||
}
|
||||
|
||||
export enum HttpRequestMethod {
|
||||
GET = 'GET',
|
||||
POST = 'POST',
|
||||
}
|
||||
|
||||
export interface ConnectionCoordinates {
|
||||
x: number;
|
||||
y: number;
|
||||
|
||||
Reference in New Issue
Block a user