mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
NewPanelEditor: minor UI twekas (#24042)
* Forward ref for tabs, use html props * Inspect: add inspect label to drawer title * Add tooltips to sidebar pane tabs, copy changes * Remove unused import * Place tooltips over tabs * Inspector: dont show transformations select if there is only one data frame * Review
This commit is contained in:
@@ -31,7 +31,7 @@ e2e.scenario({
|
|||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.click();
|
.click();
|
||||||
|
|
||||||
e2e.components.Drawer.General.title(PANEL_UNDER_TEST)
|
e2e.components.Drawer.General.title(`Inspect: ${PANEL_UNDER_TEST}`)
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.within(() => {
|
.within(() => {
|
||||||
e2e.components.Tab.title('Query').should('be.visible');
|
e2e.components.Tab.title('Query').should('be.visible');
|
||||||
@@ -44,7 +44,7 @@ e2e.scenario({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const expectDrawerTabsAndContent = () => {
|
const expectDrawerTabsAndContent = () => {
|
||||||
e2e.components.Drawer.General.title(PANEL_UNDER_TEST)
|
e2e.components.Drawer.General.title(`Inspect: ${PANEL_UNDER_TEST}`)
|
||||||
.should('be.visible')
|
.should('be.visible')
|
||||||
.within(() => {
|
.within(() => {
|
||||||
e2e.components.Tab.title('Data').should('be.visible');
|
e2e.components.Tab.title('Data').should('be.visible');
|
||||||
@@ -87,7 +87,7 @@ const expectDrawerTabsAndContent = () => {
|
|||||||
const expectDrawerClose = () => {
|
const expectDrawerClose = () => {
|
||||||
// close using close button
|
// close using close button
|
||||||
e2e.components.Drawer.General.close().click();
|
e2e.components.Drawer.General.close().click();
|
||||||
e2e.components.Drawer.General.title(PANEL_UNDER_TEST).should('not.be.visible');
|
e2e.components.Drawer.General.title(`Inspect: ${PANEL_UNDER_TEST}`).should('not.be.visible');
|
||||||
};
|
};
|
||||||
|
|
||||||
const expectDrawerExpandAndContract = (viewPortWidth: number) => {
|
const expectDrawerExpandAndContract = (viewPortWidth: number) => {
|
||||||
|
|||||||
@@ -314,7 +314,7 @@ export class PanelPlugin<TOptions = any, TFieldConfigOptions extends object = an
|
|||||||
|
|
||||||
for (const customProp of builder.getRegistry().list()) {
|
for (const customProp of builder.getRegistry().list()) {
|
||||||
customProp.isCustom = true;
|
customProp.isCustom = true;
|
||||||
customProp.category = ['Custom field options'].concat(customProp.category || []);
|
customProp.category = ['Custom options'].concat(customProp.category || []);
|
||||||
// need to do something to make the custom items not conflict with standard ones
|
// need to do something to make the custom items not conflict with standard ones
|
||||||
// problem is id (registry index) is used as property path
|
// problem is id (registry index) is used as property path
|
||||||
// so sort of need a property path on the FieldPropertyEditorItem
|
// so sort of need a property path on the FieldPropertyEditorItem
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { FC } from 'react';
|
import React, { HTMLProps } from 'react';
|
||||||
import { css, cx } from 'emotion';
|
import { css, cx } from 'emotion';
|
||||||
import { GrafanaTheme } from '@grafana/data';
|
import { GrafanaTheme } from '@grafana/data';
|
||||||
import { selectors } from '@grafana/e2e-selectors';
|
import { selectors } from '@grafana/e2e-selectors';
|
||||||
@@ -8,7 +8,7 @@ import { IconName } from '../../types';
|
|||||||
import { stylesFactory, useTheme } from '../../themes';
|
import { stylesFactory, useTheme } from '../../themes';
|
||||||
import { Counter } from './Counter';
|
import { Counter } from './Counter';
|
||||||
|
|
||||||
export interface TabProps {
|
export interface TabProps extends HTMLProps<HTMLLIElement> {
|
||||||
label: string;
|
label: string;
|
||||||
active?: boolean;
|
active?: boolean;
|
||||||
icon?: IconName;
|
icon?: IconName;
|
||||||
@@ -16,6 +16,31 @@ export interface TabProps {
|
|||||||
counter?: number;
|
counter?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const Tab = React.forwardRef<HTMLLIElement, TabProps>(
|
||||||
|
({ label, active, icon, onChangeTab, counter, className, ...otherProps }, ref) => {
|
||||||
|
const theme = useTheme();
|
||||||
|
const tabsStyles = getTabStyles(theme);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
{...otherProps}
|
||||||
|
className={cx(tabsStyles.tabItem, active && tabsStyles.activeStyle)}
|
||||||
|
onClick={() => {
|
||||||
|
if (!active) {
|
||||||
|
onChangeTab();
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
aria-label={selectors.components.Tab.title(label)}
|
||||||
|
ref={ref}
|
||||||
|
>
|
||||||
|
{icon && <Icon name={icon} />}
|
||||||
|
{label}
|
||||||
|
{typeof counter === 'number' && <Counter value={counter} />}
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
const getTabStyles = stylesFactory((theme: GrafanaTheme) => {
|
const getTabStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||||
const colors = theme.colors;
|
const colors = theme.colors;
|
||||||
|
|
||||||
@@ -47,6 +72,7 @@ const getTabStyles = stylesFactory((theme: GrafanaTheme) => {
|
|||||||
background: ${colors.bodyBg};
|
background: ${colors.bodyBg};
|
||||||
color: ${colors.link};
|
color: ${colors.link};
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
cursor: default;
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
display: block;
|
display: block;
|
||||||
@@ -61,20 +87,3 @@ const getTabStyles = stylesFactory((theme: GrafanaTheme) => {
|
|||||||
`,
|
`,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
export const Tab: FC<TabProps> = ({ label, active, icon, onChangeTab, counter }) => {
|
|
||||||
const theme = useTheme();
|
|
||||||
const tabsStyles = getTabStyles(theme);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<li
|
|
||||||
className={cx(tabsStyles.tabItem, active && tabsStyles.activeStyle)}
|
|
||||||
onClick={onChangeTab}
|
|
||||||
aria-label={selectors.components.Tab.title(label)}
|
|
||||||
>
|
|
||||||
{icon && <Icon name={icon} />}
|
|
||||||
{label}
|
|
||||||
{typeof counter === 'number' && <Counter value={counter} />}
|
|
||||||
</li>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import { StatsPickerEditor } from '../components/OptionsUI/stats';
|
|||||||
* Returns collection of common field config properties definitions
|
* Returns collection of common field config properties definitions
|
||||||
*/
|
*/
|
||||||
export const getStandardFieldConfigs = () => {
|
export const getStandardFieldConfigs = () => {
|
||||||
const category = ['Standard field options'];
|
const category = ['Standard options'];
|
||||||
const title: FieldConfigPropertyItem<any, string, StringFieldConfigSettings> = {
|
const title: FieldConfigPropertyItem<any, string, StringFieldConfigSettings> = {
|
||||||
id: 'title',
|
id: 'title',
|
||||||
path: 'title',
|
path: 'title',
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export class InspectDataTab extends PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { isLoading } = this.props;
|
const { isLoading, data } = this.props;
|
||||||
const { dataFrameIndex, transformId, transformationOptions } = this.state;
|
const { dataFrameIndex, transformId, transformationOptions } = this.state;
|
||||||
const styles = getPanelInspectorStyles();
|
const styles = getPanelInspectorStyles();
|
||||||
|
|
||||||
@@ -112,9 +112,11 @@ export class InspectDataTab extends PureComponent<Props, State> {
|
|||||||
return (
|
return (
|
||||||
<div className={styles.dataTabContent} aria-label={selectors.components.PanelInspector.Data.content}>
|
<div className={styles.dataTabContent} aria-label={selectors.components.PanelInspector.Data.content}>
|
||||||
<div className={styles.toolbar}>
|
<div className={styles.toolbar}>
|
||||||
|
{data.length > 1 && (
|
||||||
<Field label="Transformer" className="flex-grow-1">
|
<Field label="Transformer" className="flex-grow-1">
|
||||||
<Select options={transformationOptions} value={transformId} onChange={this.onTransformationChange} />
|
<Select options={transformationOptions} value={transformId} onChange={this.onTransformationChange} />
|
||||||
</Field>
|
</Field>
|
||||||
|
)}
|
||||||
{choices.length > 1 && (
|
{choices.length > 1 && (
|
||||||
<Field label="Select result" className={cx(styles.toolbarItem, 'flex-grow-1')}>
|
<Field label="Select result" className={cx(styles.toolbarItem, 'flex-grow-1')}>
|
||||||
<Select options={choices} value={dataFrameIndex} onChange={this.onSelectedFrameChanged} />
|
<Select options={choices} value={dataFrameIndex} onChange={this.onSelectedFrameChanged} />
|
||||||
|
|||||||
@@ -311,7 +311,7 @@ export class PanelInspectorUnconnected extends PureComponent<Props, State> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Drawer
|
<Drawer
|
||||||
title={panel.title || 'Panel inspect'}
|
title={`Inspect: ${panel.title}` || 'Panel inspect'}
|
||||||
subtitle={this.drawerSubtitle(tabs, activeTab)}
|
subtitle={this.drawerSubtitle(tabs, activeTab)}
|
||||||
width={drawerWidth}
|
width={drawerWidth}
|
||||||
onClose={this.onClose}
|
onClose={this.onClose}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ export const getPanelInspectorStyles = stylesFactory(() => {
|
|||||||
flex-grow: 0;
|
flex-grow: 0;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-end;
|
justify-content: flex-end;
|
||||||
|
margin-bottom: ${config.theme.spacing.sm};
|
||||||
`,
|
`,
|
||||||
toolbarItem: css`
|
toolbarItem: css`
|
||||||
margin-left: ${config.theme.spacing.md};
|
margin-left: ${config.theme.spacing.md};
|
||||||
|
|||||||
@@ -203,6 +203,7 @@ export const TabsBarContent: React.FC<{
|
|||||||
counter={item.value === 'overrides' ? overridesCount : undefined}
|
counter={item.value === 'overrides' ? overridesCount : undefined}
|
||||||
active={active.value === item.value}
|
active={active.value === item.value}
|
||||||
onChangeTab={() => setActiveTab(item.value)}
|
onChangeTab={() => setActiveTab(item.value)}
|
||||||
|
title={item.tooltip}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
<div className="flex-grow-1" />
|
<div className="flex-grow-1" />
|
||||||
@@ -225,14 +226,17 @@ const tabSelections: Array<SelectableValue<string>> = [
|
|||||||
{
|
{
|
||||||
label: 'Panel',
|
label: 'Panel',
|
||||||
value: 'options',
|
value: 'options',
|
||||||
|
tooltip: 'Configure panel display options',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Fields',
|
label: 'Field',
|
||||||
value: 'defaults',
|
value: 'defaults',
|
||||||
|
tooltip: 'Configure field options',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Overrides',
|
label: 'Overrides',
|
||||||
value: 'overrides',
|
value: 'overrides',
|
||||||
|
tooltip: 'Configure field option overrides',
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export const PanelOptionsTab: FC<Props> = ({
|
|||||||
};
|
};
|
||||||
// Fist common panel settings Title, description
|
// Fist common panel settings Title, description
|
||||||
elements.push(
|
elements.push(
|
||||||
<OptionsGroup title="Panel settings" id="Panel settings" key="Panel settings">
|
<OptionsGroup title="Settings" id="Panel settings" key="Panel settings">
|
||||||
<Field label="Panel title">
|
<Field label="Panel title">
|
||||||
<Input defaultValue={panel.title} onBlur={e => onPanelConfigChange('title', e.currentTarget.value)} />
|
<Input defaultValue={panel.title} onBlur={e => onPanelConfigChange('title', e.currentTarget.value)} />
|
||||||
</Field>
|
</Field>
|
||||||
@@ -65,7 +65,7 @@ export const PanelOptionsTab: FC<Props> = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
elements.push(
|
elements.push(
|
||||||
<OptionsGroup title="Panel type" id="Panel type" key="Panel type" defaultToClosed onToggle={focusVisPickerInput}>
|
<OptionsGroup title="Visualisation" id="Panel type" key="Panel type" defaultToClosed onToggle={focusVisPickerInput}>
|
||||||
<VisualizationTab panel={panel} ref={visTabInputRef} />
|
<VisualizationTab panel={panel} ref={visTabInputRef} />
|
||||||
</OptionsGroup>
|
</OptionsGroup>
|
||||||
);
|
);
|
||||||
@@ -73,7 +73,7 @@ export const PanelOptionsTab: FC<Props> = ({
|
|||||||
// Old legacy react editor
|
// Old legacy react editor
|
||||||
if (plugin.editor && panel && !plugin.optionEditors) {
|
if (plugin.editor && panel && !plugin.optionEditors) {
|
||||||
elements.push(
|
elements.push(
|
||||||
<OptionsGroup title="Display" id="legacy react editor" key="legacy react editor">
|
<OptionsGroup title="Options" id="legacy react editor" key="legacy react editor">
|
||||||
<plugin.editor data={data} options={panel.getOptions()} onOptionsChange={onPanelOptionsChanged} />
|
<plugin.editor data={data} options={panel.getOptions()} onOptionsChange={onPanelOptionsChanged} />
|
||||||
</OptionsGroup>
|
</OptionsGroup>
|
||||||
);
|
);
|
||||||
@@ -98,9 +98,7 @@ export const PanelOptionsTab: FC<Props> = ({
|
|||||||
|
|
||||||
elements.push(
|
elements.push(
|
||||||
<OptionsGroup
|
<OptionsGroup
|
||||||
renderTitle={isExpanded => (
|
renderTitle={isExpanded => <>Links {!isExpanded && panelLinksCount > 0 && <Counter value={panelLinksCount} />}</>}
|
||||||
<>Panel links {!isExpanded && panelLinksCount > 0 && <Counter value={panelLinksCount} />}</>
|
|
||||||
)}
|
|
||||||
id="panel links"
|
id="panel links"
|
||||||
key="panel links"
|
key="panel links"
|
||||||
defaultToClosed
|
defaultToClosed
|
||||||
@@ -115,7 +113,7 @@ export const PanelOptionsTab: FC<Props> = ({
|
|||||||
);
|
);
|
||||||
|
|
||||||
elements.push(
|
elements.push(
|
||||||
<OptionsGroup title="Panel repeats" id="panel repeats" key="panel repeats" defaultToClosed>
|
<OptionsGroup title="Repeat options" id="panel repeats" key="panel repeats" defaultToClosed>
|
||||||
<Field
|
<Field
|
||||||
label="Repeat by variable"
|
label="Repeat by variable"
|
||||||
description="Repeat this panel for each value in the selected variable.
|
description="Repeat this panel for each value in the selected variable.
|
||||||
|
|||||||
Reference in New Issue
Block a user