mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
TestData: Add schema-based form for simulation (#49637)
* add inputs for corresponding schema * change input to default value * reformat inline fields and keep local state * add comment on state * show input on default
This commit is contained in:
parent
15b3bbad6b
commit
104c4a7630
@ -1,23 +1,14 @@
|
|||||||
import React, { FormEvent, useMemo } from 'react';
|
import React, { FormEvent, useMemo, useState } from 'react';
|
||||||
import { useAsync } from 'react-use';
|
import { useAsync } from 'react-use';
|
||||||
|
|
||||||
import { DataFrameJSON, SelectableValue } from '@grafana/data';
|
import { DataFrameJSON, SelectableValue } from '@grafana/data';
|
||||||
import {
|
import { InlineField, InlineFieldRow, InlineSwitch, Input, Label, Select } from '@grafana/ui';
|
||||||
InlineField,
|
|
||||||
InlineFieldRow,
|
|
||||||
Button,
|
|
||||||
FieldSet,
|
|
||||||
InlineSwitch,
|
|
||||||
Input,
|
|
||||||
Label,
|
|
||||||
Select,
|
|
||||||
Form,
|
|
||||||
TextArea,
|
|
||||||
} from '@grafana/ui';
|
|
||||||
|
|
||||||
import { EditorProps } from '../QueryEditor';
|
import { EditorProps } from '../QueryEditor';
|
||||||
import { SimulationQuery } from '../types';
|
import { SimulationQuery } from '../types';
|
||||||
|
|
||||||
|
import { SimulationSchemaForm } from './SimulationSchemaForm';
|
||||||
|
|
||||||
// Type string `json:"type"`
|
// Type string `json:"type"`
|
||||||
// Name string `json:"name"`
|
// Name string `json:"name"`
|
||||||
// Description string `json:"description"`
|
// Description string `json:"description"`
|
||||||
@ -31,12 +22,12 @@ interface SimInfo {
|
|||||||
forward: boolean;
|
forward: boolean;
|
||||||
config: DataFrameJSON;
|
config: DataFrameJSON;
|
||||||
}
|
}
|
||||||
interface FormDTO {
|
|
||||||
config: string;
|
|
||||||
}
|
|
||||||
export const SimulationQueryEditor = ({ onChange, query, ds }: EditorProps) => {
|
export const SimulationQueryEditor = ({ onChange, query, ds }: EditorProps) => {
|
||||||
const simQuery = query.sim ?? ({} as SimulationQuery);
|
const simQuery = query.sim ?? ({} as SimulationQuery);
|
||||||
const simKey = simQuery.key ?? ({} as typeof simQuery.key);
|
const simKey = simQuery.key ?? ({} as typeof simQuery.key);
|
||||||
|
// keep track of updated config state to pass down to form
|
||||||
|
const [cfgValue, setCfgValue] = useState<Record<string, any>>({});
|
||||||
|
|
||||||
// This only changes once
|
// This only changes once
|
||||||
const info = useAsync(async () => {
|
const info = useAsync(async () => {
|
||||||
@ -63,7 +54,9 @@ export const SimulationQueryEditor = ({ onChange, query, ds }: EditorProps) => {
|
|||||||
if (simKey.uid) {
|
if (simKey.uid) {
|
||||||
path += '/' + simKey.uid;
|
path += '/' + simKey.uid;
|
||||||
}
|
}
|
||||||
return (await ds.getResource('sim/' + path))?.config;
|
let config = (await ds.getResource('sim/' + path))?.config;
|
||||||
|
setCfgValue(config.value);
|
||||||
|
return config;
|
||||||
}, [simKey.type, simKey.tick, simKey.uid]);
|
}, [simKey.type, simKey.tick, simKey.uid]);
|
||||||
|
|
||||||
const onUpdateKey = (key: typeof simQuery.key) => {
|
const onUpdateKey = (key: typeof simQuery.key) => {
|
||||||
@ -91,14 +84,16 @@ export const SimulationQueryEditor = ({ onChange, query, ds }: EditorProps) => {
|
|||||||
const onToggleLast = () => {
|
const onToggleLast = () => {
|
||||||
onChange({ ...query, sim: { ...simQuery, last: !simQuery.last } });
|
onChange({ ...query, sim: { ...simQuery, last: !simQuery.last } });
|
||||||
};
|
};
|
||||||
const onSubmitChange = (data: FormDTO) => {
|
|
||||||
|
const onSchemaFormChange = (config: Record<string, any>) => {
|
||||||
let path = simKey.type + '/' + simKey.tick + 'hz';
|
let path = simKey.type + '/' + simKey.tick + 'hz';
|
||||||
if (simKey.uid) {
|
if (simKey.uid) {
|
||||||
path += '/' + simKey.uid;
|
path += '/' + simKey.uid;
|
||||||
}
|
}
|
||||||
ds.postResource('sim/' + path, JSON.parse(data.config));
|
ds.postResource('sim/' + path, config).then((res) => {
|
||||||
|
setCfgValue(res.config);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<InlineFieldRow>
|
<InlineFieldRow>
|
||||||
@ -112,7 +107,6 @@ export const SimulationQueryEditor = ({ onChange, query, ds }: EditorProps) => {
|
|||||||
/>
|
/>
|
||||||
</InlineField>
|
</InlineField>
|
||||||
</InlineFieldRow>
|
</InlineFieldRow>
|
||||||
|
|
||||||
<InlineFieldRow>
|
<InlineFieldRow>
|
||||||
<InlineField labelWidth={14} label="Stream" tooltip="connect to the live channel">
|
<InlineField labelWidth={14} label="Stream" tooltip="connect to the live channel">
|
||||||
<InlineSwitch value={Boolean(simQuery.stream)} onChange={onToggleStream} />
|
<InlineSwitch value={Boolean(simQuery.stream)} onChange={onToggleStream} />
|
||||||
@ -139,18 +133,11 @@ export const SimulationQueryEditor = ({ onChange, query, ds }: EditorProps) => {
|
|||||||
<Input type="text" placeholder="optional" value={simQuery.key.uid} onChange={onUIDChanged} />
|
<Input type="text" placeholder="optional" value={simQuery.key.uid} onChange={onUIDChanged} />
|
||||||
</InlineField>
|
</InlineField>
|
||||||
</InlineFieldRow>
|
</InlineFieldRow>
|
||||||
<div>
|
<SimulationSchemaForm
|
||||||
<Form onSubmit={onSubmitChange}>
|
onChange={onSchemaFormChange}
|
||||||
{({ register }) => (
|
config={cfgValue ?? config.value}
|
||||||
<FieldSet>
|
schema={current.details?.config.schema ?? { fields: [] }}
|
||||||
<TextArea {...register('config')} defaultValue={JSON.stringify(config.value, null, 2)} rows={7} />
|
/>
|
||||||
<Button type="submit">Submit</Button>
|
|
||||||
</FieldSet>
|
|
||||||
)}
|
|
||||||
</Form>
|
|
||||||
SCHEMA:
|
|
||||||
<pre>{JSON.stringify(current.details?.config.schema, null, 2)}</pre>
|
|
||||||
</div>
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
89
public/app/plugins/datasource/testdata/components/SimulationSchemaForm.tsx
vendored
Normal file
89
public/app/plugins/datasource/testdata/components/SimulationSchemaForm.tsx
vendored
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
import { css } from '@emotion/css';
|
||||||
|
import React, { FormEvent, useState, ChangeEvent } from 'react';
|
||||||
|
|
||||||
|
import { DataFrameSchema, FieldSchema, GrafanaTheme2 } from '@grafana/data';
|
||||||
|
import { useStyles2, TextArea, InlineField, Input, FieldSet, InlineSwitch } from '@grafana/ui';
|
||||||
|
|
||||||
|
interface SchemaFormProps {
|
||||||
|
config: Record<string, any>;
|
||||||
|
schema: DataFrameSchema;
|
||||||
|
onChange: (config: Record<string, any>) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderInput = (field: FieldSchema, onChange: SchemaFormProps['onChange'], config: SchemaFormProps['config']) => {
|
||||||
|
switch (field.type) {
|
||||||
|
case 'number':
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
defaultValue={config?.[field.name]}
|
||||||
|
onChange={(e: FormEvent<HTMLInputElement>) => {
|
||||||
|
const newValue = e.currentTarget.valueAsNumber;
|
||||||
|
onChange({ ...config, [field.name]: newValue });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
case 'boolean':
|
||||||
|
return (
|
||||||
|
<InlineSwitch
|
||||||
|
value={config?.[field.name] ?? true}
|
||||||
|
onChange={() => {
|
||||||
|
onChange({ ...config, [field.name]: !config[field.name] });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return (
|
||||||
|
<Input
|
||||||
|
type="string"
|
||||||
|
value={config?.[field.name]}
|
||||||
|
onChange={(e: ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const newValue = e.target.value;
|
||||||
|
onChange({ ...config, [field.name]: newValue });
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getStyles = (theme: GrafanaTheme2) => {
|
||||||
|
return {
|
||||||
|
jsonView: css`
|
||||||
|
margin-bottom: ${theme.spacing(1)};
|
||||||
|
`,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const SimulationSchemaForm = ({ config, schema, onChange }: SchemaFormProps) => {
|
||||||
|
const [jsonView, setJsonView] = useState<boolean>(false);
|
||||||
|
|
||||||
|
const styles = useStyles2(getStyles);
|
||||||
|
|
||||||
|
const onUpdateTextArea = (event: FormEvent<HTMLTextAreaElement>) => {
|
||||||
|
const element = event.target as HTMLInputElement;
|
||||||
|
onChange(JSON.parse(element.value));
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FieldSet label="Config">
|
||||||
|
<InlineSwitch
|
||||||
|
className={styles.jsonView}
|
||||||
|
label="JSON View"
|
||||||
|
showLabel
|
||||||
|
value={jsonView}
|
||||||
|
onChange={() => setJsonView(!jsonView)}
|
||||||
|
/>
|
||||||
|
{jsonView ? (
|
||||||
|
<TextArea defaultValue={JSON.stringify(config, null, 2)} rows={7} onChange={onUpdateTextArea} />
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{schema.fields.map((field) => (
|
||||||
|
<InlineField label={field.name} key={field.name} labelWidth={14}>
|
||||||
|
{renderInput(field, onChange, config)}
|
||||||
|
</InlineField>
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</FieldSet>
|
||||||
|
);
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user