Table: add a select option when multiple tables exist (#23545)

* add a table picker

* move picker to the top

* add missing change

* Removed overflow from panel-content so dropdown menus can extend a panel, moved the select to the bottom

Co-authored-by: Torkel Ödegaard <torkel@grafana.com>
This commit is contained in:
Ryan McKinley
2020-04-16 12:35:58 -07:00
committed by GitHub
parent e64e8dd098
commit 6c021f7bb9
11 changed files with 83 additions and 43 deletions

View File

@@ -67,7 +67,7 @@ export interface GrafanaThemeCommons {
formSpacingBase: number;
formMargin: string;
formFieldsetMargin: string;
formInputHeight: string;
formInputHeight: number;
formButtonHeight: number;
formInputPaddingHorizontal: string;
// Used for icons do define spacing between icon and input field

View File

@@ -57,7 +57,7 @@ export const getInputStyles = stylesFactory(({ theme, invalid = false }: StyleDe
label: input-wrapper;
display: flex;
width: 100%;
height: ${height};
height: ${height}px;
border-radius: ${borderRadius};
&:hover {
> .prefix,

View File

@@ -133,7 +133,7 @@ export function sharedSingleStatMigrationHandler(panel: PanelModel<SingleStatBas
const { fieldOptions } = options;
if (previousVersion < 6.6) {
if (previousVersion < 6.6 && fieldOptions) {
// discard the old `override` options and enter an empty array
if (fieldOptions && fieldOptions.override) {
const { override, ...rest } = options.fieldOptions;

View File

@@ -73,7 +73,7 @@ const getStyles = stylesFactory((theme: GrafanaTheme) => {
background-color: ${bgColor};
border-radius: ${borderRadius};
border-color: ${borderColor};
height: ${theme.spacing.formInputHeight};
height: ${theme.spacing.formInputHeight}px;
&:focus {
${getFocusCss(theme)}

View File

@@ -199,7 +199,7 @@ exports[`TimePicker renders buttons correctly 1`] = `
"formButtonHeight": 32,
"formFieldsetMargin": "16px",
"formInputAffixPaddingHorizontal": "4px",
"formInputHeight": "32px",
"formInputHeight": 32,
"formInputMargin": "16px",
"formInputPaddingHorizontal": "8px",
"formLabelMargin": "0 0 4px 0",
@@ -515,7 +515,7 @@ exports[`TimePicker renders content correctly after beeing open 1`] = `
"formButtonHeight": 32,
"formFieldsetMargin": "16px",
"formInputAffixPaddingHorizontal": "4px",
"formInputHeight": "32px",
"formInputHeight": 32,
"formInputMargin": "16px",
"formInputPaddingHorizontal": "8px",
"formLabelMargin": "0 0 4px 0",

View File

@@ -89,7 +89,7 @@ const theme: GrafanaThemeCommons = {
formSpacingBase: SPACING_BASE,
formMargin: `${SPACING_BASE * 4}px`,
formFieldsetMargin: `${SPACING_BASE * 2}px`,
formInputHeight: `${SPACING_BASE * 4}px`,
formInputHeight: SPACING_BASE * 4,
formButtonHeight: SPACING_BASE * 4,
formInputPaddingHorizontal: `${SPACING_BASE}px`,

View File

@@ -80,8 +80,8 @@ const getQueryOperationRowStyles = stylesFactory((theme: GrafanaTheme) => {
padding: 0 ${theme.spacing.sm};
border-radius: ${theme.border.radius.sm};
background: ${theme.colors.bg2};
height: ${theme.spacing.formInputHeight};
line-height: ${theme.spacing.formInputHeight};
height: ${theme.spacing.formInputHeight}px;
line-height: ${theme.spacing.formInputHeight}px;
display: flex;
align-items: center;
justify-content: space-between;

View File

@@ -74,21 +74,19 @@ export class NewsPanel extends PureComponent<Props, State> {
}
return (
<div className={styles.container}>
<CustomScrollbar>
{news.map((item, index) => {
return (
<div key={index} className={styles.item}>
<a href={item.link} target="_blank">
<div className={styles.title}>{item.title}</div>
<div className={styles.date}>{dateTime(item.date).format('MMM DD')} </div>
</a>
<div className={styles.content} dangerouslySetInnerHTML={{ __html: sanitize(item.content) }} />
</div>
);
})}
</CustomScrollbar>
</div>
<CustomScrollbar autoHeightMin="100%" autoHeightMax="100%">
{news.map((item, index) => {
return (
<div key={index} className={styles.item}>
<a href={item.link} target="_blank">
<div className={styles.title}>{item.title}</div>
<div className={styles.date}>{dateTime(item.date).format('MMM DD')} </div>
</a>
<div className={styles.content} dangerouslySetInnerHTML={{ __html: sanitize(item.content) }} />
</div>
);
})}
</CustomScrollbar>
);
}
}

View File

@@ -1,8 +1,10 @@
import React, { Component } from 'react';
import { Table } from '@grafana/ui';
import { Field, FieldMatcherID, PanelProps } from '@grafana/data';
import { Table, Select } from '@grafana/ui';
import { Field, FieldMatcherID, PanelProps, DataFrame, SelectableValue } from '@grafana/data';
import { Options } from './types';
import { css } from 'emotion';
import { config } from 'app/core/config';
interface Props extends PanelProps<Options> {}
@@ -30,20 +32,65 @@ export class TablePanel extends Component<Props> {
});
};
onChangeTableSelection = (val: SelectableValue<number>) => {
this.props.onOptionsChange({
...this.props.options,
frameIndex: val.value || 0,
});
// Force a redraw -- but no need to re-query
this.forceUpdate();
};
renderTable(frame: DataFrame, width: number, height: number) {
const {
options: { showHeader, resizable },
} = this.props;
return <Table height={height} width={width} data={frame} noHeader={!showHeader} resizable={resizable} />;
}
render() {
const {
data,
height,
width,
options: { showHeader, resizable },
options: { frameIndex },
} = this.props;
if (data.series.length < 1) {
return <div>No Table Data...</div>;
const count = data.series?.length;
if (!count || count < 1) {
return <div>No data</div>;
}
return (
<Table height={height - 16} width={width} data={data.series[0]} noHeader={!showHeader} resizable={resizable} />
);
if (count > 1) {
const inputHeight = config.theme.spacing.formInputHeight;
const padding = 8;
const index = frameIndex > 0 && frameIndex < count ? frameIndex : 0;
const names = data.series.map((frame, index) => {
return {
label: `${frame.name ?? 'Series'}`,
value: index,
};
});
return (
<div className={tableStyles.wrapper}>
{this.renderTable(data.series[index], width, height - inputHeight - padding)}
<Select options={names} value={names[index]} onChange={this.onChangeTableSelection} />
</div>
);
}
return this.renderTable(data.series[0], width, height);
}
}
const tableStyles = {
wrapper: css`
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
`,
};

View File

@@ -1,4 +1,5 @@
export interface Options {
frameIndex: number;
showHeader: boolean;
resizable: boolean;
}

View File

@@ -54,6 +54,9 @@ div.flot-text {
border-radius: 3px;
height: 100%;
width: 100%;
display: flex;
flex-direction: column;
flex: 1 1 0;
&--transparent {
background-color: transparent;
@@ -79,23 +82,14 @@ div.flot-text {
.panel-content {
padding: $panel-padding;
height: calc(100% - #{$panel-header-height});
width: 100%;
position: relative;
overflow: auto;
flex-grow: 1;
max-height: calc(100% - #{$panel-header-height});
&--no-padding {
padding: 0;
}
}
// For larger screens, set back to hidden to avoid double scroll bars
@include media-breakpoint-up(md) {
.panel-content {
overflow: hidden;
}
}
.dashboard-header {
font-size: $font-size-h2;
text-align: center;