mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
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:
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)}
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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`,
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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%;
|
||||
`,
|
||||
};
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export interface Options {
|
||||
frameIndex: number;
|
||||
showHeader: boolean;
|
||||
resizable: boolean;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user