Loki: remove angular (#49471)

* loki: remove angular

Co-Authored-By: Joey Tawadrous <joey.tawadrous@grafana.com>

* better backward-compatibility

* slightly better typescript check

Co-authored-by: Joey Tawadrous <joey.tawadrous@grafana.com>
This commit is contained in:
Gábor Farkas 2022-06-07 12:41:16 +02:00 committed by GitHub
parent e9fac9ee03
commit cb96f51c73
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 115 additions and 93 deletions

View File

@ -22,7 +22,6 @@ import { MetricSelect } from '../core/components/Select/MetricSelect';
import { TagFilter } from '../core/components/TagFilter/TagFilter'; import { TagFilter } from '../core/components/TagFilter/TagFilter';
import { HelpModal } from '../core/components/help/HelpModal'; import { HelpModal } from '../core/components/help/HelpModal';
import { SearchField, SearchResults, SearchResultsFilter } from '../features/search'; import { SearchField, SearchResults, SearchResultsFilter } from '../features/search';
import { LokiAnnotationsQueryEditor } from '../plugins/datasource/loki/components/AnnotationsQueryEditor';
const { SecretFormField } = LegacyForms; const { SecretFormField } = LegacyForms;
@ -143,13 +142,6 @@ export function registerAngularDirectives() {
['onChange', { watchDepth: 'reference', wrapApply: true }], ['onChange', { watchDepth: 'reference', wrapApply: true }],
]); ]);
react2AngularDirective('lokiAnnotationsQueryEditor', LokiAnnotationsQueryEditor, [
'expr',
'maxLines',
'instant',
'onChange',
['datasource', { watchDepth: 'reference' }],
]);
react2AngularDirective('datasourceHttpSettingsNext', DataSourceHttpSettings, [ react2AngularDirective('datasourceHttpSettingsNext', DataSourceHttpSettings, [
'defaultUrl', 'defaultUrl',
'showAccessOptions', 'showAccessOptions',

View File

@ -236,7 +236,7 @@ export function getAnnotationsFromData(
*/ */
export function shouldUseMappingUI(datasource: DataSourceApi): boolean { export function shouldUseMappingUI(datasource: DataSourceApi): boolean {
const { type } = datasource; const { type } = datasource;
return type !== 'prometheus' && type !== 'elasticsearch'; return type !== 'prometheus' && type !== 'elasticsearch' && type !== 'loki';
} }
/** /**
@ -244,5 +244,5 @@ export function shouldUseMappingUI(datasource: DataSourceApi): boolean {
*/ */
export function shouldUseLegacyRunner(datasource: DataSourceApi): boolean { export function shouldUseLegacyRunner(datasource: DataSourceApi): boolean {
const { type } = datasource; const { type } = datasource;
return type === 'prometheus' || type === 'elasticsearch'; return type === 'prometheus' || type === 'elasticsearch' || type === 'loki';
} }

View File

@ -1,21 +0,0 @@
import { LokiQuery } from './types';
/**
* Just a simple wrapper for a react component that is actually implementing the query editor.
*/
export class LokiAnnotationsQueryCtrl {
static templateUrl = 'partials/annotations.editor.html';
declare annotation: any;
/** @ngInject */
constructor($scope: any) {
this.annotation = $scope.ctrl.annotation;
this.annotation.target = this.annotation.target || {};
this.onQueryChange = this.onQueryChange.bind(this);
}
onQueryChange(query: LokiQuery) {
this.annotation.expr = query.expr;
this.annotation.maxLines = query.maxLines;
this.annotation.instant = query.instant;
}
}

View File

@ -1,49 +1,126 @@
// Libraries // Libraries
import React, { memo } from 'react'; import React, { memo } from 'react';
import { AnnotationQuery } from '@grafana/data';
import { EditorRow, EditorField } from '@grafana/experimental';
import { Input } from '@grafana/ui';
// Types // Types
import { LokiDatasource } from '../datasource'; import { getNormalizedLokiQuery } from '../query_utils';
import { LokiQuery } from '../types'; import { LokiQuery, LokiQueryType } from '../types';
import { LokiOptionFields } from './LokiOptionFields'; import { LokiOptionFields } from './LokiOptionFields';
import { LokiQueryField } from './LokiQueryField'; import { LokiQueryField } from './LokiQueryField';
import { LokiQueryEditorProps } from './types';
interface Props { type Props = LokiQueryEditorProps & {
expr: string; annotation?: AnnotationQuery<LokiQuery>;
maxLines?: number; onAnnotationChange?: (annotation: AnnotationQuery<LokiQuery>) => void;
instant?: boolean; };
datasource: LokiDatasource;
onChange: (query: LokiQuery) => void;
}
export const LokiAnnotationsQueryEditor = memo(function LokiAnnotationQueryEditor(props: Props) { export const LokiAnnotationsQueryEditor = memo(function LokiAnnotationQueryEditor(props: Props) {
const { expr, maxLines, instant, datasource, onChange } = props; const { annotation, onAnnotationChange } = props;
// this should never happen, but we want to keep typescript happy
if (annotation === undefined || onAnnotationChange === undefined) {
return null;
}
const onChangeQuery = (query: LokiQuery) => {
// the current version of annotations only stores an optional boolean
// field `instant` to handle the instant/range switch.
// we need to maintain compatiblity for now, so we do the same.
// we explicitly call `getNormalizedLokiQuery` to make sure `queryType`
// is set up correctly.
const instant = getNormalizedLokiQuery(query).queryType === LokiQueryType.Instant;
onAnnotationChange({
...annotation,
expr: query.expr,
maxLines: query.maxLines,
instant,
});
};
const queryWithRefId: LokiQuery = { const queryWithRefId: LokiQuery = {
refId: '', refId: '',
expr, expr: annotation.expr,
maxLines, maxLines: annotation.maxLines,
instant, instant: annotation.instant,
queryType: annotation.queryType,
}; };
return ( return (
<div className="gf-form-group"> <>
<LokiQueryField <div className="gf-form-group">
datasource={datasource} <LokiQueryField
query={queryWithRefId} datasource={props.datasource}
onChange={onChange} query={queryWithRefId}
onRunQuery={() => {}} onChange={onChangeQuery}
onBlur={() => {}} onRunQuery={() => {}}
history={[]} onBlur={() => {}}
ExtraFieldElement={ history={[]}
<LokiOptionFields ExtraFieldElement={
lineLimitValue={queryWithRefId?.maxLines?.toString() || ''} <LokiOptionFields
resolution={queryWithRefId.resolution || 1} lineLimitValue={queryWithRefId?.maxLines?.toString() || ''}
query={queryWithRefId} resolution={queryWithRefId.resolution || 1}
onRunQuery={() => {}} query={queryWithRefId}
onChange={onChange} onRunQuery={() => {}}
onChange={onChangeQuery}
/>
}
/>
</div>
<EditorRow>
<EditorField
label="Title"
tooltip={
'Use either the name or a pattern. For example, {{instance}} is replaced with label value for the label instance.'
}
>
<Input
type="text"
placeholder="alertname"
value={annotation.titleFormat}
onChange={(event) => {
onAnnotationChange({
...annotation,
titleFormat: event.currentTarget.value,
});
}}
/> />
} </EditorField>
/> <EditorField label="Tags">
</div> <Input
type="text"
placeholder="label1,label2"
value={annotation.tagKeys}
onChange={(event) => {
onAnnotationChange({
...annotation,
tagKeys: event.currentTarget.value,
});
}}
/>
</EditorField>
<EditorField
label="Text"
tooltip={
'Use either the name or a pattern. For example, {{instance}} is replaced with label value for the label instance.'
}
>
<Input
type="text"
placeholder="instance"
value={annotation.textFormat}
onChange={(event) => {
onAnnotationChange({
...annotation,
textFormat: event.currentTarget.value,
});
}}
/>
</EditorField>
</EditorRow>
</>
); );
}); });

View File

@ -47,6 +47,7 @@ import { renderLegendFormat } from '../prometheus/legend';
import { addLabelToQuery } from './add_label_to_query'; import { addLabelToQuery } from './add_label_to_query';
import { transformBackendResult } from './backendResultTransformer'; import { transformBackendResult } from './backendResultTransformer';
import { LokiAnnotationsQueryEditor } from './components/AnnotationsQueryEditor';
import { DEFAULT_RESOLUTION } from './components/LokiOptionFields'; import { DEFAULT_RESOLUTION } from './components/LokiOptionFields';
import LanguageProvider from './language_provider'; import LanguageProvider from './language_provider';
import { escapeLabelValueInSelector } from './language_utils'; import { escapeLabelValueInSelector } from './language_utils';
@ -118,6 +119,9 @@ export class LokiDatasource
const settingsData = instanceSettings.jsonData || {}; const settingsData = instanceSettings.jsonData || {};
this.maxLines = parseInt(settingsData.maxLines ?? '0', 10) || DEFAULT_MAX_LINES; this.maxLines = parseInt(settingsData.maxLines ?? '0', 10) || DEFAULT_MAX_LINES;
this.useBackendMode = config.featureToggles.lokiBackendMode ?? false; this.useBackendMode = config.featureToggles.lokiBackendMode ?? false;
this.annotations = {
QueryEditor: LokiAnnotationsQueryEditor,
};
} }
_request(apiUrl: string, data?: any, options?: Partial<BackendSrvRequest>): Observable<Record<string, any>> { _request(apiUrl: string, data?: any, options?: Partial<BackendSrvRequest>): Observable<Record<string, any>> {

View File

@ -1,6 +1,5 @@
import { DataSourcePlugin } from '@grafana/data'; import { DataSourcePlugin } from '@grafana/data';
import { LokiAnnotationsQueryCtrl } from './LokiAnnotationsQueryCtrl';
import LokiCheatSheet from './components/LokiCheatSheet'; import LokiCheatSheet from './components/LokiCheatSheet';
import LokiQueryEditorByApp from './components/LokiQueryEditorByApp'; import LokiQueryEditorByApp from './components/LokiQueryEditorByApp';
import { ConfigEditor } from './configuration/ConfigEditor'; import { ConfigEditor } from './configuration/ConfigEditor';
@ -9,5 +8,4 @@ import { LokiDatasource } from './datasource';
export const plugin = new DataSourcePlugin(LokiDatasource) export const plugin = new DataSourcePlugin(LokiDatasource)
.setQueryEditor(LokiQueryEditorByApp) .setQueryEditor(LokiQueryEditorByApp)
.setConfigEditor(ConfigEditor) .setConfigEditor(ConfigEditor)
.setQueryEditorHelp(LokiCheatSheet) .setQueryEditorHelp(LokiCheatSheet);
.setAnnotationQueryCtrl(LokiAnnotationsQueryCtrl);

View File

@ -1,28 +0,0 @@
<loki-annotations-query-editor
expr="ctrl.annotation.expr"
max-lines="ctrl.annotation.maxLines"
instant="ctrl.annotation.instant"
on-change="ctrl.onQueryChange"
datasource="ctrl.datasource"
>
</loki-annotations-query-editor>
<div class="gf-form-group">
<h5 class="section-heading">Field formats<tip>For title and text fields, use either the name or a pattern. For example, {{instance}} is replaced with label value for the label instance.</tip></h5>
<div class="gf-form-inline">
<div class="gf-form">
<span class="gf-form-label width-5">Title</span>
<input type="text" class="gf-form-input max-width-9" ng-model='ctrl.annotation.titleFormat' placeholder="alertname"></input>
</div>
<div class="gf-form">
<span class="gf-form-label width-5">Tags</span>
<input type="text" class="gf-form-input max-width-9" ng-model='ctrl.annotation.tagKeys' placeholder="label1,label2"></input>
</div>
<div class="gf-form-inline">
<div class="gf-form">
<span class="gf-form-label width-5">Text</span>
<input type="text" class="gf-form-input max-width-9" ng-model='ctrl.annotation.textFormat' placeholder="instance"></input>
</div>
</div>
</div>
</div>