1import { SelectableValue } from '@grafana/data';
2import { Alert, InlineField, Input, Select } from '@grafana/ui';
3import React, { ChangeEvent, useCallback, useEffect, useState } from 'react';
4import { AzureMonitorQuery, AzureQueryType } from '../../types';
5import LogsQueryEditor from '../LogsQueryEditor';
6import DataSource from '../../datasource';
7import useLastError from '../../utils/useLastError';
8import { Space } from '../Space';
9import { migrateStringQueriesToObjectQueries } from '../../grafanaTemplateVariableFns';
10
11const AZURE_QUERY_VARIABLE_TYPE_OPTIONS = [
12  { label: 'Grafana Query Function', value: AzureQueryType.GrafanaTemplateVariableFn },
13  { label: 'Logs', value: AzureQueryType.LogAnalytics },
14];
15
16const GrafanaTemplateVariableFnInput = ({
17  query,
18  updateQuery,
19  datasource,
20}: {
21  query: AzureMonitorQuery;
22  updateQuery: (val: AzureMonitorQuery) => void;
23  datasource: DataSource;
24}) => {
25  const [inputVal, setInputVal] = useState('');
26  useEffect(() => {
27    setInputVal(query.grafanaTemplateVariableFn?.rawQuery || '');
28  }, [query.grafanaTemplateVariableFn?.rawQuery]);
29
30  const onRunQuery = useCallback(
31    (newQuery: string) => {
32      migrateStringQueriesToObjectQueries(newQuery, { datasource }).then((updatedQuery) => {
33        if (updatedQuery.queryType === AzureQueryType.GrafanaTemplateVariableFn) {
34          updateQuery(updatedQuery);
35        } else {
36          updateQuery({
37            ...query,
38            grafanaTemplateVariableFn: {
39              kind: 'UnknownQuery',
40              rawQuery: newQuery,
41            },
42          });
43        }
44      });
45    },
46    [datasource, query, updateQuery]
47  );
48
49  const onChange = (event: ChangeEvent<HTMLInputElement>) => {
50    setInputVal(event.target.value);
51  };
52
53  return (
54    <InlineField label="Grafana template variable function">
55      <Input
56        placeholder={'type a grafana template variable function, ex: Subscriptions()'}
57        value={inputVal}
58        onChange={onChange}
59        onBlur={() => onRunQuery(inputVal)}
60      />
61    </InlineField>
62  );
63};
64
65type Props = {
66  query: AzureMonitorQuery | string;
67  onChange: (query: AzureMonitorQuery) => void;
68  datasource: DataSource;
69};
70
71const VariableEditor = (props: Props) => {
72  const defaultQuery: AzureMonitorQuery = {
73    refId: 'A',
74    queryType: AzureQueryType.GrafanaTemplateVariableFn,
75  };
76  const [query, setQuery] = useState(defaultQuery);
77
78  useEffect(() => {
79    migrateStringQueriesToObjectQueries(props.query, { datasource: props.datasource }).then((migratedQuery) => {
80      setQuery(migratedQuery);
81    });
82  }, [props.query, props.datasource]);
83
84  const onQueryTypeChange = (selectableValue: SelectableValue) => {
85    if (selectableValue.value) {
86      setQuery({
87        ...query,
88        queryType: selectableValue.value,
89      });
90    }
91  };
92  const onLogsQueryChange = (queryChange: AzureMonitorQuery) => {
93    setQuery(queryChange);
94
95    // only hit backend if there's something to query (prevents error when selecting the resource before pinging a query)
96    if (queryChange.azureLogAnalytics?.query) {
97      props.onChange(queryChange);
98    }
99  };
100
101  const [errorMessage, setError] = useLastError();
102
103  const variableOptionGroup = {
104    label: 'Template Variables',
105    // TODO: figure out a way to filter out the current variable from the variables list
106    // options: props.datasource.getVariables().map((v) => ({ label: v, value: v })),
107    options: [],
108  };
109
110  return (
111    <>
112      <InlineField label="Select query type">
113        <Select
114          aria-label="select query type"
115          onChange={onQueryTypeChange}
116          options={AZURE_QUERY_VARIABLE_TYPE_OPTIONS}
117          width={25}
118          value={query.queryType}
119        />
120      </InlineField>
121      {query.queryType === AzureQueryType.LogAnalytics && (
122        <>
123          <LogsQueryEditor
124            subscriptionId={query.subscription}
125            query={query}
126            datasource={props.datasource}
127            onChange={onLogsQueryChange}
128            variableOptionGroup={variableOptionGroup}
129            setError={setError}
130            hideFormatAs={true}
131          />
132          {errorMessage && (
133            <>
134              <Space v={2} />
135              <Alert severity="error" title="An error occurred while requesting metadata from Azure Monitor">
136                {errorMessage}
137              </Alert>
138            </>
139          )}
140        </>
141      )}
142      {query.queryType === AzureQueryType.GrafanaTemplateVariableFn && (
143        <GrafanaTemplateVariableFnInput query={query} updateQuery={props.onChange} datasource={props.datasource} />
144      )}
145    </>
146  );
147};
148
149export default VariableEditor;
150