SimulationQueryEditor.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. import React, { FormEvent, useMemo } from 'react';
  2. import { useAsync } from 'react-use';
  3. import { DataFrameJSON, SelectableValue } from '@grafana/data';
  4. import {
  5. InlineField,
  6. InlineFieldRow,
  7. Button,
  8. FieldSet,
  9. InlineSwitch,
  10. Input,
  11. Label,
  12. Select,
  13. Form,
  14. TextArea,
  15. } from '@grafana/ui';
  16. import { EditorProps } from '../QueryEditor';
  17. import { SimulationQuery } from '../types';
  18. // Type string `json:"type"`
  19. // Name string `json:"name"`
  20. // Description string `json:"description"`
  21. // OnlyForward bool `json:"forward"`
  22. // ConfigFields *data.Frame `json:"config"`
  23. interface SimInfo {
  24. type: string;
  25. name: string;
  26. description: string;
  27. forward: boolean;
  28. config: DataFrameJSON;
  29. }
  30. interface FormDTO {
  31. config: string;
  32. }
  33. export const SimulationQueryEditor = ({ onChange, query, ds }: EditorProps) => {
  34. const simQuery = query.sim ?? ({} as SimulationQuery);
  35. const simKey = simQuery.key ?? ({} as typeof simQuery.key);
  36. // This only changes once
  37. const info = useAsync(async () => {
  38. const v = (await ds.getResource('sims')) as SimInfo[];
  39. return {
  40. sims: v,
  41. options: v.map((s) => ({ label: s.name, value: s.type, description: s.description })),
  42. };
  43. }, [ds]);
  44. const current = useMemo(() => {
  45. const type = simKey.type;
  46. if (!type || !info.value) {
  47. return {};
  48. }
  49. return {
  50. details: info.value.sims.find((v) => v.type === type),
  51. option: info.value.options.find((v) => v.value === type),
  52. };
  53. }, [info.value, simKey?.type]);
  54. let config = useAsync(async () => {
  55. let path = simKey.type + '/' + simKey.tick + 'hz';
  56. if (simKey.uid) {
  57. path += '/' + simKey.uid;
  58. }
  59. return (await ds.getResource('sim/' + path))?.config;
  60. }, [simKey.type, simKey.tick, simKey.uid]);
  61. const onUpdateKey = (key: typeof simQuery.key) => {
  62. onChange({ ...query, sim: { ...simQuery, key } });
  63. };
  64. const onUIDChanged = (e: FormEvent<HTMLInputElement>) => {
  65. const { value } = e.target as HTMLInputElement;
  66. onUpdateKey({ ...simKey, uid: value ?? undefined });
  67. };
  68. const onTickChanged = (e: FormEvent<HTMLInputElement>) => {
  69. const tick = e.currentTarget.valueAsNumber;
  70. onUpdateKey({ ...simKey, tick });
  71. };
  72. const onTypeChange = (v: SelectableValue<string>) => {
  73. onUpdateKey({ ...simKey, type: v.value! });
  74. };
  75. const onToggleStream = () => {
  76. onChange({ ...query, sim: { ...simQuery, stream: !simQuery.stream } });
  77. };
  78. const onToggleLast = () => {
  79. onChange({ ...query, sim: { ...simQuery, last: !simQuery.last } });
  80. };
  81. const onSubmitChange = (data: FormDTO) => {
  82. let path = simKey.type + '/' + simKey.tick + 'hz';
  83. if (simKey.uid) {
  84. path += '/' + simKey.uid;
  85. }
  86. ds.postResource('sim/' + path, JSON.parse(data.config));
  87. };
  88. return (
  89. <>
  90. <InlineFieldRow>
  91. <InlineField labelWidth={14} label="Simulation" tooltip="">
  92. <Select
  93. isLoading={info.loading}
  94. options={info.value?.options ?? []}
  95. value={current.option}
  96. onChange={onTypeChange}
  97. width={32}
  98. />
  99. </InlineField>
  100. </InlineFieldRow>
  101. <InlineFieldRow>
  102. <InlineField labelWidth={14} label="Stream" tooltip="connect to the live channel">
  103. <InlineSwitch value={Boolean(simQuery.stream)} onChange={onToggleStream} />
  104. </InlineField>
  105. <InlineField label="Interval" tooltip="the rate a simulation will spit out events">
  106. <Input
  107. width={10}
  108. type="number"
  109. value={simKey.tick}
  110. onChange={onTickChanged}
  111. min={1 / 10}
  112. max={50}
  113. suffix="hz"
  114. />
  115. </InlineField>
  116. <InlineField label="Last" tooltip="Only return the last value">
  117. <Label>
  118. <InlineSwitch value={Boolean(simQuery.last)} onChange={onToggleLast} />
  119. </Label>
  120. </InlineField>
  121. <InlineField label="UID" tooltip="A UID will allow multiple simulations to run at the same time">
  122. <Input type="text" placeholder="optional" value={simQuery.key.uid} onChange={onUIDChanged} />
  123. </InlineField>
  124. </InlineFieldRow>
  125. <div>
  126. <Form onSubmit={onSubmitChange}>
  127. {({ register }) => (
  128. <FieldSet>
  129. <TextArea {...register('config')} defaultValue={JSON.stringify(config.value, null, 2)} rows={7} />
  130. <Button type="submit">Submit</Button>
  131. </FieldSet>
  132. )}
  133. </Form>
  134. SCHEMA:
  135. <pre>{JSON.stringify(current.details?.config.schema, null, 2)}</pre>
  136. </div>
  137. </>
  138. );
  139. };