LokiContextUi: Add loading indicator (#64167)

add loading indicator to LokiContextUi
This commit is contained in:
Sven Grossmann
2023-03-06 17:25:04 +01:00
committed by GitHub
parent 66ef5325d1
commit 5db0d14606
2 changed files with 69 additions and 44 deletions

View File

@@ -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<ContextFilter[]>([]);
const [initialized, setInitialized] = useState(false);
const [loading, setLoading] = useState(false);
const timerHandle = React.useRef<number>();
const previousInitialized = React.useRef<boolean>(false);
const previousContextFilters = React.useRef<ContextFilter[]>([]);
@@ -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 (
<div className={styles.multiSelectWrapper}>
<div>
<div className={styles.textWrapper}>
{' '}
<Tooltip
content={
@@ -153,6 +169,7 @@ export function LokiContextUi(props: LokiContextUiProps) {
/>
</Tooltip>{' '}
Select labels to be included in the context query:
<LoadingPlaceholder text="" className={`${styles.loadingPlaceholder} ${loading ? '' : styles.hidden}`} />
</div>
<div>
<MultiSelect

View File

@@ -137,6 +137,7 @@ export class LokiDatasource
private streams = new LiveStreams();
languageProvider: LanguageProvider;
maxLines: number;
onContextClose: (() => void) | undefined;
constructor(
private instanceSettings: DataSourceInstanceSettings<LokiOptions>,
@@ -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,
});
}