mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch '15217-panels-without-queries' into move-error-boundry
This commit is contained in:
commit
1db5d86b12
@ -145,6 +145,7 @@ func (hs *HTTPServer) getFrontendSettingsMap(c *m.ReqContext) (map[string]interf
|
|||||||
"info": panel.Info,
|
"info": panel.Info,
|
||||||
"hideFromList": panel.HideFromList,
|
"hideFromList": panel.HideFromList,
|
||||||
"sort": getPanelSort(panel.Id),
|
"sort": getPanelSort(panel.Id),
|
||||||
|
"noQueries": panel.NoQueries,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -47,6 +47,7 @@ type PluginBase struct {
|
|||||||
BaseUrl string `json:"baseUrl"`
|
BaseUrl string `json:"baseUrl"`
|
||||||
HideFromList bool `json:"hideFromList,omitempty"`
|
HideFromList bool `json:"hideFromList,omitempty"`
|
||||||
State PluginState `json:"state,omitempty"`
|
State PluginState `json:"state,omitempty"`
|
||||||
|
NoQueries bool `json:"noQueries"`
|
||||||
|
|
||||||
IncludedInAppId string `json:"-"`
|
IncludedInAppId string `json:"-"`
|
||||||
PluginDir string `json:"-"`
|
PluginDir string `json:"-"`
|
||||||
|
@ -10,14 +10,14 @@ import { PanelHeader } from './PanelHeader/PanelHeader';
|
|||||||
import { DataPanel } from './DataPanel';
|
import { DataPanel } from './DataPanel';
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import { applyPanelTimeOverrides } from 'app/features/dashboard/utils/panel';
|
import { applyPanelTimeOverrides, snapshotDataToPanelData } from 'app/features/dashboard/utils/panel';
|
||||||
import { PANEL_HEADER_HEIGHT } from 'app/core/constants';
|
import { PANEL_HEADER_HEIGHT } from 'app/core/constants';
|
||||||
import { profiler } from 'app/core/profiler';
|
import { profiler } from 'app/core/profiler';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { DashboardModel, PanelModel } from '../state';
|
import { DashboardModel, PanelModel } from '../state';
|
||||||
import { PanelPlugin } from 'app/types';
|
import { PanelPlugin } from 'app/types';
|
||||||
import { TimeRange, LoadingState } from '@grafana/ui';
|
import { TimeRange, LoadingState, PanelData } from '@grafana/ui';
|
||||||
|
|
||||||
import variables from 'sass/_variables.scss';
|
import variables from 'sass/_variables.scss';
|
||||||
import templateSrv from 'app/features/templating/template_srv';
|
import templateSrv from 'app/features/templating/template_srv';
|
||||||
@ -94,7 +94,7 @@ export class PanelChrome extends PureComponent<Props, State> {
|
|||||||
return !this.props.dashboard.otherPanelInFullscreen(this.props.panel);
|
return !this.props.dashboard.otherPanelInFullscreen(this.props.panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
renderPanel(loading, panelData, width, height): JSX.Element {
|
renderPanelPlugin(loading: LoadingState, panelData: PanelData, width: number, height: number): JSX.Element {
|
||||||
const { panel, plugin } = this.props;
|
const { panel, plugin } = this.props;
|
||||||
const { timeRange, renderCounter } = this.state;
|
const { timeRange, renderCounter } = this.state;
|
||||||
const PanelComponent = plugin.exports.Panel;
|
const PanelComponent = plugin.exports.Panel;
|
||||||
@ -121,11 +121,45 @@ export class PanelChrome extends PureComponent<Props, State> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
renderHelper = (width: number, height: number): JSX.Element => {
|
||||||
const { panel, dashboard } = this.props;
|
const { panel, plugin } = this.props;
|
||||||
const { refreshCounter, timeRange, timeInfo } = this.state;
|
const { refreshCounter, timeRange } = this.state;
|
||||||
|
const { datasource, targets } = panel;
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{panel.snapshotData && panel.snapshotData.length > 0 ? (
|
||||||
|
this.renderPanelPlugin(LoadingState.Done, snapshotDataToPanelData(panel), width, height)
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
{plugin.noQueries ?
|
||||||
|
this.renderPanelPlugin(LoadingState.Done, null, width, height)
|
||||||
|
: (
|
||||||
|
<DataPanel
|
||||||
|
datasource={datasource}
|
||||||
|
queries={targets}
|
||||||
|
timeRange={timeRange}
|
||||||
|
isVisible={this.isVisible}
|
||||||
|
widthPixels={width}
|
||||||
|
refreshCounter={refreshCounter}
|
||||||
|
onDataResponse={this.onDataResponse}
|
||||||
|
>
|
||||||
|
{({ loading, panelData }) => {
|
||||||
|
return this.renderPanelPlugin(loading, panelData, width, height);
|
||||||
|
}}
|
||||||
|
</DataPanel>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { dashboard, panel } = this.props;
|
||||||
|
const { timeInfo } = this.state;
|
||||||
|
const { transparent } = panel;
|
||||||
|
|
||||||
const { datasource, targets, transparent } = panel;
|
|
||||||
const containerClassNames = `panel-container panel-container--absolute ${transparent ? 'panel-transparent' : ''}`;
|
const containerClassNames = `panel-container panel-container--absolute ${transparent ? 'panel-transparent' : ''}`;
|
||||||
return (
|
return (
|
||||||
<AutoSizer>
|
<AutoSizer>
|
||||||
@ -145,23 +179,7 @@ export class PanelChrome extends PureComponent<Props, State> {
|
|||||||
scopedVars={panel.scopedVars}
|
scopedVars={panel.scopedVars}
|
||||||
links={panel.links}
|
links={panel.links}
|
||||||
/>
|
/>
|
||||||
{panel.snapshotData ? (
|
{this.renderHelper(width, height)}
|
||||||
this.renderPanel(false, panel.snapshotData, width, height)
|
|
||||||
) : (
|
|
||||||
<DataPanel
|
|
||||||
datasource={datasource}
|
|
||||||
queries={targets}
|
|
||||||
timeRange={timeRange}
|
|
||||||
isVisible={this.isVisible}
|
|
||||||
widthPixels={width}
|
|
||||||
refreshCounter={refreshCounter}
|
|
||||||
onDataResponse={this.onDataResponse}
|
|
||||||
>
|
|
||||||
{({ loading, panelData }) => {
|
|
||||||
return this.renderPanel(loading, panelData, width, height);
|
|
||||||
}}
|
|
||||||
</DataPanel>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
|
@ -30,6 +30,32 @@ interface PanelEditorTab {
|
|||||||
text: string;
|
text: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum PanelEditorTabIds {
|
||||||
|
Queries = 'queries',
|
||||||
|
Visualization = 'visualization',
|
||||||
|
Advanced = 'advanced',
|
||||||
|
Alert = 'alert'
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PanelEditorTab {
|
||||||
|
id: string;
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const panelEditorTabTexts = {
|
||||||
|
[PanelEditorTabIds.Queries]: 'Queries',
|
||||||
|
[PanelEditorTabIds.Visualization]: 'Visualization',
|
||||||
|
[PanelEditorTabIds.Advanced]: 'Panel Options',
|
||||||
|
[PanelEditorTabIds.Alert]: 'Alert',
|
||||||
|
};
|
||||||
|
|
||||||
|
const getPanelEditorTab = (tabId: PanelEditorTabIds): PanelEditorTab => {
|
||||||
|
return {
|
||||||
|
id: tabId,
|
||||||
|
text: panelEditorTabTexts[tabId]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export class PanelEditor extends PureComponent<PanelEditorProps> {
|
export class PanelEditor extends PureComponent<PanelEditorProps> {
|
||||||
constructor(props) {
|
constructor(props) {
|
||||||
super(props);
|
super(props);
|
||||||
@ -72,31 +98,26 @@ export class PanelEditor extends PureComponent<PanelEditorProps> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { plugin } = this.props;
|
const { plugin } = this.props;
|
||||||
let activeTab = store.getState().location.query.tab || 'queries';
|
let activeTab: PanelEditorTabIds = store.getState().location.query.tab || PanelEditorTabIds.Queries;
|
||||||
|
|
||||||
const tabs: PanelEditorTab[] = [
|
const tabs: PanelEditorTab[] = [
|
||||||
{ id: 'queries', text: 'Queries' },
|
getPanelEditorTab(PanelEditorTabIds.Queries),
|
||||||
{ id: 'visualization', text: 'Visualization' },
|
getPanelEditorTab(PanelEditorTabIds.Visualization),
|
||||||
{ id: 'advanced', text: 'Panel Options' },
|
getPanelEditorTab(PanelEditorTabIds.Advanced),
|
||||||
];
|
];
|
||||||
|
|
||||||
// handle panels that do not have queries tab
|
// handle panels that do not have queries tab
|
||||||
if (plugin.exports.PanelCtrl) {
|
if (plugin.noQueries) {
|
||||||
if (!plugin.exports.PanelCtrl.prototype.onDataReceived) {
|
// remove queries tab
|
||||||
// remove queries tab
|
tabs.shift();
|
||||||
tabs.shift();
|
// switch tab
|
||||||
// switch tab
|
if (activeTab === PanelEditorTabIds.Queries) {
|
||||||
if (activeTab === 'queries') {
|
activeTab = PanelEditorTabIds.Visualization;
|
||||||
activeTab = 'visualization';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config.alertingEnabled && plugin.id === 'graph') {
|
if (config.alertingEnabled && plugin.id === 'graph') {
|
||||||
tabs.push({
|
tabs.push(getPanelEditorTab(PanelEditorTabIds.Alert));
|
||||||
id: 'alert',
|
|
||||||
text: 'Alert',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -4,7 +4,8 @@ import store from 'app/core/store';
|
|||||||
// Models
|
// Models
|
||||||
import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
|
import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
|
||||||
import { PanelModel } from 'app/features/dashboard/state/PanelModel';
|
import { PanelModel } from 'app/features/dashboard/state/PanelModel';
|
||||||
import { TimeRange } from '@grafana/ui';
|
import { PanelData, TimeRange, TimeSeries } from '@grafana/ui';
|
||||||
|
import { TableData } from '@grafana/ui/src';
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
import { isString as _isString } from 'lodash';
|
import { isString as _isString } from 'lodash';
|
||||||
@ -168,3 +169,19 @@ export function getResolution(panel: PanelModel): number {
|
|||||||
|
|
||||||
return panel.maxDataPoints ? panel.maxDataPoints : Math.ceil(width * (panel.gridPos.w / 24));
|
return panel.maxDataPoints ? panel.maxDataPoints : Math.ceil(width * (panel.gridPos.w / 24));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const isTimeSeries = (data: any): data is TimeSeries => data && data.hasOwnProperty('datapoints');
|
||||||
|
const isTableData = (data: any): data is TableData => data && data.hasOwnProperty('columns');
|
||||||
|
export const snapshotDataToPanelData = (panel: PanelModel): PanelData => {
|
||||||
|
const snapshotData = panel.snapshotData;
|
||||||
|
if (isTimeSeries(snapshotData[0])) {
|
||||||
|
return {
|
||||||
|
timeSeries: snapshotData
|
||||||
|
} as PanelData;
|
||||||
|
} else if (isTableData(snapshotData[0])) {
|
||||||
|
return {
|
||||||
|
tableData: snapshotData[0]
|
||||||
|
} as PanelData;
|
||||||
|
}
|
||||||
|
throw new Error('snapshotData is invalid:' + snapshotData.toString());
|
||||||
|
};
|
||||||
|
@ -9,7 +9,7 @@ import { processTimeSeries } from '@grafana/ui/src/utils';
|
|||||||
import { Graph } from '@grafana/ui';
|
import { Graph } from '@grafana/ui';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { PanelProps, NullValueMode } from '@grafana/ui/src/types';
|
import { PanelProps, NullValueMode, TimeSeriesVMs } from '@grafana/ui/src/types';
|
||||||
import { Options } from './types';
|
import { Options } from './types';
|
||||||
|
|
||||||
interface Props extends PanelProps<Options> {}
|
interface Props extends PanelProps<Options> {}
|
||||||
@ -19,7 +19,7 @@ export class GraphPanel extends PureComponent<Props> {
|
|||||||
const { panelData, timeRange, width, height } = this.props;
|
const { panelData, timeRange, width, height } = this.props;
|
||||||
const { showLines, showBars, showPoints } = this.props.options;
|
const { showLines, showBars, showPoints } = this.props.options;
|
||||||
|
|
||||||
let vmSeries;
|
let vmSeries: TimeSeriesVMs;
|
||||||
if (panelData.timeSeries) {
|
if (panelData.timeSeries) {
|
||||||
vmSeries = processTimeSeries({
|
vmSeries = processTimeSeries({
|
||||||
timeSeries: panelData.timeSeries,
|
timeSeries: panelData.timeSeries,
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
"type": "panel",
|
"type": "panel",
|
||||||
"name": "React Graph",
|
"name": "React Graph",
|
||||||
"id": "graph2",
|
"id": "graph2",
|
||||||
|
|
||||||
"state": "alpha",
|
"state": "alpha",
|
||||||
|
|
||||||
"info": {
|
"info": {
|
||||||
|
@ -2,7 +2,7 @@ import React, { PureComponent } from 'react';
|
|||||||
import { PanelProps } from '@grafana/ui';
|
import { PanelProps } from '@grafana/ui';
|
||||||
|
|
||||||
export class Text2 extends PureComponent<PanelProps> {
|
export class Text2 extends PureComponent<PanelProps> {
|
||||||
constructor(props) {
|
constructor(props: PanelProps) {
|
||||||
super(props);
|
super(props);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
"type": "panel",
|
"type": "panel",
|
||||||
"name": "Text v2",
|
"name": "Text v2",
|
||||||
"id": "text2",
|
"id": "text2",
|
||||||
|
|
||||||
"state": "alpha",
|
"state": "alpha",
|
||||||
|
"noQueries": true,
|
||||||
|
|
||||||
"info": {
|
"info": {
|
||||||
"author": {
|
"author": {
|
||||||
|
@ -9,6 +9,7 @@ export interface PanelPlugin {
|
|||||||
info: any;
|
info: any;
|
||||||
sort: number;
|
sort: number;
|
||||||
exports?: PluginExports;
|
exports?: PluginExports;
|
||||||
|
noQueries?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Plugin {
|
export interface Plugin {
|
||||||
|
Loading…
Reference in New Issue
Block a user