import { css } from '@emotion/css'; import { startCase, uniqBy } from 'lodash'; import React, { useCallback, useEffect, useState } from 'react'; import { GrafanaTheme2, SelectableValue } from '@grafana/data'; import { TemplateSrv } from '@grafana/runtime'; import { getSelectStyles, Select, useStyles2, useTheme2 } from '@grafana/ui'; import { INNER_LABEL_WIDTH, LABEL_WIDTH, SELECT_WIDTH } from '../constants'; import CloudMonitoringDatasource from '../datasource'; import { MetricDescriptor } from '../types'; import { QueryEditorField, QueryEditorRow } from '.'; export interface Props { refId: string; onChange: (metricDescriptor: MetricDescriptor) => void; templateSrv: TemplateSrv; templateVariableOptions: Array>; datasource: CloudMonitoringDatasource; projectName: string; metricType: string; children: (metricDescriptor?: MetricDescriptor) => JSX.Element; } interface State { metricDescriptors: MetricDescriptor[]; metrics: any[]; services: any[]; service: string; metric: string; metricDescriptor?: MetricDescriptor; projectName: string | null; } export function Metrics(props: Props) { const [state, setState] = useState({ metricDescriptors: [], metrics: [], services: [], service: '', metric: '', projectName: null, }); const theme = useTheme2(); const selectStyles = getSelectStyles(theme); const customStyle = useStyles2(getStyles); const { services, service, metrics, metricDescriptors } = state; const { metricType, templateVariableOptions, projectName, templateSrv, datasource, onChange, children } = props; const getSelectedMetricDescriptor = useCallback( (metricDescriptors: MetricDescriptor[], metricType: string) => { return metricDescriptors.find((md) => md.type === templateSrv.replace(metricType))!; }, [templateSrv] ); useEffect(() => { const loadMetricDescriptors = async () => { if (projectName) { const metricDescriptors = await datasource.getMetricTypes(projectName); const services = getServicesList(metricDescriptors); setState((prevState) => ({ ...prevState, metricDescriptors, services, })); } }; loadMetricDescriptors(); }, [datasource, projectName, customStyle, selectStyles.optionDescription]); useEffect(() => { const getMetricsList = (metricDescriptors: MetricDescriptor[]) => { const selectedMetricDescriptor = getSelectedMetricDescriptor(metricDescriptors, metricType); if (!selectedMetricDescriptor) { return []; } const metricsByService = metricDescriptors .filter((m) => m.service === selectedMetricDescriptor.service) .map((m) => ({ service: m.service, value: m.type, label: m.displayName, component: function optionComponent() { return (
{m.type}
{m.description}
); }, })); return metricsByService; }; const metrics = getMetricsList(metricDescriptors); const service = metrics.length > 0 ? metrics[0].service : ''; const metricDescriptor = getSelectedMetricDescriptor(metricDescriptors, metricType); setState((prevState) => ({ ...prevState, metricDescriptor, metrics, service: service, })); }, [metricDescriptors, getSelectedMetricDescriptor, metricType, customStyle, selectStyles.optionDescription]); const onServiceChange = ({ value: service }: any) => { const metrics = metricDescriptors .filter((m: MetricDescriptor) => m.service === templateSrv.replace(service)) .map((m: MetricDescriptor) => ({ service: m.service, value: m.type, label: m.displayName, description: m.description, })); if (metrics.length > 0 && !metrics.some((m) => m.value === templateSrv.replace(metricType))) { onMetricTypeChange(metrics[0], { service, metrics }); } else { setState({ ...state, service, metrics }); } }; const onMetricTypeChange = ({ value }: SelectableValue, extra: any = {}) => { const metricDescriptor = getSelectedMetricDescriptor(state.metricDescriptors, value!); setState({ ...state, metricDescriptor, ...extra }); onChange({ ...metricDescriptor, type: value! }); }; const getServicesList = (metricDescriptors: MetricDescriptor[]) => { const services = metricDescriptors.map((m) => ({ value: m.service, label: startCase(m.serviceShortName), })); return services.length > 0 ? uniqBy(services, (s) => s.value) : []; }; return ( <> {children(state.metricDescriptor)} ); } const getStyles = (theme: GrafanaTheme2) => css` label: grafana-select-option-description; font-weight: normal; font-style: italic; color: ${theme.colors.text.secondary}; `;