Overrides: Show option group counters for options that represent collections (#23655)

This commit is contained in:
Dominik Prokop 2020-04-18 14:05:38 +02:00 committed by GitHub
parent 4e521a84b4
commit 539edba31b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 67 additions and 9 deletions

View File

@ -41,6 +41,11 @@ export interface OptionsEditorItem<TOptions, TSettings, TEditorProps, TValue> ex
* @param currentConfig Current options values
*/
showIf?: (currentConfig: TOptions) => boolean;
/**
* Function that returns number of items if given option represents a collection, i.e. array of items.
* @param value
*/
getItemsCount?: (value?: TValue) => number;
}
/**

View File

@ -143,6 +143,7 @@ export const getStandardFieldConfigs = () => {
},
shouldApply: field => field.type === FieldType.number,
category: ['Color & thresholds'],
getItemsCount: value => (value ? value.steps.length : 0),
};
const mappings: FieldConfigPropertyItem<any, ValueMapping[], ValueMappingFieldConfigSettings> = {
@ -158,6 +159,7 @@ export const getStandardFieldConfigs = () => {
defaultValue: [],
shouldApply: field => field.type === FieldType.number,
category: ['Value mappings'],
getItemsCount: (value?) => (value ? value.length : 0),
};
const noValue: FieldConfigPropertyItem<any, string, StringFieldConfigSettings> = {
@ -191,6 +193,7 @@ export const getStandardFieldConfigs = () => {
},
shouldApply: () => true,
category: ['Data links'],
getItemsCount: value => (value ? value.length : 0),
};
const color: FieldConfigPropertyItem<any, string, StringFieldConfigSettings> = {

View File

@ -1,8 +1,9 @@
import { DynamicConfigValue, FieldConfigOptionsRegistry, FieldOverrideContext, GrafanaTheme } from '@grafana/data';
import React from 'react';
import { Field, HorizontalGroup, IconButton, IconName, Label, stylesFactory, useTheme } from '@grafana/ui';
import { Field, HorizontalGroup, IconButton, Label, stylesFactory, useTheme } from '@grafana/ui';
import { css, cx } from 'emotion';
import { OptionsGroup } from './OptionsGroup';
import { Counter } from '@grafana/ui/src/components/Tabs/Counter';
interface DynamicConfigValueEditorProps {
property: DynamicConfigValue;
registry: FieldConfigOptionsRegistry;
@ -28,11 +29,15 @@ export const DynamicConfigValueEditor: React.FC<DynamicConfigValueEditorProps> =
return null;
}
let editor;
const renderLabel = (iconName: IconName, includeDescription = true) => () => (
const renderLabel = (includeDescription = true, includeCounter = false) => (isExpanded = false) => (
<HorizontalGroup justify="space-between">
<Label description={includeDescription ? item.description : undefined}>{item.name}</Label>
<Label description={includeDescription ? item.description : undefined}>
{item.name}
{!isExpanded && includeCounter && item.getItemsCount && <Counter value={item.getItemsCount(property.value)} />}
</Label>
<div>
<IconButton name={iconName} onClick={onRemove} />
<IconButton name="times" onClick={onRemove} />
</div>
</HorizontalGroup>
);
@ -40,7 +45,7 @@ export const DynamicConfigValueEditor: React.FC<DynamicConfigValueEditorProps> =
if (isCollapsible) {
editor = (
<OptionsGroup
renderTitle={renderLabel('trash-alt', false)}
renderTitle={renderLabel(false, true)}
className={css`
padding-left: 0;
padding-right: 0;
@ -61,7 +66,7 @@ export const DynamicConfigValueEditor: React.FC<DynamicConfigValueEditorProps> =
} else {
editor = (
<div>
<Field label={renderLabel('times')()} description={item.description}>
<Field label={renderLabel()()} description={item.description}>
<item.override
value={property.value}
onChange={value => {

View File

@ -13,6 +13,7 @@ import { getDataLinksVariableSuggestions } from '../../../panel/panellinks/link_
import { OverrideEditor } from './OverrideEditor';
import groupBy from 'lodash/groupBy';
import { OptionsGroup } from './OptionsGroup';
import { Counter } from '@grafana/ui/src/components/Tabs/Counter';
interface Props {
plugin: PanelPlugin;
@ -180,8 +181,19 @@ export const DefaultFieldConfigEditor: React.FC<Props> = ({ data, onChange, conf
return (
<>
{Object.keys(groupedConfigs).map((k, i) => {
const groupItemsCounter = countGroupItems(groupedConfigs[k], config);
return (
<OptionsGroup title={k} key={`${k}/${i}`}>
<OptionsGroup
renderTitle={isExpanded => {
return (
<>
{k} {!isExpanded && groupItemsCounter && <Counter value={groupItemsCounter} />}
</>
);
}}
key={`${k}/${i}`}
>
<>
{groupedConfigs[k].map(c => {
return renderEditor(c);
@ -193,3 +205,20 @@ export const DefaultFieldConfigEditor: React.FC<Props> = ({ data, onChange, conf
</>
);
};
const countGroupItems = (group: FieldConfigPropertyItem[], config: FieldConfigSource) => {
let counter = 0;
for (const item of group) {
const value = item.isCustom
? config.defaults.custom
? config.defaults.custom[item.path]
: undefined
: (config.defaults as any)[item.path];
if (item.getItemsCount && item.getItemsCount(value) > 0) {
counter = counter + item.getItemsCount(value);
}
}
return counter === 0 ? undefined : counter;
};

View File

@ -91,6 +91,7 @@ export const OptionsPaneContent: React.FC<{
onClose={onClose}
setSearchMode={setSearchMode}
setActiveTab={setActiveTab}
panel={panel}
/>
</TabsBar>
<TabContent className={styles.tabContent}>
@ -128,7 +129,11 @@ export const TabsBarContent: React.FC<{
onClose: () => void;
setSearchMode: (mode: boolean) => void;
setActiveTab: (tab: string) => void;
}> = ({ width, showFields, isSearching, activeTab, onClose, setSearchMode, setActiveTab, styles }) => {
panel: PanelModel;
}> = ({ width, showFields, isSearching, activeTab, onClose, setSearchMode, setActiveTab, styles, panel }) => {
const overridesCount =
panel.getFieldConfig().overrides.length === 0 ? undefined : panel.getFieldConfig().overrides.length;
if (isSearching) {
const defaultStyles = {
transition: 'width 50ms ease-in-out',
@ -190,6 +195,7 @@ export const TabsBarContent: React.FC<{
<Tab
key={item.value}
label={item.label}
counter={item.value === 'overrides' ? overridesCount : undefined}
active={active.value === item.value}
onChangeTab={() => setActiveTab(item.value)}
/>

View File

@ -7,6 +7,7 @@ import { getPanelLinksVariableSuggestions } from '../../../panel/panellinks/link
import { getVariables } from '../../../variables/state/selectors';
import { PanelOptionsEditor } from './PanelOptionsEditor';
import { AngularPanelOptions } from '../../panel_editor/AngularPanelOptions';
import { Counter } from '@grafana/ui/src/components/Tabs/Counter';
interface Props {
panel: PanelModel;
@ -29,6 +30,7 @@ export const PanelOptionsTab: FC<Props> = ({
}) => {
const elements: JSX.Element[] = [];
const linkVariablesSuggestions = useMemo(() => getPanelLinksVariableSuggestions(), []);
const panelLinksCount = panel && panel.links ? panel.links.length : undefined;
const variableOptions = getVariableOptions();
const directionOptions = [
@ -89,7 +91,15 @@ export const PanelOptionsTab: FC<Props> = ({
}
elements.push(
<OptionsGroup title="Panel links" key="panel links" defaultToClosed={true}>
<OptionsGroup
renderTitle={isExpanded => (
<>
Panel links {!isExpanded && panelLinksCount && panelLinksCount !== 0 && <Counter value={panelLinksCount} />}
</>
)}
key="panel links"
defaultToClosed={true}
>
<DataLinksInlineEditor
links={panel.links}
onChange={links => onPanelConfigChange('links', links)}