PanelEdit: Improves viz picker ux, auto close on click (#33633)

* PanelEdit: Improves viz picker ux, auto close on click

* Fixing strict ts error

* Updated e2e
This commit is contained in:
Torkel Ödegaard 2021-05-03 16:49:09 +02:00 committed by GitHub
parent 437b247b95
commit 578283078b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 46 additions and 38 deletions

View File

@ -73,21 +73,15 @@ e2e.scenario({
// Change to Text panel
e2e.components.PluginVisualization.item('Text').scrollIntoView().should('be.visible').click();
e2e.components.PluginVisualization.current().within((div: JQuery<HTMLDivElement>) => {
expect(div.text()).equals('Text');
});
e2e.components.PanelEditor.toggleVizPicker().should((e) => expect(e).to.contain('Text'));
// Data pane should not be rendered
e2e.components.PanelEditor.DataPane.content().should('not.exist');
// Change to Table panel
e2e.components.PluginVisualization.item('Table').scrollIntoView().should('be.visible').click();
e2e.components.PluginVisualization.current().within((div: JQuery<HTMLDivElement>) => {
expect(div.text()).equals('Table');
});
// close viz picker
e2e.components.PanelEditor.toggleVizPicker().click();
e2e.components.PluginVisualization.item('Table').scrollIntoView().should('be.visible').click();
e2e.components.PanelEditor.toggleVizPicker().should((e) => expect(e).to.contain('Table'));
// Data pane should be rendered
e2e.components.PanelEditor.DataPane.content().should('be.visible');

View File

@ -84,6 +84,7 @@ export type ThemeColorsInput = DeepPartial<ThemeColorsBase<ThemeRichColor>>;
class DarkColors implements ThemeColorsBase<Partial<ThemeRichColor>> {
mode: ThemeColorsMode = 'dark';
// Used to get more white opacity colors
whiteBase = '201, 209, 217';
border = {

View File

@ -20,9 +20,7 @@ const getTabsBarStyles = stylesFactory((theme: GrafanaTheme2, hideBorder = false
`,
tabs: css`
position: relative;
top: 1px;
display: flex;
// Sometimes TabsBar is rendered without any tabs, and should preserve height
height: 41px;
`,
};

View File

@ -258,28 +258,30 @@ func getPanelSort(id string) int {
sort = 1
case "timeseries":
sort = 2
case "stat":
case "barchart":
sort = 3
case "gauge":
case "stat":
sort = 4
case "bargauge":
case "gauge":
sort = 5
case "table":
case "bargauge":
sort = 6
case "singlestat":
case "table":
sort = 7
case "piechart":
case "singlestat":
sort = 8
case "text":
case "piechart":
sort = 9
case "heatmap":
sort = 10
case "alertlist":
case "text":
sort = 11
case "dashlist":
case "alertlist":
sort = 12
case "news":
case "dashlist":
sort = 13
case "news":
sort = 14
}
return sort
}

View File

@ -17,5 +17,9 @@ func (p *PanelPlugin) Load(decoder *json.Decoder, base *PluginBase, backendPlugi
return nil, err
}
if p.Id == "grafana-piechart-panel" {
p.Name = "Pie Chart (old)"
}
return p, nil
}

View File

@ -26,12 +26,15 @@ export const VisualizationSelectPane: FC<Props> = ({ panel }) => {
const searchRef = useRef<HTMLInputElement | null>(null);
const onPluginTypeChange = useCallback(
(meta: PanelPluginMeta) => {
if (meta.id === plugin.meta.id) {
dispatch(toggleVizPicker(false));
} else {
(meta: PanelPluginMeta, withModKey: boolean) => {
if (meta.id !== plugin.meta.id) {
dispatch(changePanelPlugin(panel, meta.id));
}
// close viz picker unless a mod key is pressed while clicking
if (!withModKey) {
dispatch(toggleVizPicker(false));
}
},
[dispatch, panel, plugin.meta.id]
);
@ -53,8 +56,9 @@ export const VisualizationSelectPane: FC<Props> = ({ panel }) => {
const query = e.currentTarget.value;
const plugins = getAllPanelPluginMeta();
const match = filterPluginList(plugins, query, plugin.meta);
if (match && match.length) {
onPluginTypeChange(match[0]);
onPluginTypeChange(match[0], true);
}
}
},

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { MouseEventHandler } from 'react';
import { GrafanaTheme2, isUnsignedPluginSignature, PanelPluginMeta, PluginState } from '@grafana/data';
import { Badge, BadgeProps, IconButton, PluginSignatureBadge, useStyles2 } from '@grafana/ui';
import { css, cx } from '@emotion/css';
@ -8,7 +8,7 @@ interface Props {
isCurrent: boolean;
plugin: PanelPluginMeta;
title: string;
onClick: () => void;
onClick: MouseEventHandler<HTMLDivElement>;
onDelete?: () => void;
disabled?: boolean;
showBadge?: boolean;
@ -75,6 +75,7 @@ const getStyles = (theme: GrafanaTheme2) => {
background: ${theme.colors.background.secondary};
border-radius: ${theme.shape.borderRadius()};
box-shadow: ${theme.shadows.z1};
border: 1px solid ${theme.colors.background.secondary};
align-items: center;
padding: 8px;
width: 100%;
@ -95,7 +96,7 @@ const getStyles = (theme: GrafanaTheme2) => {
`,
current: css`
label: currentVisualizationItem;
border-color: ${theme.colors.primary.border};
background: ${theme.colors.action.selected};
`,
disabled: css`
opacity: 0.2;
@ -116,6 +117,7 @@ const getStyles = (theme: GrafanaTheme2) => {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
color: ${theme.colors.text.secondary};
font-size: ${theme.typography.bodySmall.fontSize};
font-weight: ${theme.typography.fontWeightLight};
padding: 0 ${theme.spacing(1.25)};

View File

@ -8,7 +8,7 @@ import { css } from '@emotion/css';
export interface Props {
current: PanelPluginMeta;
onTypeChange: (newType: PanelPluginMeta) => void;
onTypeChange: (newType: PanelPluginMeta, withModKey?: boolean) => void;
searchQuery: string;
onClose: () => void;
}
@ -35,21 +35,26 @@ export function filterPluginList(
return true;
});
}
const query = searchQuery.toLowerCase();
const first: PanelPluginMeta[] = [];
const match: PanelPluginMeta[] = [];
for (const item of pluginsList) {
if (item.state === PluginState.deprecated && current.id !== item.id) {
continue;
}
const name = item.name.toLowerCase();
const idx = name.indexOf(query);
if (idx === 0) {
first.push(item);
} else if (idx > 0) {
match.push(item);
}
}
return first.concat(match);
}
@ -75,7 +80,7 @@ export const VizTypePicker: React.FC<Props> = ({ searchQuery, onTypeChange, curr
key={plugin.id}
isCurrent={isCurrent}
plugin={plugin}
onClick={() => onTypeChange(plugin)}
onClick={(e) => onTypeChange(plugin, e.metaKey || e.ctrlKey || e.altKey)}
/>
);
};
@ -108,7 +113,6 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
max-width: 100%;
display: grid;
grid-gap: ${theme.spacing.sm};
grid-template-columns: repeat(auto-fit, minmax(185px, 1fr));
`,
};
});

View File

@ -1,11 +1,11 @@
import React from 'react';
import React, { MouseEventHandler } from 'react';
import { PanelPluginMeta } from '@grafana/data';
import { PanelTypeCard } from './PanelTypeCard';
interface Props {
isCurrent: boolean;
plugin: PanelPluginMeta;
onClick: () => void;
onClick: MouseEventHandler<HTMLDivElement>;
disabled: boolean;
}

View File

@ -1,8 +1,8 @@
import { indexOf } from 'lodash';
import { auto } from 'angular';
export class QueryCtrl {
target!: any;
export class QueryCtrl<T = any> {
target!: T;
datasource!: any;
panelCtrl!: any;
panel: any;

View File

@ -20,11 +20,10 @@ WHERE
ORDER BY
<time_column> ASC`;
export class MssqlQueryCtrl extends QueryCtrl {
export class MssqlQueryCtrl extends QueryCtrl<MssqlQuery> {
static templateUrl = 'partials/query.editor.html';
formats: any[];
target: MssqlQuery;
lastQueryMeta?: QueryResultMeta;
lastQueryError?: string;
showHelp = false;