mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Overrides: Show option group counters for options that represent collections (#23655)
This commit is contained in:
parent
4e521a84b4
commit
539edba31b
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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> = {
|
||||
|
@ -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 => {
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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)}
|
||||
/>
|
||||
|
@ -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)}
|
||||
|
Loading…
Reference in New Issue
Block a user