diff --git a/public/app/plugins/datasource/loki/components/LokiContextUi.tsx b/public/app/plugins/datasource/loki/components/LokiContextUi.tsx index 76a0068ad07..859a715845d 100644 --- a/public/app/plugins/datasource/loki/components/LokiContextUi.tsx +++ b/public/app/plugins/datasource/loki/components/LokiContextUi.tsx @@ -5,7 +5,7 @@ import { useAsync } from 'react-use'; import { GrafanaTheme2, LogRowModel, SelectableValue } from '@grafana/data'; import { reportInteraction } from '@grafana/runtime'; -import { MultiSelect, Tag, Tooltip, useStyles2 } from '@grafana/ui'; +import { LoadingPlaceholder, MultiSelect, Tag, Tooltip, useStyles2 } from '@grafana/ui'; import LokiLanguageProvider from '../LanguageProvider'; import { ContextFilter } from '../types'; @@ -35,6 +35,19 @@ function getStyles(theme: GrafanaTheme2) { overscroll-behavior: contain; } `, + loadingPlaceholder: css` + margin-bottom: 0px; + float: right; + display: inline; + margin-left: auto; + `, + textWrapper: css` + display: flex; + align-items: center; + `, + hidden: css` + visibility: hidden; + `, }; } @@ -51,6 +64,7 @@ export function LokiContextUi(props: LokiContextUiProps) { const [contextFilters, setContextFilters] = useState([]); const [initialized, setInitialized] = useState(false); + const [loading, setLoading] = useState(false); const timerHandle = React.useRef(); const previousInitialized = React.useRef(false); const previousContextFilters = React.useRef([]); @@ -75,8 +89,10 @@ export function LokiContextUi(props: LokiContextUiProps) { if (timerHandle.current) { clearTimeout(timerHandle.current); } + setLoading(true); timerHandle.current = window.setTimeout(() => { updateFilter(contextFilters); + setLoading(false); }, 1500); return () => { @@ -134,7 +150,7 @@ export function LokiContextUi(props: LokiContextUiProps) { return (
-
+
{' '} {' '} Select labels to be included in the context query: +
void) | undefined; constructor( private instanceSettings: DataSourceInstanceSettings, @@ -789,53 +790,60 @@ export class LokiDatasource } getLogRowContextUi(row: LogRowModel, runContextQuery: () => void): React.ReactNode { - return LokiContextUi({ - row, - languageProvider: this.languageProvider, - onClose: () => { - this.prepareContextExpr = this.prepareContextExprWithoutParsedLabels; - }, - updateFilter: (contextFilters: ContextFilter[]) => { - this.prepareContextExpr = async (row: LogRowModel, origQuery?: DataQuery) => { - await this.languageProvider.start(); - const labels = this.languageProvider.getLabelKeys(); + const updateFilter = (contextFilters: ContextFilter[]) => { + this.prepareContextExpr = async (row: LogRowModel, origQuery?: DataQuery) => { + await this.languageProvider.start(); + const labels = this.languageProvider.getLabelKeys(); - let expr = contextFilters - .map((filter) => { - const label = filter.value; - if (filter && !filter.fromParser && filter.enabled && labels.includes(label)) { - // escape backslashes in label as users can't escape them by themselves - return `${label}="${escapeLabelValueInExactSelector(row.labels[label])}"`; - } - return ''; - }) - // Filter empty strings - .filter((label) => !!label) - .join(','); - - expr = `{${expr}}`; - - const parserContextFilters = contextFilters.filter((filter) => filter.fromParser && filter.enabled); - if (parserContextFilters.length) { - // we should also filter for labels from parsers, let's find the right parser - if (origQuery) { - const parser = getParserFromQuery((origQuery as LokiQuery).expr); - if (parser) { - expr = addParserToQuery(expr, parser); - } + let expr = contextFilters + .map((filter) => { + const label = filter.value; + if (filter && !filter.fromParser && filter.enabled && labels.includes(label)) { + // escape backslashes in label as users can't escape them by themselves + return `${label}="${escapeLabelValueInExactSelector(row.labels[label])}"`; } - for (const filter of parserContextFilters) { - if (filter.enabled) { - expr = addLabelToQuery(expr, filter.label, '=', row.labels[filter.label]); - } + return ''; + }) + // Filter empty strings + .filter((label) => !!label) + .join(','); + + expr = `{${expr}}`; + + const parserContextFilters = contextFilters.filter((filter) => filter.fromParser && filter.enabled); + if (parserContextFilters.length) { + // we should also filter for labels from parsers, let's find the right parser + if (origQuery) { + const parser = getParserFromQuery((origQuery as LokiQuery).expr); + if (parser) { + expr = addParserToQuery(expr, parser); + } + } + for (const filter of parserContextFilters) { + if (filter.enabled) { + expr = addLabelToQuery(expr, filter.label, '=', row.labels[filter.label]); } } - return expr; - }; - if (runContextQuery) { - runContextQuery(); } - }, + return expr; + }; + if (runContextQuery) { + runContextQuery(); + } + }; + + // we need to cache this function so that it doesn't get recreated on every render + this.onContextClose = + this.onContextClose ?? + (() => { + this.prepareContextExpr = this.prepareContextExprWithoutParsedLabels; + }); + + return LokiContextUi({ + row, + updateFilter, + languageProvider: this.languageProvider, + onClose: this.onContextClose, }); }