Files
Erik Sundell a111cc0d5c Stackdriver: Support for SLO queries (#22917)
* wip: add slo support

* Export DataSourcePlugin

* wip: break out metric query editor into its own component

* wip: refactor frontend - keep SLO and Metric query in differnt objects

* wip - load services and slos

* Fix broken test

* Add interactive slo expression builder

* Change order of dropdowns

* Refactoring backend model. slo unit testing in progress

* Unit test migration and SLOs

* Cleanup SLO editor

* Simplify alias by component

* Support alias by for slos

* Support slos in variable queries

* Fix broken last query error

* Update Help section to include SLO aliases

* streamline datasource resource cache

* Break out api specific stuff in datasource to its own file

* Move get projects call to frontend

* Refactor api caching

* Unit test api service

* Fix lint go issue

* Fix typescript strict errors

* Fix test datasource

* Use budget fraction selector instead of budget

* Reset SLO when service is changed

* Handle error in case resource call returned no data

* Show real SLI display name

* Use unsafe prefix on will mount hook

* Store goal in query model since it will be used as soon as graph panel supports adding a threshold

* Add comment to describe why componentWillMount is used

* Interpolate sloid

* Break out SLO aggregation into its own func

* Also test group bys for metricquery test

* Remove not used type fields

* Remove annoying stackdriver prefix from error message

* Default view param to FULL

* Add part about SLO query builder in docs

* Use new images

* Fixes after feedback

* Add one more group by test

* Make stackdriver types internal

* Update docs/sources/features/datasources/stackdriver.md

Co-Authored-By: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>

* Update docs/sources/features/datasources/stackdriver.md

Co-Authored-By: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>

* Update docs/sources/features/datasources/stackdriver.md

Co-Authored-By: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>

* Updates after PR feedback

* add test for when no alias by defined

* fix infinite loop when newVariables feature flag is on

onChange being called in componentDidUpdate produces an
infinite loop when using the new React template variable
implementation.

Also fixes a spelling mistake

* implements feedback for documentation changes

* more doc changes

Co-authored-by: Diana Payton <52059945+oddlittlebird@users.noreply.github.com>
Co-authored-by: Daniel Lee <dan.limerick@gmail.com>
2020-03-27 12:01:16 +01:00

150 lines
4.4 KiB
TypeScript

import React from 'react';
import { Input } from '@grafana/ui';
import { TemplateSrv } from 'app/features/templating/template_srv';
import { SelectableValue } from '@grafana/data';
import StackdriverDatasource from '../datasource';
import { Metrics, LabelFilter, AnnotationsHelp, Project } from './';
import { toOption } from '../functions';
import { AnnotationTarget, MetricDescriptor } from '../types';
export interface Props {
onQueryChange: (target: AnnotationTarget) => void;
target: AnnotationTarget;
datasource: StackdriverDatasource;
templateSrv: TemplateSrv;
}
interface State extends AnnotationTarget {
variableOptionGroup: SelectableValue<string>;
variableOptions: Array<SelectableValue<string>>;
labels: any;
[key: string]: any;
}
const DefaultTarget: State = {
projectName: '',
projects: [],
metricType: '',
filters: [],
metricKind: '',
valueType: '',
refId: 'annotationQuery',
title: '',
text: '',
labels: {},
variableOptionGroup: {},
variableOptions: [],
};
export class AnnotationQueryEditor extends React.Component<Props, State> {
state: State = DefaultTarget;
async UNSAFE_componentWillMount() {
// Unfortunately, migrations like this need to go componentWillMount. As soon as there's
// migration hook for this module.ts, we can do the migrations there instead.
const { target, datasource } = this.props;
if (!target.projectName) {
target.projectName = datasource.getDefaultProject();
}
const variableOptionGroup = {
label: 'Template Variables',
options: datasource.variables.map(toOption),
};
const projects = await datasource.getProjects();
this.setState({
variableOptionGroup,
variableOptions: variableOptionGroup.options,
...target,
projects,
});
datasource.getLabels(target.metricType, target.projectName, target.refId).then(labels => this.setState({ labels }));
}
onMetricTypeChange = ({ valueType, metricKind, type, unit }: MetricDescriptor) => {
const { onQueryChange, datasource } = this.props;
this.setState(
{
metricType: type,
unit,
valueType,
metricKind,
},
() => {
onQueryChange(this.state);
}
);
datasource.getLabels(type, this.state.refId, this.state.projectName).then(labels => this.setState({ labels }));
};
onChange(prop: string, value: string | string[]) {
this.setState({ [prop]: value }, () => {
this.props.onQueryChange(this.state);
});
}
render() {
const { metricType, projectName, filters, title, text, variableOptionGroup, labels, variableOptions } = this.state;
const { datasource } = this.props;
return (
<>
<Project
templateVariableOptions={variableOptions}
datasource={datasource}
projectName={projectName || datasource.getDefaultProject()}
onChange={value => this.onChange('projectName', value)}
/>
<Metrics
projectName={projectName}
metricType={metricType}
templateSrv={datasource.templateSrv}
datasource={datasource}
templateVariableOptions={variableOptions}
onChange={metric => this.onMetricTypeChange(metric)}
>
{metric => (
<>
<LabelFilter
labels={labels}
filters={filters}
onChange={value => this.onChange('filters', value)}
variableOptionGroup={variableOptionGroup}
/>
</>
)}
</Metrics>
<div className="gf-form gf-form-inline">
<div className="gf-form">
<span className="gf-form-label query-keyword width-9">Title</span>
<Input
type="text"
className="gf-form-input width-20"
value={title}
onChange={e => this.onChange('title', e.target.value)}
/>
</div>
<div className="gf-form">
<span className="gf-form-label query-keyword width-9">Text</span>
<Input
type="text"
className="gf-form-input width-20"
value={text}
onChange={e => this.onChange('text', e.target.value)}
/>
</div>
<div className="gf-form gf-form--grow">
<div className="gf-form-label gf-form-label--grow" />
</div>
</div>
<AnnotationsHelp />
</>
);
}
}