Refactor: Decouple Label Browser from LocalStorage (#40449)

* Refactor: Decouple Label Browser from LocalStorage

* Clean up
This commit is contained in:
Piotr Jamróz
2021-10-15 14:18:11 +02:00
committed by GitHub
parent 7140867868
commit 6dc21d5899
7 changed files with 154 additions and 109 deletions

View File

@@ -3,8 +3,8 @@ import store from '../../store';
export interface Props<T> {
storageKey: string;
defaultValue?: T;
children: (value: T, onSaveToStore: (value: T) => void) => React.ReactNode;
defaultValue: T;
children: (value: T, onSaveToStore: (value: T) => void, onDeleteFromStore: () => void) => React.ReactNode;
}
interface State<T> {
@@ -32,10 +32,20 @@ export class LocalStorageValueProvider<T> extends PureComponent<Props<T>, State<
this.setState({ value });
};
onDeleteFromStore = () => {
const { storageKey, defaultValue } = this.props;
try {
store.delete(storageKey);
} catch (error) {
console.log(error);
}
this.setState({ value: defaultValue });
};
render() {
const { children } = this.props;
const { value } = this.state;
return <>{children(value, this.onSaveToStore)}</>;
return <>{children(value, this.onSaveToStore, this.onDeleteFromStore)}</>;
}
}

View File

@@ -109,6 +109,9 @@ describe('LokiLabelBrowser', () => {
onChange: () => {},
autoSelect: 0,
languageProvider: (mockLanguageProvider as unknown) as LokiLanguageProvider,
lastUsedLabels: [],
storeLastUsedLabels: () => {},
deleteLastUsedLabels: () => {},
};
return defaults;

View File

@@ -13,7 +13,6 @@ import {
import LokiLanguageProvider from '../language_provider';
import PromQlLanguageProvider from '../../prometheus/language_provider';
import { css, cx } from '@emotion/css';
import store from 'app/core/store';
import { FixedSizeList } from 'react-window';
import { GrafanaTheme2 } from '@grafana/data';
import { sortBy } from 'lodash';
@@ -24,8 +23,6 @@ const MAX_VALUE_COUNT = 10000;
const MAX_AUTO_SELECT = 4;
const EMPTY_SELECTOR = '{}';
export const LAST_USED_LABELS_KEY = 'grafana.datasources.loki.browser.labels';
export interface BrowserProps {
// TODO #33976: Is it possible to use a common interface here? For example: LabelsLanguageProvider
languageProvider: LokiLanguageProvider | PromQlLanguageProvider;
@@ -33,6 +30,9 @@ export interface BrowserProps {
theme: GrafanaTheme2;
autoSelect?: number;
hide?: () => void;
lastUsedLabels: string[];
storeLastUsedLabels: (labels: string[]) => void;
deleteLastUsedLabels: () => void;
}
interface BrowserState {
@@ -208,7 +208,7 @@ export class UnthemedLokiLabelBrowser extends React.Component<BrowserProps, Brow
}));
return { labels, searchTerm: '', status: '', error: '', validationStatus: '' };
});
store.delete(LAST_USED_LABELS_KEY);
this.props.deleteLastUsedLabels();
};
onClickLabel = (name: string, value: string | undefined, event: React.MouseEvent<HTMLElement>) => {
@@ -261,9 +261,9 @@ export class UnthemedLokiLabelBrowser extends React.Component<BrowserProps, Brow
}
componentDidMount() {
const { languageProvider, autoSelect = MAX_AUTO_SELECT } = this.props;
const { languageProvider, autoSelect = MAX_AUTO_SELECT, lastUsedLabels } = this.props;
if (languageProvider) {
const selectedLabels: string[] = store.getObject(LAST_USED_LABELS_KEY, []);
const selectedLabels: string[] = lastUsedLabels;
languageProvider.start().then(() => {
let rawLabels: string[] = languageProvider.getLabelKeys();
if (rawLabels.length > MAX_LABEL_COUNT) {
@@ -295,7 +295,7 @@ export class UnthemedLokiLabelBrowser extends React.Component<BrowserProps, Brow
return;
}
const selectedLabels = this.state.labels.filter((label) => label.selected).map((label) => label.name);
store.setObject(LAST_USED_LABELS_KEY, selectedLabels);
this.props.storeLastUsedLabels(selectedLabels);
if (label.selected) {
// Refetch values for newly selected label...
if (!label.values) {

View File

@@ -17,6 +17,9 @@ import { LanguageMap, languages as prismLanguages } from 'prismjs';
import LokiLanguageProvider from '../language_provider';
import { shouldRefreshLabels } from '../language_utils';
import LokiDatasource from '../datasource';
import { LocalStorageValueProvider } from 'app/core/components/LocalStorageValueProvider';
const LAST_USED_LABELS_KEY = 'grafana.datasources.loki.browser.labels';
function getChooserText(hasSyntax: boolean, hasLogLabels: boolean) {
if (!hasSyntax) {
@@ -158,6 +161,9 @@ export class LokiQueryField extends React.PureComponent<LokiQueryFieldProps, Lok
const chooserText = getChooserText(labelsLoaded, hasLogLabels);
const buttonDisabled = !(labelsLoaded && hasLogLabels);
return (
<LocalStorageValueProvider<string[]> storageKey={LAST_USED_LABELS_KEY} defaultValue={[]}>
{(lastUsedLabels, onLastUsedLabelsSave, onLastUsedLabelsDelete) => {
return (
<>
<div
@@ -189,12 +195,21 @@ export class LokiQueryField extends React.PureComponent<LokiQueryFieldProps, Lok
</div>
{labelBrowserVisible && (
<div className="gf-form">
<LokiLabelBrowser languageProvider={lokiLanguageProvider} onChange={this.onChangeLabelBrowser} />
<LokiLabelBrowser
languageProvider={lokiLanguageProvider}
onChange={this.onChangeLabelBrowser}
lastUsedLabels={lastUsedLabels || []}
storeLastUsedLabels={onLastUsedLabelsSave}
deleteLastUsedLabels={onLastUsedLabelsDelete}
/>
</div>
)}
{ExtraFieldElement}
</>
);
}}
</LocalStorageValueProvider>
);
}
}

View File

@@ -23,8 +23,10 @@ import { QueryEditorProps, QueryHint, isDataFrame, toLegacyResponseData, TimeRan
import { PrometheusDatasource } from '../datasource';
import { PrometheusMetricsBrowser } from './PrometheusMetricsBrowser';
import { MonacoQueryFieldLazy } from './monaco-query-field/MonacoQueryFieldLazy';
import { LocalStorageValueProvider } from 'app/core/components/LocalStorageValueProvider';
export const RECORDING_RULES_GROUP = '__recording_rules__';
const LAST_USED_LABELS_KEY = 'grafana.datasources.prometheus.browser.labels';
function getChooserText(metricsLookupDisabled: boolean, hasSyntax: boolean, hasMetrics: boolean) {
if (metricsLookupDisabled) {
@@ -276,6 +278,9 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
const isMonacoEditorEnabled = config.featureToggles.prometheusMonaco;
return (
<LocalStorageValueProvider<string[]> storageKey={LAST_USED_LABELS_KEY} defaultValue={[]}>
{(lastUsedLabels, onLastUsedLabelsSave, onLastUsedLabelsDelete) => {
return (
<>
<div
@@ -319,7 +324,13 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
</div>
{labelBrowserVisible && (
<div className="gf-form">
<PrometheusMetricsBrowser languageProvider={languageProvider} onChange={this.onChangeLabelBrowser} />
<PrometheusMetricsBrowser
languageProvider={languageProvider}
onChange={this.onChangeLabelBrowser}
lastUsedLabels={lastUsedLabels || []}
storeLastUsedLabels={onLastUsedLabelsSave}
deleteLastUsedLabels={onLastUsedLabelsDelete}
/>
</div>
)}
@@ -338,6 +349,9 @@ class PromQueryField extends React.PureComponent<PromQueryFieldProps, PromQueryF
) : null}
</>
);
}}
</LocalStorageValueProvider>
);
}
}

View File

@@ -133,6 +133,9 @@ describe('PrometheusMetricsBrowser', () => {
onChange: () => {},
autoSelect: 0,
languageProvider: (mockLanguageProvider as unknown) as PromQlLanguageProvider,
lastUsedLabels: [],
storeLastUsedLabels: () => {},
deleteLastUsedLabels: () => {},
};
return defaults;

View File

@@ -12,7 +12,6 @@ import {
import PromQlLanguageProvider from '../language_provider';
import { escapeLabelValueInExactSelector, escapeLabelValueInRegexSelector } from '../language_utils';
import { css, cx } from '@emotion/css';
import store from 'app/core/store';
import { FixedSizeList } from 'react-window';
import { GrafanaTheme } from '@grafana/data';
@@ -24,14 +23,15 @@ const EMPTY_SELECTOR = '{}';
const METRIC_LABEL = '__name__';
const LIST_ITEM_SIZE = 25;
export const LAST_USED_LABELS_KEY = 'grafana.datasources.prometheus.browser.labels';
export interface BrowserProps {
languageProvider: PromQlLanguageProvider;
onChange: (selector: string) => void;
theme: GrafanaTheme;
autoSelect?: number;
hide?: () => void;
lastUsedLabels: string[];
storeLastUsedLabels: (labels: string[]) => void;
deleteLastUsedLabels: () => void;
}
interface BrowserState {
@@ -243,7 +243,7 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component<BrowserPro
valueSearchTerm: '',
};
});
store.delete(LAST_USED_LABELS_KEY);
this.props.deleteLastUsedLabels();
// Get metrics
this.fetchValues(METRIC_LABEL, EMPTY_SELECTOR);
};
@@ -316,9 +316,9 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component<BrowserPro
}
componentDidMount() {
const { languageProvider } = this.props;
const { languageProvider, lastUsedLabels } = this.props;
if (languageProvider) {
const selectedLabels: string[] = store.getObject(LAST_USED_LABELS_KEY, []);
const selectedLabels: string[] = lastUsedLabels;
languageProvider.start().then(() => {
let rawLabels: string[] = languageProvider.getLabelKeys();
// TODO too-many-metrics
@@ -353,7 +353,7 @@ export class UnthemedPrometheusMetricsBrowser extends React.Component<BrowserPro
return;
}
const selectedLabels = this.state.labels.filter((label) => label.selected).map((label) => label.name);
store.setObject(LAST_USED_LABELS_KEY, selectedLabels);
this.props.storeLastUsedLabels(selectedLabels);
if (label.selected) {
// Refetch values for newly selected label...
if (!label.values) {