1import React from 'react';
2import useAsync from 'react-use/lib/useAsync';
3import { getDS } from './utils';
4import { InlineField, InlineFieldRow } from '@grafana/ui';
5import { AdHocVariableFilter } from '../../../../features/variables/types';
6import { TempoQuery } from '../datasource';
7import { AdHocFilter } from '../../../../features/variables/adhoc/picker/AdHocFilter';
8import { PrometheusDatasource } from '../../prometheus/datasource';
9
10export function ServiceGraphSection({
11  graphDatasourceUid,
12  query,
13  onChange,
14}: {
15  graphDatasourceUid?: string;
16  query: TempoQuery;
17  onChange: (value: TempoQuery) => void;
18}) {
19  const dsState = useAsync(() => getDS(graphDatasourceUid), [graphDatasourceUid]);
20  if (dsState.loading) {
21    return null;
22  }
23
24  const ds = dsState.value as PrometheusDatasource;
25
26  if (!graphDatasourceUid) {
27    return <div className="text-warning">Please set up a service graph datasource in the datasource settings.</div>;
28  }
29
30  if (graphDatasourceUid && !ds) {
31    return (
32      <div className="text-warning">
33        Service graph datasource is configured but the data source no longer exists. Please configure existing data
34        source to use the service graph functionality.
35      </div>
36    );
37  }
38  const filters = queryToFilter(query.serviceMapQuery || '');
39
40  return (
41    <div>
42      <InlineFieldRow>
43        <InlineField label="Filter" labelWidth={14} grow>
44          <AdHocFilter
45            datasource={{ uid: graphDatasourceUid }}
46            filters={filters}
47            addFilter={(filter: AdHocVariableFilter) => {
48              onChange({
49                ...query,
50                serviceMapQuery: filtersToQuery([...filters, filter]),
51              });
52            }}
53            removeFilter={(index: number) => {
54              const newFilters = [...filters];
55              newFilters.splice(index, 1);
56              onChange({ ...query, serviceMapQuery: filtersToQuery(newFilters) });
57            }}
58            changeFilter={(index: number, filter: AdHocVariableFilter) => {
59              const newFilters = [...filters];
60              newFilters.splice(index, 1, filter);
61              onChange({ ...query, serviceMapQuery: filtersToQuery(newFilters) });
62            }}
63          />
64        </InlineField>
65      </InlineFieldRow>
66    </div>
67  );
68}
69
70function queryToFilter(query: string): AdHocVariableFilter[] {
71  let match;
72  let filters: AdHocVariableFilter[] = [];
73  const re = /([\w_]+)(=|!=|<|>|=~|!~)"(.*?)"/g;
74  while ((match = re.exec(query)) !== null) {
75    filters.push({
76      key: match[1],
77      operator: match[2],
78      value: match[3],
79      condition: '',
80    });
81  }
82  return filters;
83}
84
85function filtersToQuery(filters: AdHocVariableFilter[]): string {
86  return `{${filters.map((f) => `${f.key}${f.operator}"${f.value}"`).join(',')}}`;
87}
88