mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
PanelEdit: Highlight matched words when searching options (#33717)
This commit is contained in:
@@ -37,7 +37,7 @@ export class OptionsPaneCategoryDescriptor {
|
||||
return this;
|
||||
}
|
||||
|
||||
render(isSearching?: boolean) {
|
||||
render(searchQuery?: string) {
|
||||
if (this.props.customRender) {
|
||||
return this.props.customRender();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { Field, Label } from '@grafana/ui';
|
||||
import React, { ReactNode } from 'react';
|
||||
import Highlighter from 'react-highlight-words';
|
||||
import { OptionsPaneCategoryDescriptor } from './OptionsPaneCategoryDescriptor';
|
||||
|
||||
export interface OptionsPaneItemProps {
|
||||
@@ -21,10 +22,10 @@ export class OptionsPaneItemDescriptor {
|
||||
|
||||
constructor(public props: OptionsPaneItemProps) {}
|
||||
|
||||
getLabel(isSearching?: boolean): ReactNode {
|
||||
getLabel(searchQuery?: string): ReactNode {
|
||||
const { title, description } = this.props;
|
||||
|
||||
if (!isSearching) {
|
||||
if (!searchQuery) {
|
||||
// Do not render label for categories with only one child
|
||||
if (this.parent.props.title === title) {
|
||||
return null;
|
||||
@@ -33,24 +34,30 @@ export class OptionsPaneItemDescriptor {
|
||||
return title;
|
||||
}
|
||||
|
||||
const categories: string[] = [];
|
||||
const categories: React.ReactNode[] = [];
|
||||
|
||||
if (this.parent.parent) {
|
||||
categories.push(this.parent.parent.props.title);
|
||||
categories.push(this.highlightWord(this.parent.parent.props.title, searchQuery));
|
||||
}
|
||||
|
||||
if (this.parent.props.title !== title) {
|
||||
categories.push(this.parent.props.title);
|
||||
categories.push(this.highlightWord(this.parent.props.title, searchQuery));
|
||||
}
|
||||
|
||||
return (
|
||||
<Label description={description} category={categories}>
|
||||
{title}
|
||||
<Label description={description && this.highlightWord(description, searchQuery)} category={categories}>
|
||||
{this.highlightWord(title, searchQuery)}
|
||||
</Label>
|
||||
);
|
||||
}
|
||||
|
||||
render(isSearching?: boolean) {
|
||||
highlightWord(word: string, query: string) {
|
||||
return (
|
||||
<Highlighter textToHighlight={word} searchWords={[query]} highlightClassName={'search-fragment-highlight'} />
|
||||
);
|
||||
}
|
||||
|
||||
render(searchQuery?: string) {
|
||||
const { title, description, render, showIf, skipField } = this.props;
|
||||
const key = `${this.parent.props.id} ${title}`;
|
||||
|
||||
@@ -64,7 +71,7 @@ export class OptionsPaneItemDescriptor {
|
||||
|
||||
return (
|
||||
<Field
|
||||
label={this.getLabel(isSearching)}
|
||||
label={this.getLabel(searchQuery)}
|
||||
description={description}
|
||||
key={key}
|
||||
aria-label={selectors.components.PanelEditor.OptionsPane.fieldLabel(key)}
|
||||
|
||||
@@ -139,9 +139,9 @@ function renderSearchHits(
|
||||
key="Normal options"
|
||||
forceOpen={1}
|
||||
>
|
||||
{optionHits.map((hit) => hit.render(true))}
|
||||
{optionHits.map((hit) => hit.render(searchQuery))}
|
||||
</OptionsPaneCategory>
|
||||
{overrideHits.map((override) => override.render(true))}
|
||||
{overrideHits.map((override) => override.render(searchQuery))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -152,6 +152,11 @@ const getStyles = (theme: GrafanaTheme2) => ({
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1 1 0;
|
||||
|
||||
.search-fragment-highlight {
|
||||
color: ${theme.colors.warning.text};
|
||||
background: transparent;
|
||||
}
|
||||
`,
|
||||
searchBox: css`
|
||||
display: flex;
|
||||
|
||||
Reference in New Issue
Block a user