diff --git a/package.json b/package.json index 68b7647fb58..9a04bff77eb 100644 --- a/package.json +++ b/package.json @@ -163,6 +163,7 @@ "react-sizeme": "^2.3.6", "react-table": "^6.8.6", "react-transition-group": "^2.2.1", + "react-virtualized": "^9.21.0", "redux": "^4.0.0", "redux-logger": "^3.0.6", "redux-thunk": "^2.3.0", diff --git a/public/app/core/components/Switch/Switch.tsx b/public/app/core/components/Switch/Switch.tsx index a4bb73a291b..09c5b894d3d 100644 --- a/public/app/core/components/Switch/Switch.tsx +++ b/public/app/core/components/Switch/Switch.tsx @@ -26,6 +26,7 @@ export class Switch extends PureComponent { render() { const { labelClass = '', switchClass = '', label, checked, small } = this.props; + const labelId = `check-${this.state.id}`; let labelClassName = `gf-form-label ${labelClass} pointer`; let switchClassName = `gf-form-switch ${switchClass}`; diff --git a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx index 55249a4716f..84db3a2cf99 100644 --- a/public/app/features/dashboard/dashgrid/DashboardGrid.tsx +++ b/public/app/features/dashboard/dashgrid/DashboardGrid.tsx @@ -176,6 +176,7 @@ export class DashboardGrid extends React.Component { renderPanels() { const panelElements = []; + console.log('render panels'); for (const panel of this.props.dashboard.panels) { const panelClasses = classNames({ panel: true, 'panel--fullscreen': panel.fullscreen }); diff --git a/public/app/features/dashboard/dashgrid/DataPanel.tsx b/public/app/features/dashboard/dashgrid/DataPanel.tsx index 413cb788756..ecff4a7fabf 100644 --- a/public/app/features/dashboard/dashgrid/DataPanel.tsx +++ b/public/app/features/dashboard/dashgrid/DataPanel.tsx @@ -4,6 +4,9 @@ import React, { Component } from 'react'; // Services import { getDatasourceSrv } from 'app/features/plugins/datasource_srv'; +// Utils +import kbn from 'app/core/utils/kbn'; + // Types import { TimeRange, LoadingState, DataQueryOptions, DataQueryResponse, TimeSeries } from 'app/types'; @@ -19,7 +22,10 @@ export interface Props { dashboardId?: number; isVisible?: boolean; timeRange?: TimeRange; + widthPixels: number; refreshCounter: number; + minInterval?: string; + maxDataPoints?: number; children: (r: RenderProps) => JSX.Element; } @@ -30,6 +36,8 @@ export interface State { } export class DataPanel extends Component { + dataSourceSrv = getDatasourceSrv(); + static defaultProps = { isVisible: true, panelId: 1, @@ -49,7 +57,7 @@ export class DataPanel extends Component { } componentDidMount() { - console.log('DataPanel mount'); + this.issueQueries(); } async componentDidUpdate(prevProps: Props) { @@ -61,11 +69,11 @@ export class DataPanel extends Component { } hasPropsChanged(prevProps: Props) { - return this.props.refreshCounter !== prevProps.refreshCounter || this.props.isVisible !== prevProps.isVisible; + return this.props.refreshCounter !== prevProps.refreshCounter; } issueQueries = async () => { - const { isVisible, queries, datasource, panelId, dashboardId, timeRange } = this.props; + const { isVisible, queries, datasource, panelId, dashboardId, timeRange, widthPixels, maxDataPoints } = this.props; if (!isVisible) { return; @@ -79,18 +87,22 @@ export class DataPanel extends Component { this.setState({ loading: LoadingState.Loading }); try { - const dataSourceSrv = getDatasourceSrv(); - const ds = await dataSourceSrv.get(datasource); + const ds = await this.dataSourceSrv.get(datasource); + + // TODO interpolate variables + const minInterval = this.props.minInterval || ds.interval; + const intervalRes = kbn.calculateInterval(timeRange, widthPixels, minInterval); + const queryOptions: DataQueryOptions = { timezone: 'browser', panelId: panelId, dashboardId: dashboardId, range: timeRange, rangeRaw: timeRange.raw, - interval: '1s', - intervalMs: 60000, + interval: intervalRes.interval, + intervalMs: intervalRes.intervalMs, targets: queries, - maxDataPoints: 500, + maxDataPoints: maxDataPoints || widthPixels, scopedVars: {}, cacheTimeout: null, }; @@ -111,17 +123,10 @@ export class DataPanel extends Component { }; render() { - const { response, loading, isFirstLoad } = this.state; - console.log('data panel render'); + const { response, loading } = this.state; const timeSeries = response.data; - if (isFirstLoad && (loading === LoadingState.Loading || loading === LoadingState.NotStarted)) { - return ( -
-

Loading

-
- ); - } + console.log('data panel render'); return ( <> @@ -139,7 +144,7 @@ export class DataPanel extends Component { if (loading === LoadingState.Loading) { return ( -
+
); diff --git a/public/app/features/dashboard/dashgrid/PanelChrome.tsx b/public/app/features/dashboard/dashgrid/PanelChrome.tsx index 3bfa1d365b7..99b44e6ff72 100644 --- a/public/app/features/dashboard/dashgrid/PanelChrome.tsx +++ b/public/app/features/dashboard/dashgrid/PanelChrome.tsx @@ -1,5 +1,6 @@ // Libraries import React, { ComponentClass, PureComponent } from 'react'; +import { AutoSizer } from 'react-virtualized'; // Services import { getTimeSrv, TimeSrv } from '../time_srv'; @@ -87,31 +88,45 @@ export class PanelChrome extends PureComponent { console.log('panelChrome render'); return ( -
- -
- - {({ loading, timeSeries }) => { - console.log('panelcrome inner render'); - return ( - - ); - }} - -
-
+ + {({ width, height }) => { + if (width === 0) { + return null; + } + + return ( +
+ + {({ loading, timeSeries }) => { + return ( + <> + +
+ +
+ + ); + }} +
+
+ ); + }} +
); } } diff --git a/public/app/plugins/panel/graph2/module.tsx b/public/app/plugins/panel/graph2/module.tsx index b898d54c984..5b6e11b7f83 100644 --- a/public/app/plugins/panel/graph2/module.tsx +++ b/public/app/plugins/panel/graph2/module.tsx @@ -23,7 +23,7 @@ export class Graph2 extends PureComponent { } render() { - const { timeSeries, timeRange } = this.props; + const { timeSeries, timeRange, width, height } = this.props; const { showLines, showBars, showPoints } = this.props.options; const vmSeries = getTimeSeriesVMs({ @@ -38,6 +38,8 @@ export class Graph2 extends PureComponent { showLines={showLines} showPoints={showPoints} showBars={showBars} + width={width} + height={height} /> ); } diff --git a/public/app/types/panel.ts b/public/app/types/panel.ts index d70723408b0..88540c16f04 100644 --- a/public/app/types/panel.ts +++ b/public/app/types/panel.ts @@ -6,6 +6,8 @@ export interface PanelProps { loading: LoadingState; options: T; renderCounter: number; + width: number; + height: number; } export interface PanelOptionsProps { diff --git a/public/app/types/series.ts b/public/app/types/series.ts index 997090bf541..1feba9a3b53 100644 --- a/public/app/types/series.ts +++ b/public/app/types/series.ts @@ -89,4 +89,6 @@ export interface DataQueryOptions { export interface DataSourceApi { query(options: DataQueryOptions): Promise; testDatasource(): Promise; + + interval?: string; } diff --git a/public/app/viz/Graph.tsx b/public/app/viz/Graph.tsx index 566080fbc92..bdababb3e50 100644 --- a/public/app/viz/Graph.tsx +++ b/public/app/viz/Graph.tsx @@ -1,7 +1,6 @@ // Libraries import $ from 'jquery'; import React, { PureComponent } from 'react'; -import { withSize } from 'react-sizeme'; import 'vendor/flot/jquery.flot'; import 'vendor/flot/jquery.flot.time'; @@ -14,7 +13,8 @@ interface GraphProps { showLines?: boolean; showPoints?: boolean; showBars?: boolean; - size?: { width: number; height: number }; + width: number; + height: number; } export class Graph extends PureComponent { @@ -24,16 +24,10 @@ export class Graph extends PureComponent { showBars: false, }; - element: any; + element: HTMLElement; - componentDidUpdate(prevProps: GraphProps) { - if ( - prevProps.timeSeries !== this.props.timeSeries || - prevProps.timeRange !== this.props.timeRange || - prevProps.size !== this.props.size - ) { - this.draw(); - } + componentDidUpdate() { + this.draw(); } componentDidMount() { @@ -41,13 +35,13 @@ export class Graph extends PureComponent { } draw() { - const { size, timeSeries, timeRange, showLines, showBars, showPoints } = this.props; + const { width, timeSeries, timeRange, showLines, showBars, showPoints } = this.props; - if (!size) { + if (!width) { return; } - const ticks = (size.width || 0) / 100; + const ticks = width / 100; const min = timeRange.from.valueOf(); const max = timeRange.to.valueOf(); @@ -98,6 +92,7 @@ export class Graph extends PureComponent { }; try { + console.log('Graph render'); $.plot(this.element, timeSeries, flotOptions); } catch (err) { console.log('Graph rendering error', err, flotOptions, timeSeries); @@ -139,4 +134,4 @@ function time_format(ticks, min, max) { return '%H:%M'; } -export default withSize()(Graph); +export default Graph; diff --git a/public/sass/pages/_dashboard.scss b/public/sass/pages/_dashboard.scss index 79fe0b2569b..cffbd28597e 100644 --- a/public/sass/pages/_dashboard.scss +++ b/public/sass/pages/_dashboard.scss @@ -43,6 +43,7 @@ div.flot-text { position: relative; border-radius: 3px; height: 100%; + width: 100%; &.panel-transparent { background-color: transparent; @@ -60,6 +61,10 @@ div.flot-text { &--is-editing { height: auto; } + + &--absolute { + position: absolute; + } } .panel-content { diff --git a/yarn.lock b/yarn.lock index 4c7bbdd130c..400a432492c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -25,6 +25,13 @@ esutils "^2.0.2" js-tokens "^4.0.0" +"@babel/runtime@^7.1.2": + version "7.1.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.1.5.tgz#4170907641cf1f61508f563ece3725150cc6fe39" + integrity sha512-xKnPpXG/pvK1B90JkwwxSGii90rQGKtzcMt2gI5G6+M0REXaq6rOHsGC2ay6/d0Uje7zzvSzjEzfR3ENhFlrfA== + dependencies: + regenerator-runtime "^0.12.0" + "@babel/types@^7.0.0": version "7.1.2" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.1.2.tgz#183e7952cf6691628afdc2e2b90d03240bac80c0" @@ -2624,7 +2631,7 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -classnames@2.x, classnames@^2.2.5, classnames@^2.2.6: +classnames@2.x, classnames@^2.2.3, classnames@^2.2.5, classnames@^2.2.6: version "2.2.6" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== @@ -4163,6 +4170,13 @@ dom-css@^2.0.0: prefix-style "2.0.1" to-camel-case "1.0.0" +"dom-helpers@^2.4.0 || ^3.0.0": + version "3.4.0" + resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.4.0.tgz#e9b369700f959f62ecde5a6babde4bccd9169af8" + integrity sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA== + dependencies: + "@babel/runtime" "^7.1.2" + dom-helpers@^3.3.1: version "3.3.1" resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6" @@ -8431,7 +8445,7 @@ longest@^1.0.1: resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc= -loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.1, loose-envify@^1.4.0: +loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.3.0, loose-envify@^1.3.1, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== @@ -11413,6 +11427,18 @@ react-transition-group@^2.2.1: prop-types "^15.6.2" react-lifecycles-compat "^3.0.4" +react-virtualized@^9.21.0: + version "9.21.0" + resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.21.0.tgz#8267c40ffb48db35b242a36dea85edcf280a6506" + integrity sha512-duKD2HvO33mqld4EtQKm9H9H0p+xce1c++2D5xn59Ma7P8VT7CprfAe5hwjd1OGkyhqzOZiTMlTal7LxjH5yBQ== + dependencies: + babel-runtime "^6.26.0" + classnames "^2.2.3" + dom-helpers "^2.4.0 || ^3.0.0" + loose-envify "^1.3.0" + prop-types "^15.6.0" + react-lifecycles-compat "^3.0.4" + react@^16.5.0: version "16.5.2" resolved "https://registry.yarnpkg.com/react/-/react-16.5.2.tgz#19f6b444ed139baa45609eee6dc3d318b3895d42" @@ -11686,6 +11712,11 @@ regenerator-runtime@^0.11.0: resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9" integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg== +regenerator-runtime@^0.12.0: + version "0.12.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.12.1.tgz#fa1a71544764c036f8c49b13a08b2594c9f8a0de" + integrity sha512-odxIc1/vDlo4iZcfXqRYFj0vpXFNoGdKMAUieAlFYO6m/nl5e9KR/beGf41z4a1FI+aQgtjhuaSlDxQ0hmkrHg== + regenerator-transform@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.10.1.tgz#1e4996837231da8b7f3cf4114d71b5691a0680dd"