Commit f7950491 by Dominik Prokop Committed by GitHub

Field overrides: Overrides UI improvements (#27073)

* Add filter name by regex matcher for overrides

* Update docs

* Introduce UI improvements to overrides list

* Update public/app/features/dashboard/components/PanelEditor/OverrideEditor.tsx

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>

* Review improvements

* Fix merge

* Remove ellipsis

Co-authored-by: kay delaney <45561153+kaydelaney@users.noreply.github.com>
parent 954a2811
...@@ -99,7 +99,6 @@ Allows you to type in a regular expression against which fields to be overridden ...@@ -99,7 +99,6 @@ Allows you to type in a regular expression against which fields to be overridden
Allows you to select fields by their type (string, numeric, etc). Allows you to select fields by their type (string, numeric, etc).
## Field options ## Field options
This section explains all available field options. They are listed in alphabetical order. This section explains all available field options. They are listed in alphabetical order.
......
...@@ -22,4 +22,5 @@ export const fieldNameByRegexMatcherItem: FieldMatcherUIRegistryItem<string> = { ...@@ -22,4 +22,5 @@ export const fieldNameByRegexMatcherItem: FieldMatcherUIRegistryItem<string> = {
matcher: fieldMatchers.get(FieldMatcherID.byRegexp), matcher: fieldMatchers.get(FieldMatcherID.byRegexp),
name: 'Filter by field using regex', name: 'Filter by field using regex',
description: 'Set properties for fields with names matching provided regex', description: 'Set properties for fields with names matching provided regex',
optionsToLabel: options => options,
}; };
...@@ -28,6 +28,7 @@ export const fieldNameMatcherItem: FieldMatcherUIRegistryItem<string> = { ...@@ -28,6 +28,7 @@ export const fieldNameMatcherItem: FieldMatcherUIRegistryItem<string> = {
matcher: fieldMatchers.get(FieldMatcherID.byName), matcher: fieldMatchers.get(FieldMatcherID.byName),
name: 'Filter by field', name: 'Filter by field',
description: 'Set properties for fields matching the name', description: 'Set properties for fields matching the name',
optionsToLabel: options => options,
}; };
const useFieldDisplayNames = (data: DataFrame[]): Set<string> => { const useFieldDisplayNames = (data: DataFrame[]): Set<string> => {
......
...@@ -81,4 +81,5 @@ export const fieldTypeMatcherItem: FieldMatcherUIRegistryItem<string> = { ...@@ -81,4 +81,5 @@ export const fieldTypeMatcherItem: FieldMatcherUIRegistryItem<string> = {
matcher: fieldMatchers.get(FieldMatcherID.byType), matcher: fieldMatchers.get(FieldMatcherID.byType),
name: 'Filter by type', name: 'Filter by type',
description: 'Set properties for fields matching a type', description: 'Set properties for fields matching a type',
optionsToLabel: options => options,
}; };
import { Registry } from '@grafana/data'; import { Registry } from '@grafana/data';
import { fieldNameMatcherItem } from './FieldNameMatcherEditor';
import { FieldMatcherUIRegistryItem } from './types'; import { FieldMatcherUIRegistryItem } from './types';
import { fieldNameMatcherItem } from './FieldNameMatcherEditor';
import { fieldNameByRegexMatcherItem } from './FieldNameByRegexMatcherEditor'; import { fieldNameByRegexMatcherItem } from './FieldNameByRegexMatcherEditor';
import { fieldTypeMatcherItem } from './FieldTypeMatcherEditor'; import { fieldTypeMatcherItem } from './FieldTypeMatcherEditor';
......
...@@ -4,6 +4,8 @@ import { DataFrame, RegistryItem, FieldMatcherInfo } from '@grafana/data'; ...@@ -4,6 +4,8 @@ import { DataFrame, RegistryItem, FieldMatcherInfo } from '@grafana/data';
export interface FieldMatcherUIRegistryItem<TOptions> extends RegistryItem { export interface FieldMatcherUIRegistryItem<TOptions> extends RegistryItem {
component: React.ComponentType<MatcherUIProps<TOptions>>; component: React.ComponentType<MatcherUIProps<TOptions>>;
matcher: FieldMatcherInfo<TOptions>; matcher: FieldMatcherInfo<TOptions>;
/* Maps matcher options to human-readable label */
optionsToLabel: (options: TOptions) => string;
} }
export interface MatcherUIProps<T> { export interface MatcherUIProps<T> {
......
...@@ -76,7 +76,7 @@ export const OverrideFieldConfigEditor: React.FC<Props> = props => { ...@@ -76,7 +76,7 @@ export const OverrideFieldConfigEditor: React.FC<Props> = props => {
// TODO: apply matcher to retrieve fields // TODO: apply matcher to retrieve fields
return ( return (
<OverrideEditor <OverrideEditor
name={`Override ${i + 1}`} name={`${fieldMatchersUI.get(o.matcher.id).name}`}
key={`${o.matcher.id}/${i}`} key={`${o.matcher.id}/${i}`}
data={data} data={data}
override={o} override={o}
......
...@@ -108,7 +108,7 @@ const CollapsibleSection: FC<Omit<OptionsGroupProps, 'persistMe'>> = ({ ...@@ -108,7 +108,7 @@ const CollapsibleSection: FC<Omit<OptionsGroupProps, 'persistMe'>> = ({
<div className={cx(styles.toggle, 'editor-options-group-toggle')}> <div className={cx(styles.toggle, 'editor-options-group-toggle')}>
<Icon name={isExpanded ? 'angle-down' : 'angle-right'} /> <Icon name={isExpanded ? 'angle-down' : 'angle-right'} />
</div> </div>
<div style={{ width: '100%' }}>{renderTitle ? renderTitle(isExpanded) : title}</div> <div className={styles.title}>{renderTitle ? renderTitle(isExpanded) : title}</div>
</div> </div>
{isExpanded && <div className={styles.body}>{_.isFunction(children) ? children(toggleExpand) : children}</div>} {isExpanded && <div className={styles.body}>{_.isFunction(children) ? children(toggleExpand) : children}</div>}
</div> </div>
...@@ -130,9 +130,12 @@ const getStyles = stylesFactory((theme: GrafanaTheme, isExpanded: boolean, isNes ...@@ -130,9 +130,12 @@ const getStyles = stylesFactory((theme: GrafanaTheme, isExpanded: boolean, isNes
), ),
toggle: css` toggle: css`
color: ${theme.colors.textWeak}; color: ${theme.colors.textWeak};
font-size: ${theme.typography.size.lg};
margin-right: ${theme.spacing.sm}; margin-right: ${theme.spacing.sm};
`, `,
title: css`
flex-grow: 1;
overflow: hidden;
`,
header: cx( header: cx(
css` css`
display: flex; display: flex;
......
...@@ -110,6 +110,8 @@ export const OverrideEditor: React.FC<OverrideEditorProps> = ({ ...@@ -110,6 +110,8 @@ export const OverrideEditor: React.FC<OverrideEditorProps> = ({
}); });
const renderOverrideTitle = (isExpanded: boolean) => { const renderOverrideTitle = (isExpanded: boolean) => {
const overriddenProperites = override.properties.map(p => registry.get(p.id).name).join(', ');
const matcherOptions = matcherUi.optionsToLabel(override.matcher.options);
return ( return (
<div> <div>
<HorizontalGroup justify="space-between"> <HorizontalGroup justify="space-between">
...@@ -118,8 +120,13 @@ export const OverrideEditor: React.FC<OverrideEditorProps> = ({ ...@@ -118,8 +120,13 @@ export const OverrideEditor: React.FC<OverrideEditorProps> = ({
</HorizontalGroup> </HorizontalGroup>
{!isExpanded && ( {!isExpanded && (
<div className={styles.overrideDetails}> <div className={styles.overrideDetails}>
Matcher <Icon name="angle-right" /> {matcherUi.name} <br /> <div className={styles.options} title={matcherOptions}>
{override.properties.length === 0 ? 'No' : override.properties.length} properties overriden Options <Icon name="angle-right" /> {matcherOptions}
</div>
<div className={styles.options} title={overriddenProperites}>
Properties overridden <Icon name="angle-right" />
{overriddenProperites}
</div>
</div> </div>
)} )}
</div> </div>
...@@ -137,7 +144,7 @@ export const OverrideEditor: React.FC<OverrideEditorProps> = ({ ...@@ -137,7 +144,7 @@ export const OverrideEditor: React.FC<OverrideEditorProps> = ({
/> />
</Field> </Field>
<div> <>
{override.properties.map((p, j) => { {override.properties.map((p, j) => {
const item = registry.getIfExists(p.id); const item = registry.getIfExists(p.id);
...@@ -176,7 +183,7 @@ export const OverrideEditor: React.FC<OverrideEditorProps> = ({ ...@@ -176,7 +183,7 @@ export const OverrideEditor: React.FC<OverrideEditorProps> = ({
/> />
</div> </div>
)} )}
</div> </>
</OptionsGroup> </OptionsGroup>
); );
}; };
...@@ -194,5 +201,9 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => { ...@@ -194,5 +201,9 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
color: ${theme.colors.textWeak}; color: ${theme.colors.textWeak};
font-weight: ${theme.typography.weight.regular}; font-weight: ${theme.typography.weight.regular};
`, `,
options: css`
overflow: hidden;
padding-right: ${theme.spacing.xl};
`,
}; };
}); });
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment