mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Dashboard: Move some plugin & panel state to redux (#22052)
* WIP: dashboard panel redux * Progress * Progress * Changing plugin type * Progress * Updated * Progess * Fixed timing issue * Updated * Fixed unit tests * Fixed issue in dashboard page * Updated test
This commit is contained in:
parent
258b507179
commit
49407987fe
@ -1,12 +1,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { shallow } from 'enzyme';
|
import { shallow } from 'enzyme';
|
||||||
import { AddPanelWidget, Props } from './AddPanelWidget';
|
import { AddPanelWidgetUnconnected as AddPanelWidget, Props } from './AddPanelWidget';
|
||||||
import { DashboardModel, PanelModel } from '../../state';
|
import { DashboardModel, PanelModel } from '../../state';
|
||||||
|
|
||||||
const setup = (propOverrides?: object) => {
|
const setup = (propOverrides?: object) => {
|
||||||
const props: Props = {
|
const props: Props = {
|
||||||
dashboard: {} as DashboardModel,
|
dashboard: {} as DashboardModel,
|
||||||
panel: {} as PanelModel,
|
panel: {} as PanelModel,
|
||||||
|
addPanelToDashboard: jest.fn() as any,
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.assign(props, propOverrides);
|
Object.assign(props, propOverrides);
|
||||||
|
@ -3,28 +3,36 @@ import React from 'react';
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import { LocationUpdate } from '@grafana/runtime';
|
import { LocationUpdate } from '@grafana/runtime';
|
||||||
import { e2e } from '@grafana/e2e';
|
import { e2e } from '@grafana/e2e';
|
||||||
|
import { connect, MapDispatchToProps } from 'react-redux';
|
||||||
// Utils
|
// Utils
|
||||||
import config from 'app/core/config';
|
import config from 'app/core/config';
|
||||||
import store from 'app/core/store';
|
import store from 'app/core/store';
|
||||||
// Store
|
// Store
|
||||||
import { store as reduxStore } from 'app/store/store';
|
import { store as reduxStore } from 'app/store/store';
|
||||||
import { updateLocation } from 'app/core/actions';
|
import { updateLocation } from 'app/core/actions';
|
||||||
|
import { addPanelToDashboard } from 'app/features/dashboard/state/reducers';
|
||||||
// Types
|
// Types
|
||||||
import { DashboardModel, PanelModel } from '../../state';
|
import { DashboardModel, PanelModel } from '../../state';
|
||||||
import { LS_PANEL_COPY_KEY } from 'app/core/constants';
|
import { LS_PANEL_COPY_KEY } from 'app/core/constants';
|
||||||
|
|
||||||
export type PanelPluginInfo = { id: any; defaults: { gridPos: { w: any; h: any }; title: any } };
|
export type PanelPluginInfo = { id: any; defaults: { gridPos: { w: any; h: any }; title: any } };
|
||||||
|
|
||||||
export interface Props {
|
export interface OwnProps {
|
||||||
panel: PanelModel;
|
panel: PanelModel;
|
||||||
dashboard: DashboardModel;
|
dashboard: DashboardModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface DispatchProps {
|
||||||
|
addPanelToDashboard: typeof addPanelToDashboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Props = OwnProps & DispatchProps;
|
||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
copiedPanelPlugins: any[];
|
copiedPanelPlugins: any[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AddPanelWidget extends React.Component<Props, State> {
|
export class AddPanelWidgetUnconnected extends React.Component<Props, State> {
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
this.handleCloseAddPanel = this.handleCloseAddPanel.bind(this);
|
this.handleCloseAddPanel = this.handleCloseAddPanel.bind(this);
|
||||||
@ -188,3 +196,7 @@ export class AddPanelWidget extends React.Component<Props, State> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mapDispatchToProps: MapDispatchToProps<DispatchProps, OwnProps> = { addPanelToDashboard };
|
||||||
|
|
||||||
|
export const AddPanelWidget = connect(null, mapDispatchToProps)(AddPanelWidgetUnconnected);
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
mockToolkitActionCreatorWithoutPayload,
|
mockToolkitActionCreatorWithoutPayload,
|
||||||
ToolkitActionCreatorWithoutPayloadMockType,
|
ToolkitActionCreatorWithoutPayloadMockType,
|
||||||
} from 'test/core/redux/mocks';
|
} from 'test/core/redux/mocks';
|
||||||
import { DashboardInitPhase, DashboardRouteInfo, MutableDashboard } from 'app/types';
|
import { DashboardInitPhase, DashboardRouteInfo } from 'app/types';
|
||||||
import { notifyApp, updateLocation } from 'app/core/actions';
|
import { notifyApp, updateLocation } from 'app/core/actions';
|
||||||
|
|
||||||
jest.mock('app/features/dashboard/components/DashboardSettings/SettingsCtrl', () => ({}));
|
jest.mock('app/features/dashboard/components/DashboardSettings/SettingsCtrl', () => ({}));
|
||||||
@ -215,7 +215,7 @@ describe('DashboardPage', () => {
|
|||||||
it('should set scrollTop to 0', () => {
|
it('should set scrollTop to 0', () => {
|
||||||
expect(ctx.wrapper).not.toBe(null);
|
expect(ctx.wrapper).not.toBe(null);
|
||||||
expect(ctx.wrapper?.state()).not.toBe(null);
|
expect(ctx.wrapper?.state()).not.toBe(null);
|
||||||
expect(ctx.wrapper?.state().scrollTop).toBe(0);
|
expect(ctx.wrapper?.state().updateScrollTop).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should add panel widget to dashboard panels', () => {
|
it('should add panel widget to dashboard panels', () => {
|
||||||
@ -272,7 +272,7 @@ describe('DashboardPage', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
dashboard: {
|
dashboard: {
|
||||||
getModel: () => null as MutableDashboard,
|
getModel: () => null as DashboardModel,
|
||||||
},
|
},
|
||||||
} as any);
|
} as any);
|
||||||
|
|
||||||
@ -290,7 +290,7 @@ describe('DashboardPage', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
dashboard: {
|
dashboard: {
|
||||||
getModel: () => null as MutableDashboard,
|
getModel: () => null as DashboardModel,
|
||||||
},
|
},
|
||||||
} as any);
|
} as any);
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ export interface State {
|
|||||||
isFullscreen: boolean;
|
isFullscreen: boolean;
|
||||||
fullscreenPanel: PanelModel | null;
|
fullscreenPanel: PanelModel | null;
|
||||||
scrollTop: number;
|
scrollTop: number;
|
||||||
updateScrollTop: number;
|
updateScrollTop?: number;
|
||||||
rememberScrollTop: number;
|
rememberScrollTop: number;
|
||||||
showLoadingState: boolean;
|
showLoadingState: boolean;
|
||||||
}
|
}
|
||||||
@ -75,7 +75,6 @@ export class DashboardPage extends PureComponent<Props, State> {
|
|||||||
showLoadingState: false,
|
showLoadingState: false,
|
||||||
fullscreenPanel: null,
|
fullscreenPanel: null,
|
||||||
scrollTop: 0,
|
scrollTop: 0,
|
||||||
updateScrollTop: null,
|
|
||||||
rememberScrollTop: 0,
|
rememberScrollTop: 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -127,19 +126,19 @@ export class DashboardPage extends PureComponent<Props, State> {
|
|||||||
|
|
||||||
// Sync url state with model
|
// Sync url state with model
|
||||||
if (urlFullscreen !== dashboard.meta.fullscreen || urlEdit !== dashboard.meta.isEditing) {
|
if (urlFullscreen !== dashboard.meta.fullscreen || urlEdit !== dashboard.meta.isEditing) {
|
||||||
if (!isNaN(parseInt(urlPanelId, 10))) {
|
if (urlPanelId && !isNaN(parseInt(urlPanelId, 10))) {
|
||||||
this.onEnterFullscreen();
|
this.onEnterFullscreen(dashboard, urlPanelId);
|
||||||
} else {
|
} else {
|
||||||
this.onLeaveFullscreen();
|
this.onLeaveFullscreen(dashboard);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onEnterFullscreen() {
|
onEnterFullscreen(dashboard: DashboardModel, urlPanelId: string) {
|
||||||
const { dashboard, urlEdit, urlFullscreen, urlPanelId } = this.props;
|
const { urlEdit, urlFullscreen } = this.props;
|
||||||
|
|
||||||
const panelId = parseInt(urlPanelId, 10);
|
|
||||||
|
|
||||||
|
const panelId = parseInt(urlPanelId!, 10);
|
||||||
|
dashboard;
|
||||||
// need to expand parent row if this panel is inside a row
|
// need to expand parent row if this panel is inside a row
|
||||||
dashboard.expandParentRowFor(panelId);
|
dashboard.expandParentRowFor(panelId);
|
||||||
|
|
||||||
@ -148,7 +147,7 @@ export class DashboardPage extends PureComponent<Props, State> {
|
|||||||
if (panel) {
|
if (panel) {
|
||||||
dashboard.setViewMode(panel, urlFullscreen, urlEdit);
|
dashboard.setViewMode(panel, urlFullscreen, urlEdit);
|
||||||
this.setState({
|
this.setState({
|
||||||
isEditing: urlEdit && dashboard.meta.canEdit,
|
isEditing: urlEdit && dashboard.meta.canEdit === true,
|
||||||
isFullscreen: urlFullscreen,
|
isFullscreen: urlFullscreen,
|
||||||
fullscreenPanel: panel,
|
fullscreenPanel: panel,
|
||||||
rememberScrollTop: this.state.scrollTop,
|
rememberScrollTop: this.state.scrollTop,
|
||||||
@ -159,9 +158,7 @@ export class DashboardPage extends PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onLeaveFullscreen() {
|
onLeaveFullscreen(dashboard: DashboardModel) {
|
||||||
const { dashboard } = this.props;
|
|
||||||
|
|
||||||
if (this.state.fullscreenPanel) {
|
if (this.state.fullscreenPanel) {
|
||||||
dashboard.setViewMode(this.state.fullscreenPanel, false, false);
|
dashboard.setViewMode(this.state.fullscreenPanel, false, false);
|
||||||
}
|
}
|
||||||
@ -181,7 +178,7 @@ export class DashboardPage extends PureComponent<Props, State> {
|
|||||||
|
|
||||||
triggerPanelsRendering() {
|
triggerPanelsRendering() {
|
||||||
try {
|
try {
|
||||||
this.props.dashboard.render();
|
this.props.dashboard!.render();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
this.props.notifyApp(createErrorNotification(`Panel rendering error`, err));
|
this.props.notifyApp(createErrorNotification(`Panel rendering error`, err));
|
||||||
@ -226,7 +223,7 @@ export class DashboardPage extends PureComponent<Props, State> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// scroll to top after adding panel
|
// scroll to top after adding panel
|
||||||
this.setState({ scrollTop: 0 });
|
this.setState({ updateScrollTop: 0 });
|
||||||
};
|
};
|
||||||
|
|
||||||
renderSlowInitState() {
|
renderSlowInitState() {
|
||||||
|
@ -113,7 +113,6 @@ exports[`DashboardPage Dashboard init completed Should render dashboard grid 1`
|
|||||||
autoHideTimeout={200}
|
autoHideTimeout={200}
|
||||||
className="custom-scrollbar--page"
|
className="custom-scrollbar--page"
|
||||||
hideTracksWhenNotNeeded={false}
|
hideTracksWhenNotNeeded={false}
|
||||||
scrollTop={null}
|
|
||||||
setScrollTop={[Function]}
|
setScrollTop={[Function]}
|
||||||
updateAfterMountMs={500}
|
updateAfterMountMs={500}
|
||||||
>
|
>
|
||||||
@ -449,7 +448,6 @@ exports[`DashboardPage When dashboard has editview url state should render setti
|
|||||||
autoHideTimeout={200}
|
autoHideTimeout={200}
|
||||||
className="custom-scrollbar--page"
|
className="custom-scrollbar--page"
|
||||||
hideTracksWhenNotNeeded={false}
|
hideTracksWhenNotNeeded={false}
|
||||||
scrollTop={null}
|
|
||||||
setScrollTop={[Function]}
|
setScrollTop={[Function]}
|
||||||
updateAfterMountMs={500}
|
updateAfterMountMs={500}
|
||||||
>
|
>
|
||||||
|
@ -6,6 +6,10 @@ import classNames from 'classnames';
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import sizeMe from 'react-sizeme';
|
import sizeMe from 'react-sizeme';
|
||||||
|
|
||||||
|
// Components
|
||||||
|
import { AddPanelWidget } from '../components/AddPanelWidget';
|
||||||
|
import { DashboardRow } from '../components/DashboardRow';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT } from 'app/core/constants';
|
import { GRID_CELL_HEIGHT, GRID_CELL_VMARGIN, GRID_COLUMN_COUNT } from 'app/core/constants';
|
||||||
import { DashboardPanel } from './DashboardPanel';
|
import { DashboardPanel } from './DashboardPanel';
|
||||||
@ -102,6 +106,7 @@ export class DashboardGrid extends PureComponent<Props> {
|
|||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { dashboard } = this.props;
|
const { dashboard } = this.props;
|
||||||
|
|
||||||
dashboard.on(panelAdded, this.triggerForceUpdate);
|
dashboard.on(panelAdded, this.triggerForceUpdate);
|
||||||
dashboard.on(panelRemoved, this.triggerForceUpdate);
|
dashboard.on(panelRemoved, this.triggerForceUpdate);
|
||||||
dashboard.on(CoreEvents.repeatsProcessed, this.triggerForceUpdate);
|
dashboard.on(CoreEvents.repeatsProcessed, this.triggerForceUpdate);
|
||||||
@ -173,7 +178,6 @@ export class DashboardGrid extends PureComponent<Props> {
|
|||||||
for (const panel of this.props.dashboard.panels) {
|
for (const panel of this.props.dashboard.panels) {
|
||||||
panel.resizeDone();
|
panel.resizeDone();
|
||||||
}
|
}
|
||||||
this.forceUpdate();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
onViewModeChanged = () => {
|
onViewModeChanged = () => {
|
||||||
@ -241,10 +245,12 @@ export class DashboardGrid extends PureComponent<Props> {
|
|||||||
|
|
||||||
renderPanels() {
|
renderPanels() {
|
||||||
const panelElements = [];
|
const panelElements = [];
|
||||||
|
|
||||||
for (const panel of this.props.dashboard.panels) {
|
for (const panel of this.props.dashboard.panels) {
|
||||||
const panelClasses = classNames({ 'react-grid-item--fullscreen': panel.fullscreen });
|
const panelClasses = classNames({ 'react-grid-item--fullscreen': panel.fullscreen });
|
||||||
const id = panel.id.toString();
|
const id = panel.id.toString();
|
||||||
panel.isInView = this.isInView(panel);
|
panel.isInView = this.isInView(panel);
|
||||||
|
|
||||||
panelElements.push(
|
panelElements.push(
|
||||||
<div
|
<div
|
||||||
key={id}
|
key={id}
|
||||||
@ -254,6 +260,24 @@ export class DashboardGrid extends PureComponent<Props> {
|
|||||||
this.panelRef[id] = elem;
|
this.panelRef[id] = elem;
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{this.renderPanel(panel)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return panelElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPanel(panel: PanelModel) {
|
||||||
|
if (panel.type === 'row') {
|
||||||
|
return <DashboardRow panel={panel} dashboard={this.props.dashboard} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (panel.type === 'add-panel') {
|
||||||
|
return <AddPanelWidget panel={panel} dashboard={this.props.dashboard} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
<DashboardPanel
|
<DashboardPanel
|
||||||
panel={panel}
|
panel={panel}
|
||||||
dashboard={this.props.dashboard}
|
dashboard={this.props.dashboard}
|
||||||
@ -261,13 +285,9 @@ export class DashboardGrid extends PureComponent<Props> {
|
|||||||
isFullscreen={panel.fullscreen}
|
isFullscreen={panel.fullscreen}
|
||||||
isInView={panel.isInView}
|
isInView={panel.isInView}
|
||||||
/>
|
/>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return panelElements;
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { dashboard, isFullscreen } = this.props;
|
const { dashboard, isFullscreen } = this.props;
|
||||||
|
|
||||||
|
@ -2,23 +2,23 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import AutoSizer from 'react-virtualized-auto-sizer';
|
import AutoSizer from 'react-virtualized-auto-sizer';
|
||||||
|
import { connect, MapStateToProps, MapDispatchToProps } from 'react-redux';
|
||||||
// Utils & Services
|
|
||||||
import { importPanelPlugin } from 'app/features/plugins/plugin_loader';
|
|
||||||
|
|
||||||
// Components
|
// Components
|
||||||
import { AddPanelWidget } from '../components/AddPanelWidget';
|
|
||||||
import { DashboardRow } from '../components/DashboardRow';
|
|
||||||
import { PanelChrome } from './PanelChrome';
|
import { PanelChrome } from './PanelChrome';
|
||||||
import { PanelEditor } from '../panel_editor/PanelEditor';
|
import { PanelEditor } from '../panel_editor/PanelEditor';
|
||||||
import { PanelResizer } from './PanelResizer';
|
import { PanelResizer } from './PanelResizer';
|
||||||
import { PanelChromeAngular } from './PanelChromeAngular';
|
import { PanelChromeAngular } from './PanelChromeAngular';
|
||||||
|
|
||||||
|
// Actions
|
||||||
|
import { initDashboardPanel } from '../state/actions';
|
||||||
|
|
||||||
// Types
|
// Types
|
||||||
import { PanelModel, DashboardModel } from '../state';
|
import { PanelModel, DashboardModel } from '../state';
|
||||||
import { PanelPluginMeta, PanelPlugin } from '@grafana/data';
|
import { StoreState } from 'app/types';
|
||||||
|
import { PanelPlugin } from '@grafana/data';
|
||||||
|
|
||||||
export interface Props {
|
export interface OwnProps {
|
||||||
panel: PanelModel;
|
panel: PanelModel;
|
||||||
dashboard: DashboardModel;
|
dashboard: DashboardModel;
|
||||||
isEditing: boolean;
|
isEditing: boolean;
|
||||||
@ -27,12 +27,21 @@ export interface Props {
|
|||||||
isInView: boolean;
|
isInView: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ConnectedProps {
|
||||||
|
plugin?: PanelPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DispatchProps {
|
||||||
|
initDashboardPanel: typeof initDashboardPanel;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Props = OwnProps & ConnectedProps & DispatchProps;
|
||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
plugin: PanelPlugin;
|
|
||||||
isLazy: boolean;
|
isLazy: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class DashboardPanel extends PureComponent<Props, State> {
|
export class DashboardPanelUnconnected extends PureComponent<Props, State> {
|
||||||
element: HTMLElement;
|
element: HTMLElement;
|
||||||
specialPanels: { [key: string]: Function } = {};
|
specialPanels: { [key: string]: Function } = {};
|
||||||
|
|
||||||
@ -40,56 +49,15 @@ export class DashboardPanel extends PureComponent<Props, State> {
|
|||||||
super(props);
|
super(props);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
plugin: null,
|
|
||||||
isLazy: !props.isInView,
|
isLazy: !props.isInView,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.specialPanels['row'] = this.renderRow.bind(this);
|
|
||||||
this.specialPanels['add-panel'] = this.renderAddPanel.bind(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
isSpecial(pluginId: string) {
|
|
||||||
return this.specialPanels[pluginId];
|
|
||||||
}
|
|
||||||
|
|
||||||
renderRow() {
|
|
||||||
return <DashboardRow panel={this.props.panel} dashboard={this.props.dashboard} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderAddPanel() {
|
|
||||||
return <AddPanelWidget panel={this.props.panel} dashboard={this.props.dashboard} />;
|
|
||||||
}
|
|
||||||
|
|
||||||
onPluginTypeChange = (plugin: PanelPluginMeta) => {
|
|
||||||
this.loadPlugin(plugin.id);
|
|
||||||
};
|
|
||||||
|
|
||||||
async loadPlugin(pluginId: string) {
|
|
||||||
if (this.isSpecial(pluginId)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { panel } = this.props;
|
|
||||||
|
|
||||||
// handle plugin loading & changing of plugin type
|
|
||||||
if (!this.state.plugin || this.state.plugin.meta.id !== pluginId) {
|
|
||||||
const plugin = await importPanelPlugin(pluginId);
|
|
||||||
|
|
||||||
if (panel.type !== pluginId) {
|
|
||||||
panel.changePlugin(plugin);
|
|
||||||
} else {
|
|
||||||
panel.pluginLoaded(plugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.setState({ plugin });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.loadPlugin(this.props.panel.type);
|
this.props.initDashboardPanel(this.props.panel);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps: Props, prevState: State) {
|
componentDidUpdate() {
|
||||||
if (this.state.isLazy && this.props.isInView) {
|
if (this.state.isLazy && this.props.isInView) {
|
||||||
this.setState({ isLazy: false });
|
this.setState({ isLazy: false });
|
||||||
}
|
}
|
||||||
@ -104,8 +72,7 @@ export class DashboardPanel extends PureComponent<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
renderPanel() {
|
renderPanel() {
|
||||||
const { dashboard, panel, isFullscreen, isInView, isInEditMode } = this.props;
|
const { dashboard, panel, isFullscreen, isInView, isInEditMode, plugin } = this.props;
|
||||||
const { plugin } = this.state;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AutoSizer>
|
<AutoSizer>
|
||||||
@ -146,12 +113,8 @@ export class DashboardPanel extends PureComponent<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { panel, dashboard, isFullscreen, isEditing } = this.props;
|
const { panel, dashboard, isFullscreen, isEditing, plugin } = this.props;
|
||||||
const { plugin, isLazy } = this.state;
|
const { isLazy } = this.state;
|
||||||
|
|
||||||
if (this.isSpecial(panel.type)) {
|
|
||||||
return this.specialPanels[panel.type]();
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we have not loaded plugin exports yet, wait
|
// if we have not loaded plugin exports yet, wait
|
||||||
if (!plugin) {
|
if (!plugin) {
|
||||||
@ -190,15 +153,18 @@ export class DashboardPanel extends PureComponent<Props, State> {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{panel.isEditing && (
|
{panel.isEditing && <PanelEditor panel={panel} plugin={plugin} dashboard={dashboard} />}
|
||||||
<PanelEditor
|
|
||||||
panel={panel}
|
|
||||||
plugin={plugin}
|
|
||||||
dashboard={dashboard}
|
|
||||||
onPluginTypeChange={this.onPluginTypeChange}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mapStateToProps: MapStateToProps<ConnectedProps, OwnProps, StoreState> = (state, props) => {
|
||||||
|
return {
|
||||||
|
plugin: state.plugins.panels[props.panel.type],
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const mapDispatchToProps: MapDispatchToProps<DispatchProps, OwnProps> = { initDashboardPanel };
|
||||||
|
|
||||||
|
export const DashboardPanel = connect(mapStateToProps, mapDispatchToProps)(DashboardPanelUnconnected);
|
||||||
|
@ -115,8 +115,6 @@ export class PanelChromeAngular extends PureComponent<Props, State> {
|
|||||||
this.cleanUpAngularPanel();
|
this.cleanUpAngularPanel();
|
||||||
this.loadAngularPanel();
|
this.loadAngularPanel();
|
||||||
}
|
}
|
||||||
|
|
||||||
this.loadAngularPanel();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loadAngularPanel() {
|
loadAngularPanel() {
|
||||||
|
@ -49,7 +49,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
|
|||||||
id="panel-1"
|
id="panel-1"
|
||||||
key="1"
|
key="1"
|
||||||
>
|
>
|
||||||
<DashboardPanel
|
<Component
|
||||||
dashboard={
|
dashboard={
|
||||||
DashboardModel {
|
DashboardModel {
|
||||||
"annotations": Object {
|
"annotations": Object {
|
||||||
@ -292,7 +292,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
|
|||||||
id="panel-2"
|
id="panel-2"
|
||||||
key="2"
|
key="2"
|
||||||
>
|
>
|
||||||
<DashboardPanel
|
<Component
|
||||||
dashboard={
|
dashboard={
|
||||||
DashboardModel {
|
DashboardModel {
|
||||||
"annotations": Object {
|
"annotations": Object {
|
||||||
@ -535,7 +535,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
|
|||||||
id="panel-3"
|
id="panel-3"
|
||||||
key="3"
|
key="3"
|
||||||
>
|
>
|
||||||
<DashboardPanel
|
<Component
|
||||||
dashboard={
|
dashboard={
|
||||||
DashboardModel {
|
DashboardModel {
|
||||||
"annotations": Object {
|
"annotations": Object {
|
||||||
@ -778,7 +778,7 @@ exports[`DashboardGrid Can render dashboard grid Should render 1`] = `
|
|||||||
id="panel-4"
|
id="panel-4"
|
||||||
key="4"
|
key="4"
|
||||||
>
|
>
|
||||||
<DashboardPanel
|
<Component
|
||||||
dashboard={
|
dashboard={
|
||||||
DashboardModel {
|
DashboardModel {
|
||||||
"annotations": Object {
|
"annotations": Object {
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import React, { PureComponent } from 'react';
|
import React, { PureComponent } from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { hot } from 'react-hot-loader';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { Tooltip } from '@grafana/ui';
|
import { Tooltip } from '@grafana/ui';
|
||||||
import { PanelPlugin, PanelPluginMeta } from '@grafana/data';
|
import { PanelPlugin, PanelPluginMeta } from '@grafana/data';
|
||||||
@ -16,18 +15,19 @@ import { DashboardModel } from '../state/DashboardModel';
|
|||||||
import { StoreState } from '../../../types';
|
import { StoreState } from '../../../types';
|
||||||
import { panelEditorCleanUp, PanelEditorTab, PanelEditorTabIds } from './state/reducers';
|
import { panelEditorCleanUp, PanelEditorTab, PanelEditorTabIds } from './state/reducers';
|
||||||
import { changePanelEditorTab, refreshPanelEditor } from './state/actions';
|
import { changePanelEditorTab, refreshPanelEditor } from './state/actions';
|
||||||
|
import { changePanelPlugin } from '../state/actions';
|
||||||
import { getActiveTabAndTabs } from './state/selectors';
|
import { getActiveTabAndTabs } from './state/selectors';
|
||||||
|
|
||||||
interface PanelEditorProps {
|
interface PanelEditorProps {
|
||||||
panel: PanelModel;
|
panel: PanelModel;
|
||||||
dashboard: DashboardModel;
|
dashboard: DashboardModel;
|
||||||
plugin: PanelPlugin;
|
plugin: PanelPlugin;
|
||||||
onPluginTypeChange: (newType: PanelPluginMeta) => void;
|
|
||||||
activeTab: PanelEditorTabIds;
|
activeTab: PanelEditorTabIds;
|
||||||
tabs: PanelEditorTab[];
|
tabs: PanelEditorTab[];
|
||||||
refreshPanelEditor: typeof refreshPanelEditor;
|
refreshPanelEditor: typeof refreshPanelEditor;
|
||||||
panelEditorCleanUp: typeof panelEditorCleanUp;
|
panelEditorCleanUp: typeof panelEditorCleanUp;
|
||||||
changePanelEditorTab: typeof changePanelEditorTab;
|
changePanelEditorTab: typeof changePanelEditorTab;
|
||||||
|
changePanelPlugin: typeof changePanelPlugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
class UnConnectedPanelEditor extends PureComponent<PanelEditorProps> {
|
class UnConnectedPanelEditor extends PureComponent<PanelEditorProps> {
|
||||||
@ -63,9 +63,7 @@ class UnConnectedPanelEditor extends PureComponent<PanelEditorProps> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
onPluginTypeChange = (newType: PanelPluginMeta) => {
|
onPluginTypeChange = (newType: PanelPluginMeta) => {
|
||||||
const { onPluginTypeChange } = this.props;
|
this.props.changePanelPlugin(this.props.panel, newType.id);
|
||||||
onPluginTypeChange(newType);
|
|
||||||
|
|
||||||
this.refreshFromState(newType);
|
this.refreshFromState(newType);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -108,11 +106,10 @@ class UnConnectedPanelEditor extends PureComponent<PanelEditorProps> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const mapStateToProps = (state: StoreState) => getActiveTabAndTabs(state.location, state.panelEditor);
|
const mapStateToProps = (state: StoreState) => getActiveTabAndTabs(state.location, state.panelEditor);
|
||||||
|
const mapDispatchToProps = { refreshPanelEditor, panelEditorCleanUp, changePanelEditorTab, changePanelPlugin };
|
||||||
|
|
||||||
const mapDispatchToProps = { refreshPanelEditor, panelEditorCleanUp, changePanelEditorTab };
|
export const PanelEditor = connect(mapStateToProps, mapDispatchToProps)(UnConnectedPanelEditor);
|
||||||
|
|
||||||
export const PanelEditor = hot(module)(connect(mapStateToProps, mapDispatchToProps)(UnConnectedPanelEditor));
|
|
||||||
|
|
||||||
interface TabItemParams {
|
interface TabItemParams {
|
||||||
tab: PanelEditorTab;
|
tab: PanelEditorTab;
|
||||||
|
@ -92,6 +92,7 @@ const defaults: any = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export class PanelModel {
|
export class PanelModel {
|
||||||
|
/* persisted id, used in URL to identify a panel */
|
||||||
id: number;
|
id: number;
|
||||||
gridPos: GridPos;
|
gridPos: GridPos;
|
||||||
type: string;
|
type: string;
|
||||||
@ -280,6 +281,7 @@ export class PanelModel {
|
|||||||
|
|
||||||
if (plugin.panel && plugin.onPanelMigration) {
|
if (plugin.panel && plugin.onPanelMigration) {
|
||||||
const version = getPluginVersion(plugin);
|
const version = getPluginVersion(plugin);
|
||||||
|
|
||||||
if (version !== this.pluginVersion) {
|
if (version !== this.pluginVersion) {
|
||||||
this.options = plugin.onPanelMigration(this);
|
this.options = plugin.onPanelMigration(this);
|
||||||
this.pluginVersion = version;
|
this.pluginVersion = version;
|
||||||
|
@ -3,10 +3,12 @@ import { getBackendSrv } from '@grafana/runtime';
|
|||||||
import { createSuccessNotification } from 'app/core/copy/appNotification';
|
import { createSuccessNotification } from 'app/core/copy/appNotification';
|
||||||
// Actions
|
// Actions
|
||||||
import { loadPluginDashboards } from '../../plugins/state/actions';
|
import { loadPluginDashboards } from '../../plugins/state/actions';
|
||||||
import { loadDashboardPermissions } from './reducers';
|
import { loadDashboardPermissions, dashboardPanelTypeChanged } from './reducers';
|
||||||
import { notifyApp } from 'app/core/actions';
|
import { notifyApp } from 'app/core/actions';
|
||||||
|
import { loadPanelPlugin } from 'app/features/plugins/state/actions';
|
||||||
// Types
|
// Types
|
||||||
import { DashboardAcl, DashboardAclUpdateDTO, NewDashboardAclItem, PermissionLevel, ThunkResult } from 'app/types';
|
import { DashboardAcl, DashboardAclUpdateDTO, NewDashboardAclItem, PermissionLevel, ThunkResult } from 'app/types';
|
||||||
|
import { PanelModel } from './PanelModel';
|
||||||
|
|
||||||
export function getDashboardPermissions(id: number): ThunkResult<void> {
|
export function getDashboardPermissions(id: number): ThunkResult<void> {
|
||||||
return async dispatch => {
|
return async dispatch => {
|
||||||
@ -108,3 +110,35 @@ export function removeDashboard(uri: string): ThunkResult<void> {
|
|||||||
dispatch(loadPluginDashboards());
|
dispatch(loadPluginDashboards());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function initDashboardPanel(panel: PanelModel): ThunkResult<void> {
|
||||||
|
return async (dispatch, getStore) => {
|
||||||
|
let plugin = getStore().plugins.panels[panel.type];
|
||||||
|
|
||||||
|
if (!plugin) {
|
||||||
|
plugin = await dispatch(loadPanelPlugin(panel.type));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!panel.plugin) {
|
||||||
|
panel.pluginLoaded(plugin);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function changePanelPlugin(panel: PanelModel, pluginId: string): ThunkResult<void> {
|
||||||
|
return async (dispatch, getStore) => {
|
||||||
|
// ignore action is no change
|
||||||
|
if (panel.type === pluginId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let plugin = getStore().plugins.panels[pluginId];
|
||||||
|
|
||||||
|
if (!plugin) {
|
||||||
|
plugin = await dispatch(loadPanelPlugin(pluginId));
|
||||||
|
}
|
||||||
|
|
||||||
|
panel.changePlugin(plugin);
|
||||||
|
dispatch(dashboardPanelTypeChanged({ panelId: panel.id, pluginId }));
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -32,7 +32,15 @@ describe('dashboard reducer', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
state = dashboardReducer(initialState, dashboardInitFetching());
|
state = dashboardReducer(initialState, dashboardInitFetching());
|
||||||
state = dashboardReducer(state, dashboardInitSlow());
|
state = dashboardReducer(state, dashboardInitSlow());
|
||||||
state = dashboardReducer(state, dashboardInitCompleted(new DashboardModel({ title: 'My dashboard' })));
|
state = dashboardReducer(
|
||||||
|
state,
|
||||||
|
dashboardInitCompleted(
|
||||||
|
new DashboardModel({
|
||||||
|
title: 'My dashboard',
|
||||||
|
panels: [{ id: 1 }, { id: 2 }],
|
||||||
|
})
|
||||||
|
)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should set model', async () => {
|
it('should set model', async () => {
|
||||||
@ -42,6 +50,11 @@ describe('dashboard reducer', () => {
|
|||||||
it('should set reset isInitSlow', async () => {
|
it('should set reset isInitSlow', async () => {
|
||||||
expect(state.isInitSlow).toBe(false);
|
expect(state.isInitSlow).toBe(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should create panel state', async () => {
|
||||||
|
expect(state.panels['1']).toBeDefined();
|
||||||
|
expect(state.panels['2']).toBeDefined();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('dashboardInitFailed', () => {
|
describe('dashboardInitFailed', () => {
|
||||||
|
@ -3,13 +3,13 @@ import {
|
|||||||
DashboardInitPhase,
|
DashboardInitPhase,
|
||||||
DashboardState,
|
DashboardState,
|
||||||
DashboardAclDTO,
|
DashboardAclDTO,
|
||||||
MutableDashboard,
|
|
||||||
DashboardInitError,
|
DashboardInitError,
|
||||||
QueriesToUpdateOnDashboardLoad,
|
QueriesToUpdateOnDashboardLoad,
|
||||||
} from 'app/types';
|
} from 'app/types';
|
||||||
import { processAclItems } from 'app/core/utils/acl';
|
import { processAclItems } from 'app/core/utils/acl';
|
||||||
import { panelEditorReducer } from '../panel_editor/state/reducers';
|
import { panelEditorReducer } from '../panel_editor/state/reducers';
|
||||||
import { DashboardModel } from './DashboardModel';
|
import { DashboardModel } from './DashboardModel';
|
||||||
|
import { PanelModel } from './PanelModel';
|
||||||
|
|
||||||
export const initialState: DashboardState = {
|
export const initialState: DashboardState = {
|
||||||
initPhase: DashboardInitPhase.NotStarted,
|
initPhase: DashboardInitPhase.NotStarted,
|
||||||
@ -17,6 +17,8 @@ export const initialState: DashboardState = {
|
|||||||
getModel: () => null,
|
getModel: () => null,
|
||||||
permissions: [],
|
permissions: [],
|
||||||
modifiedQueries: null,
|
modifiedQueries: null,
|
||||||
|
panels: {},
|
||||||
|
initError: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
const dashbardSlice = createSlice({
|
const dashbardSlice = createSlice({
|
||||||
@ -35,10 +37,16 @@ const dashbardSlice = createSlice({
|
|||||||
dashboardInitSlow: (state, action: PayloadAction) => {
|
dashboardInitSlow: (state, action: PayloadAction) => {
|
||||||
state.isInitSlow = true;
|
state.isInitSlow = true;
|
||||||
},
|
},
|
||||||
dashboardInitCompleted: (state, action: PayloadAction<MutableDashboard>) => {
|
dashboardInitCompleted: (state, action: PayloadAction<DashboardModel>) => {
|
||||||
state.getModel = () => action.payload;
|
state.getModel = () => action.payload;
|
||||||
state.initPhase = DashboardInitPhase.Completed;
|
state.initPhase = DashboardInitPhase.Completed;
|
||||||
state.isInitSlow = false;
|
state.isInitSlow = false;
|
||||||
|
|
||||||
|
for (const panel of action.payload.panels) {
|
||||||
|
state.panels[panel.id] = {
|
||||||
|
pluginId: panel.type,
|
||||||
|
};
|
||||||
|
}
|
||||||
},
|
},
|
||||||
dashboardInitFailed: (state, action: PayloadAction<DashboardInitError>) => {
|
dashboardInitFailed: (state, action: PayloadAction<DashboardInitError>) => {
|
||||||
state.initPhase = DashboardInitPhase.Failed;
|
state.initPhase = DashboardInitPhase.Failed;
|
||||||
@ -49,7 +57,7 @@ const dashbardSlice = createSlice({
|
|||||||
},
|
},
|
||||||
cleanUpDashboard: (state, action: PayloadAction) => {
|
cleanUpDashboard: (state, action: PayloadAction) => {
|
||||||
if (state.getModel()) {
|
if (state.getModel()) {
|
||||||
state.getModel().destroy();
|
state.getModel()!.destroy();
|
||||||
state.getModel = () => null;
|
state.getModel = () => null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,9 +71,22 @@ const dashbardSlice = createSlice({
|
|||||||
clearDashboardQueriesToUpdateOnLoad: (state, action: PayloadAction) => {
|
clearDashboardQueriesToUpdateOnLoad: (state, action: PayloadAction) => {
|
||||||
state.modifiedQueries = null;
|
state.modifiedQueries = null;
|
||||||
},
|
},
|
||||||
|
dashboardPanelTypeChanged: (state, action: PayloadAction<DashboardPanelTypeChangedPayload>) => {
|
||||||
|
state.panels[action.payload.panelId] = { pluginId: action.payload.pluginId };
|
||||||
|
},
|
||||||
|
addPanelToDashboard: (state, action: PayloadAction<AddPanelPayload>) => {},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export interface DashboardPanelTypeChangedPayload {
|
||||||
|
panelId: number;
|
||||||
|
pluginId: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AddPanelPayload {
|
||||||
|
panel: PanelModel;
|
||||||
|
}
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
loadDashboardPermissions,
|
loadDashboardPermissions,
|
||||||
dashboardInitFetching,
|
dashboardInitFetching,
|
||||||
@ -76,6 +97,8 @@ export const {
|
|||||||
cleanUpDashboard,
|
cleanUpDashboard,
|
||||||
setDashboardQueriesToUpdateOnLoad,
|
setDashboardQueriesToUpdateOnLoad,
|
||||||
clearDashboardQueriesToUpdateOnLoad,
|
clearDashboardQueriesToUpdateOnLoad,
|
||||||
|
dashboardPanelTypeChanged,
|
||||||
|
addPanelToDashboard,
|
||||||
} = dashbardSlice.actions;
|
} = dashbardSlice.actions;
|
||||||
|
|
||||||
export const dashboardReducer = dashbardSlice.reducer;
|
export const dashboardReducer = dashbardSlice.reducer;
|
||||||
|
@ -225,21 +225,24 @@ import { getPanelPluginNotFound, getPanelPluginLoadError } from '../dashboard/da
|
|||||||
import { GenericDataSourcePlugin } from '../datasources/settings/PluginSettings';
|
import { GenericDataSourcePlugin } from '../datasources/settings/PluginSettings';
|
||||||
|
|
||||||
interface PanelCache {
|
interface PanelCache {
|
||||||
[key: string]: PanelPlugin;
|
[key: string]: Promise<PanelPlugin>;
|
||||||
}
|
}
|
||||||
const panelCache: PanelCache = {};
|
const panelCache: PanelCache = {};
|
||||||
|
|
||||||
export function importPanelPlugin(id: string): Promise<PanelPlugin> {
|
export function importPanelPlugin(id: string): Promise<PanelPlugin> {
|
||||||
const loaded = panelCache[id];
|
const loaded = panelCache[id];
|
||||||
|
|
||||||
if (loaded) {
|
if (loaded) {
|
||||||
return Promise.resolve(loaded);
|
return loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
const meta = config.panels[id];
|
const meta = config.panels[id];
|
||||||
|
|
||||||
if (!meta) {
|
if (!meta) {
|
||||||
return Promise.resolve(getPanelPluginNotFound(id));
|
return Promise.resolve(getPanelPluginNotFound(id));
|
||||||
}
|
}
|
||||||
|
|
||||||
return importPluginModule(meta.module)
|
panelCache[id] = importPluginModule(meta.module)
|
||||||
.then(pluginExports => {
|
.then(pluginExports => {
|
||||||
if (pluginExports.plugin) {
|
if (pluginExports.plugin) {
|
||||||
return pluginExports.plugin as PanelPlugin;
|
return pluginExports.plugin as PanelPlugin;
|
||||||
@ -252,11 +255,13 @@ export function importPanelPlugin(id: string): Promise<PanelPlugin> {
|
|||||||
})
|
})
|
||||||
.then(plugin => {
|
.then(plugin => {
|
||||||
plugin.meta = meta;
|
plugin.meta = meta;
|
||||||
return (panelCache[meta.id] = plugin);
|
return plugin;
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
// TODO, maybe a different error plugin
|
// TODO, maybe a different error plugin
|
||||||
console.warn('Error loading panel plugin: ' + id, err);
|
console.warn('Error loading panel plugin: ' + id, err);
|
||||||
return getPanelPluginLoadError(meta, err);
|
return getPanelPluginLoadError(meta, err);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return panelCache[id];
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import { getBackendSrv } from '@grafana/runtime';
|
import { getBackendSrv } from '@grafana/runtime';
|
||||||
|
import { PanelPlugin } from '@grafana/data';
|
||||||
import { ThunkResult } from 'app/types';
|
import { ThunkResult } from 'app/types';
|
||||||
import { pluginDashboardsLoad, pluginDashboardsLoaded, pluginsLoaded } from './reducers';
|
import { pluginDashboardsLoad, pluginDashboardsLoaded, pluginsLoaded, panelPluginLoaded } from './reducers';
|
||||||
|
import { importPanelPlugin } from 'app/features/plugins/plugin_loader';
|
||||||
|
|
||||||
export function loadPlugins(): ThunkResult<void> {
|
export function loadPlugins(): ThunkResult<void> {
|
||||||
return async dispatch => {
|
return async dispatch => {
|
||||||
@ -18,3 +19,20 @@ export function loadPluginDashboards(): ThunkResult<void> {
|
|||||||
dispatch(pluginDashboardsLoaded(response));
|
dispatch(pluginDashboardsLoaded(response));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function loadPanelPlugin(pluginId: string): ThunkResult<Promise<PanelPlugin>> {
|
||||||
|
return async (dispatch, getStore) => {
|
||||||
|
let plugin = getStore().plugins.panels[pluginId];
|
||||||
|
|
||||||
|
if (!plugin) {
|
||||||
|
plugin = await importPanelPlugin(pluginId);
|
||||||
|
|
||||||
|
// second check to protect against raise condition
|
||||||
|
if (!getStore().plugins.panels[pluginId]) {
|
||||||
|
dispatch(panelPluginLoaded(plugin));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return plugin;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
import { createSlice, PayloadAction } from '@reduxjs/toolkit';
|
||||||
import { PluginMeta } from '@grafana/data';
|
import { PluginMeta, PanelPlugin } from '@grafana/data';
|
||||||
import { PluginsState } from 'app/types';
|
import { PluginsState } from 'app/types';
|
||||||
import { LayoutMode, LayoutModes } from '../../../core/components/LayoutSelector/LayoutSelector';
|
import { LayoutMode, LayoutModes } from '../../../core/components/LayoutSelector/LayoutSelector';
|
||||||
import { PluginDashboard } from '../../../types/plugins';
|
import { PluginDashboard } from '../../../types/plugins';
|
||||||
@ -11,26 +11,33 @@ export const initialState: PluginsState = {
|
|||||||
hasFetched: false,
|
hasFetched: false,
|
||||||
dashboards: [],
|
dashboards: [],
|
||||||
isLoadingPluginDashboards: false,
|
isLoadingPluginDashboards: false,
|
||||||
|
panels: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
const pluginsSlice = createSlice({
|
const pluginsSlice = createSlice({
|
||||||
name: 'plugins',
|
name: 'plugins',
|
||||||
initialState,
|
initialState,
|
||||||
reducers: {
|
reducers: {
|
||||||
pluginsLoaded: (state, action: PayloadAction<PluginMeta[]>): PluginsState => {
|
pluginsLoaded: (state, action: PayloadAction<PluginMeta[]>) => {
|
||||||
return { ...state, hasFetched: true, plugins: action.payload };
|
state.hasFetched = true;
|
||||||
|
state.plugins = action.payload;
|
||||||
},
|
},
|
||||||
setPluginsSearchQuery: (state, action: PayloadAction<string>): PluginsState => {
|
setPluginsSearchQuery: (state, action: PayloadAction<string>) => {
|
||||||
return { ...state, searchQuery: action.payload };
|
state.searchQuery = action.payload;
|
||||||
},
|
},
|
||||||
setPluginsLayoutMode: (state, action: PayloadAction<LayoutMode>): PluginsState => {
|
setPluginsLayoutMode: (state, action: PayloadAction<LayoutMode>) => {
|
||||||
return { ...state, layoutMode: action.payload };
|
state.layoutMode = action.payload;
|
||||||
},
|
},
|
||||||
pluginDashboardsLoad: (state, action: PayloadAction<undefined>): PluginsState => {
|
pluginDashboardsLoad: (state, action: PayloadAction<undefined>) => {
|
||||||
return { ...state, dashboards: [], isLoadingPluginDashboards: true };
|
state.isLoadingPluginDashboards = true;
|
||||||
|
state.dashboards = [];
|
||||||
},
|
},
|
||||||
pluginDashboardsLoaded: (state, action: PayloadAction<PluginDashboard[]>): PluginsState => {
|
pluginDashboardsLoaded: (state, action: PayloadAction<PluginDashboard[]>) => {
|
||||||
return { ...state, dashboards: action.payload, isLoadingPluginDashboards: false };
|
state.isLoadingPluginDashboards = false;
|
||||||
|
state.dashboards = action.payload;
|
||||||
|
},
|
||||||
|
panelPluginLoaded: (state, action: PayloadAction<PanelPlugin>) => {
|
||||||
|
state.panels[action.payload.meta!.id] = action.payload;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@ -41,6 +48,7 @@ export const {
|
|||||||
pluginDashboardsLoaded,
|
pluginDashboardsLoaded,
|
||||||
setPluginsLayoutMode,
|
setPluginsLayoutMode,
|
||||||
setPluginsSearchQuery,
|
setPluginsSearchQuery,
|
||||||
|
panelPluginLoaded,
|
||||||
} = pluginsSlice.actions;
|
} = pluginsSlice.actions;
|
||||||
|
|
||||||
export const pluginsReducer = pluginsSlice.reducer;
|
export const pluginsReducer = pluginsSlice.reducer;
|
||||||
|
@ -1,11 +1,7 @@
|
|||||||
import { DashboardAcl } from './acl';
|
import { DashboardAcl } from './acl';
|
||||||
import { DataQuery } from '@grafana/data';
|
import { DataQuery } from '@grafana/data';
|
||||||
|
import { AngularComponent } from '@grafana/runtime';
|
||||||
export interface MutableDashboard {
|
import { DashboardModel } from 'app/features/dashboard/state/DashboardModel';
|
||||||
title: string;
|
|
||||||
meta: DashboardMeta;
|
|
||||||
destroy: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DashboardDTO {
|
export interface DashboardDTO {
|
||||||
redirectUri?: string;
|
redirectUri?: string;
|
||||||
@ -65,18 +61,24 @@ export interface DashboardInitError {
|
|||||||
|
|
||||||
export const KIOSK_MODE_TV = 'tv';
|
export const KIOSK_MODE_TV = 'tv';
|
||||||
export type KioskUrlValue = 'tv' | '1' | true;
|
export type KioskUrlValue = 'tv' | '1' | true;
|
||||||
export type GetMutableDashboardModelFn = () => MutableDashboard | null;
|
export type GetMutableDashboardModelFn = () => DashboardModel | null;
|
||||||
|
|
||||||
export interface QueriesToUpdateOnDashboardLoad {
|
export interface QueriesToUpdateOnDashboardLoad {
|
||||||
panelId: number;
|
panelId: number;
|
||||||
queries: DataQuery[];
|
queries: DataQuery[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PanelState {
|
||||||
|
pluginId: string;
|
||||||
|
angularPanel?: AngularComponent;
|
||||||
|
}
|
||||||
|
|
||||||
export interface DashboardState {
|
export interface DashboardState {
|
||||||
getModel: GetMutableDashboardModelFn;
|
getModel: GetMutableDashboardModelFn;
|
||||||
initPhase: DashboardInitPhase;
|
initPhase: DashboardInitPhase;
|
||||||
isInitSlow: boolean;
|
isInitSlow: boolean;
|
||||||
initError?: DashboardInitError;
|
initError: DashboardInitError | null;
|
||||||
permissions: DashboardAcl[] | null;
|
permissions: DashboardAcl[] | null;
|
||||||
modifiedQueries: QueriesToUpdateOnDashboardLoad | null;
|
modifiedQueries: QueriesToUpdateOnDashboardLoad | null;
|
||||||
|
panels: { [id: string]: PanelState };
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { PluginMeta } from '@grafana/data';
|
import { PluginMeta } from '@grafana/data';
|
||||||
|
import { PanelPlugin } from '@grafana/data';
|
||||||
|
|
||||||
export interface PluginDashboard {
|
export interface PluginDashboard {
|
||||||
dashboardId: number;
|
dashboardId: number;
|
||||||
@ -16,6 +17,10 @@ export interface PluginDashboard {
|
|||||||
title: string;
|
title: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PanelPluginsIndex {
|
||||||
|
[id: string]: PanelPlugin;
|
||||||
|
}
|
||||||
|
|
||||||
export interface PluginsState {
|
export interface PluginsState {
|
||||||
plugins: PluginMeta[];
|
plugins: PluginMeta[];
|
||||||
searchQuery: string;
|
searchQuery: string;
|
||||||
@ -23,6 +28,7 @@ export interface PluginsState {
|
|||||||
hasFetched: boolean;
|
hasFetched: boolean;
|
||||||
dashboards: PluginDashboard[];
|
dashboards: PluginDashboard[];
|
||||||
isLoadingPluginDashboards: boolean;
|
isLoadingPluginDashboards: boolean;
|
||||||
|
panels: PanelPluginsIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface VariableQueryProps {
|
export interface VariableQueryProps {
|
||||||
|
442
report.20200209.125304.14262.0.001.json
Normal file
442
report.20200209.125304.14262.0.001.json
Normal file
@ -0,0 +1,442 @@
|
|||||||
|
{
|
||||||
|
"header": {
|
||||||
|
"reportVersion": 1,
|
||||||
|
"event": "Allocation failed - JavaScript heap out of memory",
|
||||||
|
"trigger": "FatalError",
|
||||||
|
"filename": "report.20200209.125304.14262.0.001.json",
|
||||||
|
"dumpEventTime": "2020-02-09T12:53:04Z",
|
||||||
|
"dumpEventTimeStamp": "1581249184230",
|
||||||
|
"processId": 14262,
|
||||||
|
"cwd": "/home/torkelo/dev/go/src/github.com/grafana/grafana",
|
||||||
|
"commandLine": [
|
||||||
|
"/home/torkelo/.nvm/versions/node/v12.13.1/bin/node",
|
||||||
|
"/home/torkelo/.config/coc/extensions/node_modules/coc-tsserver/bin/tsserverForkStart",
|
||||||
|
"/home/torkelo/dev/go/src/github.com/grafana/grafana/node_modules/typescript/lib/tsserver.js",
|
||||||
|
"--allowLocalPluginLoads",
|
||||||
|
"--useInferredProjectPerProjectRoot",
|
||||||
|
"--cancellationPipeName",
|
||||||
|
"/tmp/coc-nvim-tscancellation-2615e1ca6ecfc7575540.sock*",
|
||||||
|
"--npmLocation",
|
||||||
|
"\"/home/torkelo/.nvm/versions/node/v12.13.1/bin/npm\"",
|
||||||
|
"--noGetErrOnBackgroundUpdate",
|
||||||
|
"--validateDefaultNpmLocation"
|
||||||
|
],
|
||||||
|
"nodejsVersion": "v12.13.1",
|
||||||
|
"glibcVersionRuntime": "2.27",
|
||||||
|
"glibcVersionCompiler": "2.17",
|
||||||
|
"wordSize": 64,
|
||||||
|
"arch": "x64",
|
||||||
|
"platform": "linux",
|
||||||
|
"componentVersions": {
|
||||||
|
"node": "12.13.1",
|
||||||
|
"v8": "7.7.299.13-node.16",
|
||||||
|
"uv": "1.33.1",
|
||||||
|
"zlib": "1.2.11",
|
||||||
|
"brotli": "1.0.7",
|
||||||
|
"ares": "1.15.0",
|
||||||
|
"modules": "72",
|
||||||
|
"nghttp2": "1.39.2",
|
||||||
|
"napi": "5",
|
||||||
|
"llhttp": "1.1.4",
|
||||||
|
"http_parser": "2.8.0",
|
||||||
|
"openssl": "1.1.1d",
|
||||||
|
"cldr": "35.1",
|
||||||
|
"icu": "64.2",
|
||||||
|
"tz": "2019c",
|
||||||
|
"unicode": "12.1"
|
||||||
|
},
|
||||||
|
"release": {
|
||||||
|
"name": "node",
|
||||||
|
"lts": "Erbium",
|
||||||
|
"headersUrl": "https://nodejs.org/download/release/v12.13.1/node-v12.13.1-headers.tar.gz",
|
||||||
|
"sourceUrl": "https://nodejs.org/download/release/v12.13.1/node-v12.13.1.tar.gz"
|
||||||
|
},
|
||||||
|
"osName": "Linux",
|
||||||
|
"osRelease": "4.15.0-76-generic",
|
||||||
|
"osVersion": "#86-Ubuntu SMP Fri Jan 17 17:24:28 UTC 2020",
|
||||||
|
"osMachine": "x86_64",
|
||||||
|
"cpus": [
|
||||||
|
{
|
||||||
|
"model": "Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz",
|
||||||
|
"speed": 4700,
|
||||||
|
"user": 23271600,
|
||||||
|
"nice": 70900,
|
||||||
|
"sys": 8208000,
|
||||||
|
"idle": 703176900,
|
||||||
|
"irq": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz",
|
||||||
|
"speed": 4702,
|
||||||
|
"user": 25425500,
|
||||||
|
"nice": 68900,
|
||||||
|
"sys": 8484100,
|
||||||
|
"idle": 700815000,
|
||||||
|
"irq": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz",
|
||||||
|
"speed": 4700,
|
||||||
|
"user": 22825900,
|
||||||
|
"nice": 43000,
|
||||||
|
"sys": 8405200,
|
||||||
|
"idle": 703772400,
|
||||||
|
"irq": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz",
|
||||||
|
"speed": 4700,
|
||||||
|
"user": 23125500,
|
||||||
|
"nice": 53200,
|
||||||
|
"sys": 8344900,
|
||||||
|
"idle": 703502500,
|
||||||
|
"irq": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz",
|
||||||
|
"speed": 4703,
|
||||||
|
"user": 22918700,
|
||||||
|
"nice": 38500,
|
||||||
|
"sys": 8401200,
|
||||||
|
"idle": 703666600,
|
||||||
|
"irq": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz",
|
||||||
|
"speed": 4700,
|
||||||
|
"user": 22942200,
|
||||||
|
"nice": 39600,
|
||||||
|
"sys": 8651200,
|
||||||
|
"idle": 703181200,
|
||||||
|
"irq": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz",
|
||||||
|
"speed": 4700,
|
||||||
|
"user": 23148200,
|
||||||
|
"nice": 40700,
|
||||||
|
"sys": 8578000,
|
||||||
|
"idle": 702772300,
|
||||||
|
"irq": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"model": "Intel(R) Core(TM) i7-9700K CPU @ 3.60GHz",
|
||||||
|
"speed": 4700,
|
||||||
|
"user": 23511200,
|
||||||
|
"nice": 41300,
|
||||||
|
"sys": 8625200,
|
||||||
|
"idle": 702592500,
|
||||||
|
"irq": 0
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"networkInterfaces": [
|
||||||
|
{
|
||||||
|
"name": "lo",
|
||||||
|
"internal": true,
|
||||||
|
"mac": "00:00:00:00:00:00",
|
||||||
|
"address": "127.0.0.1",
|
||||||
|
"netmask": "255.0.0.0",
|
||||||
|
"family": "IPv4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "enp3s0",
|
||||||
|
"internal": false,
|
||||||
|
"mac": "04:92:26:d6:b9:7b",
|
||||||
|
"address": "192.168.1.189",
|
||||||
|
"netmask": "255.255.255.0",
|
||||||
|
"family": "IPv4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "lo",
|
||||||
|
"internal": true,
|
||||||
|
"mac": "00:00:00:00:00:00",
|
||||||
|
"address": "::1",
|
||||||
|
"netmask": "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
|
||||||
|
"family": "IPv6",
|
||||||
|
"scopeid": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "enp3s0",
|
||||||
|
"internal": false,
|
||||||
|
"mac": "04:92:26:d6:b9:7b",
|
||||||
|
"address": "fe80::e4f0:42a8:23d4:1a5a",
|
||||||
|
"netmask": "ffff:ffff:ffff:ffff::",
|
||||||
|
"family": "IPv6",
|
||||||
|
"scopeid": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"host": "tlodesk19"
|
||||||
|
},
|
||||||
|
"javascriptStack": {
|
||||||
|
"message": "No stack.",
|
||||||
|
"stack": ["Unavailable."]
|
||||||
|
},
|
||||||
|
"nativeStack": [
|
||||||
|
{
|
||||||
|
"pc": "0x0000000000b04935",
|
||||||
|
"symbol": "report::TriggerNodeReport(v8::Isolate*, node::Environment*, char const*, char const*, std::string const&, v8::Local<v8::String>) [/home/torkelo/.nvm/versions/node/v12.13.1/bin/node]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": "0x00000000009db9e3",
|
||||||
|
"symbol": "node::OnFatalError(char const*, char const*) [/home/torkelo/.nvm/versions/node/v12.13.1/bin/node]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": "0x0000000000b39f1e",
|
||||||
|
"symbol": "v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [/home/torkelo/.nvm/versions/node/v12.13.1/bin/node]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": "0x0000000000b3a299",
|
||||||
|
"symbol": "v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [/home/torkelo/.nvm/versions/node/v12.13.1/bin/node]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": "0x0000000000ce5635",
|
||||||
|
"symbol": " [/home/torkelo/.nvm/versions/node/v12.13.1/bin/node]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": "0x0000000000ce5cc6",
|
||||||
|
"symbol": "v8::internal::Heap::RecomputeLimits(v8::internal::GarbageCollector) [/home/torkelo/.nvm/versions/node/v12.13.1/bin/node]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": "0x0000000000cf1b5a",
|
||||||
|
"symbol": "v8::internal::Heap::PerformGarbageCollection(v8::internal::GarbageCollector, v8::GCCallbackFlags) [/home/torkelo/.nvm/versions/node/v12.13.1/bin/node]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": "0x0000000000cf2a65",
|
||||||
|
"symbol": "v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [/home/torkelo/.nvm/versions/node/v12.13.1/bin/node]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": "0x0000000000cf5478",
|
||||||
|
"symbol": "v8::internal::Heap::AllocateRawWithRetryOrFail(int, v8::internal::AllocationType, v8::internal::AllocationAlignment) [/home/torkelo/.nvm/versions/node/v12.13.1/bin/node]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": "0x0000000000cbbda7",
|
||||||
|
"symbol": "v8::internal::Factory::NewFillerObject(int, bool, v8::internal::AllocationType) [/home/torkelo/.nvm/versions/node/v12.13.1/bin/node]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": "0x0000000000ff1e0b",
|
||||||
|
"symbol": "v8::internal::Runtime_AllocateInYoungGeneration(int, unsigned long*, v8::internal::Isolate*) [/home/torkelo/.nvm/versions/node/v12.13.1/bin/node]"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pc": "0x0000000001374fd9",
|
||||||
|
"symbol": " [/home/torkelo/.nvm/versions/node/v12.13.1/bin/node]"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"javascriptHeap": {
|
||||||
|
"totalMemory": 2174230528,
|
||||||
|
"totalCommittedMemory": 2173217000,
|
||||||
|
"usedMemory": 2095966360,
|
||||||
|
"availableMemory": 58693288,
|
||||||
|
"memoryLimit": 2197815296,
|
||||||
|
"heapSpaces": {
|
||||||
|
"read_only_space": {
|
||||||
|
"memorySize": 262144,
|
||||||
|
"committedMemory": 32568,
|
||||||
|
"capacity": 261872,
|
||||||
|
"used": 32296,
|
||||||
|
"available": 229576
|
||||||
|
},
|
||||||
|
"new_space": {
|
||||||
|
"memorySize": 33554432,
|
||||||
|
"committedMemory": 33552568,
|
||||||
|
"capacity": 16759808,
|
||||||
|
"used": 105024,
|
||||||
|
"available": 16654784
|
||||||
|
},
|
||||||
|
"old_space": {
|
||||||
|
"memorySize": 2043260928,
|
||||||
|
"committedMemory": 2043093624,
|
||||||
|
"capacity": 2001580720,
|
||||||
|
"used": 2001291056,
|
||||||
|
"available": 289664
|
||||||
|
},
|
||||||
|
"code_space": {
|
||||||
|
"memorySize": 9076736,
|
||||||
|
"committedMemory": 8605856,
|
||||||
|
"capacity": 8646656,
|
||||||
|
"used": 7471968,
|
||||||
|
"available": 1174688
|
||||||
|
},
|
||||||
|
"map_space": {
|
||||||
|
"memorySize": 1314816,
|
||||||
|
"committedMemory": 1170912,
|
||||||
|
"capacity": 793680,
|
||||||
|
"used": 793680,
|
||||||
|
"available": 0
|
||||||
|
},
|
||||||
|
"large_object_space": {
|
||||||
|
"memorySize": 86384640,
|
||||||
|
"committedMemory": 86384640,
|
||||||
|
"capacity": 85955568,
|
||||||
|
"used": 85955568,
|
||||||
|
"available": 0
|
||||||
|
},
|
||||||
|
"code_large_object_space": {
|
||||||
|
"memorySize": 376832,
|
||||||
|
"committedMemory": 376832,
|
||||||
|
"capacity": 316768,
|
||||||
|
"used": 316768,
|
||||||
|
"available": 0
|
||||||
|
},
|
||||||
|
"new_large_object_space": {
|
||||||
|
"memorySize": 0,
|
||||||
|
"committedMemory": 0,
|
||||||
|
"capacity": 16759808,
|
||||||
|
"used": 0,
|
||||||
|
"available": 16759808
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"resourceUsage": {
|
||||||
|
"userCpuSeconds": 1662.02,
|
||||||
|
"kernelCpuSeconds": 64.5868,
|
||||||
|
"cpuConsumptionPercent": 25.4099,
|
||||||
|
"maxRss": 2328305664,
|
||||||
|
"pageFaults": {
|
||||||
|
"IORequired": 0,
|
||||||
|
"IONotRequired": 23472269
|
||||||
|
},
|
||||||
|
"fsActivity": {
|
||||||
|
"reads": 51752,
|
||||||
|
"writes": 260112
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"uvthreadResourceUsage": {
|
||||||
|
"userCpuSeconds": 1149.51,
|
||||||
|
"kernelCpuSeconds": 30.8777,
|
||||||
|
"cpuConsumptionPercent": 17.3714,
|
||||||
|
"fsActivity": {
|
||||||
|
"reads": 51752,
|
||||||
|
"writes": 260112
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libuv": [],
|
||||||
|
"environmentVariables": {
|
||||||
|
"COLORTERM": "truecolor",
|
||||||
|
"DBUS_SESSION_BUS_ADDRESS": "unix:path=/run/user/1000/bus",
|
||||||
|
"DEFAULTS_PATH": "/usr/share/gconf/i3.default.path",
|
||||||
|
"DESKTOP_SESSION": "i3",
|
||||||
|
"DISPLAY": ":0",
|
||||||
|
"EDITOR": "nvim",
|
||||||
|
"GDMSESSION": "i3",
|
||||||
|
"GNOME_TERMINAL_SCREEN": "/org/gnome/Terminal/screen/33c3a057_5c19_4624_a686_5ec5567f5784",
|
||||||
|
"GNOME_TERMINAL_SERVICE": ":1.11",
|
||||||
|
"GOPATH": "/home/torkelo/dev/go",
|
||||||
|
"GPG_AGENT_INFO": "/run/user/1000/gnupg/S.gpg-agent:0:1",
|
||||||
|
"GTK_MODULES": "gail:atk-bridge",
|
||||||
|
"HOME": "/home/torkelo",
|
||||||
|
"LANG": "sv_SE.UTF-8",
|
||||||
|
"LC_ADDRESS": "sv_SE.UTF-8",
|
||||||
|
"LC_ALL": "sv_SE.UTF-8",
|
||||||
|
"LC_COLLATE": "sv_SE.UTF-8",
|
||||||
|
"LC_CTYPE": "sv_SE.UTF-8",
|
||||||
|
"LC_IDENTIFICATION": "sv_SE.UTF-8",
|
||||||
|
"LC_MEASUREMENT": "sv_SE.UTF-8",
|
||||||
|
"LC_MESSAGES": "sv_SE.UTF-8",
|
||||||
|
"LC_MONETARY": "sv_SE.UTF-8",
|
||||||
|
"LC_NAME": "sv_SE.UTF-8",
|
||||||
|
"LC_NUMERIC": "sv_SE.UTF-8",
|
||||||
|
"LC_PAPER": "sv_SE.UTF-8",
|
||||||
|
"LC_TELEPHONE": "sv_SE.UTF-8",
|
||||||
|
"LC_TIME": "sv_SE.UTF-8",
|
||||||
|
"LESS": "-R",
|
||||||
|
"LOGNAME": "torkelo",
|
||||||
|
"LSCOLORS": "Gxfxcxdxbxegedabagacad",
|
||||||
|
"LS_COLORS": "rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:",
|
||||||
|
"MANDATORY_PATH": "/usr/share/gconf/i3.mandatory.path",
|
||||||
|
"NVM_BIN": "/home/torkelo/.nvm/versions/node/v12.13.1/bin",
|
||||||
|
"NVM_CD_FLAGS": "-q",
|
||||||
|
"NVM_DIR": "/home/torkelo/.nvm",
|
||||||
|
"OLDPWD": "/home/torkelo",
|
||||||
|
"PAGER": "less",
|
||||||
|
"PATH": "/home/torkelo/.pyenv/plugins/pyenv-virtualenv/shims:/home/torkelo/.pyenv/shims:/home/torkelo/.pyenv/plugins/pyenv-virtualenv/shims:/home/torkelo/.pyenv/shims:/home/torkelo/bin:/home/torkelo/.dotfiles/bins:/usr/local/bin:/home/torkelo/.pyenv/shims:/home/torkelo/.pyenv/plugins/pyenv-virtualenv/shims:/home/torkelo/.pyenv/shims:/home/torkelo/.pyenv/plugins/pyenv-virtualenv/shims:/home/torkelo/.pyenv/shims:/home/torkelo/.nvm/versions/node/v12.13.1/bin:/home/torkelo/bin:/home/torkelo/.dotfiles/bins:/usr/local/bin:/home/torkelo/.pyenv/shims:/home/torkelo/.local/bin:/home/torkelo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/usr/local/go/bin:/home/torkelo/go/bin:/home/torkelo/.pyenv/bin:/home/torkelo/.rvm/bin:/home/torkelo/.local/bin:/usr/local/go/bin:/home/torkelo/.cargo/bin:/home/torkelo/dev/go/bin:/home/torkelo/.fzf/bin:/home/torkelo/.rvm/bin:/home/torkelo/.local/bin:/usr/local/go/bin:/home/torkelo/.cargo/bin:/home/torkelo/dev/go/bin",
|
||||||
|
"PROJECTS": "/home/torkelo/dev",
|
||||||
|
"PWD": "/home/torkelo/dev/go/src/github.com/grafana/grafana",
|
||||||
|
"PYENV_SHELL": "zsh",
|
||||||
|
"PYENV_VIRTUALENV_INIT": "1",
|
||||||
|
"QT_ACCESSIBILITY": "1",
|
||||||
|
"SHELL": "/usr/bin/zsh",
|
||||||
|
"SHLVL": "2",
|
||||||
|
"SSH_AGENT_PID": "1732",
|
||||||
|
"SSH_AUTH_SOCK": "/tmp/ssh-rZxvFmTCg1Ge/agent.1642",
|
||||||
|
"TERM": "xterm-256color",
|
||||||
|
"TMUX": "/tmp/tmux-1000/default,3051,0",
|
||||||
|
"TMUX_PANE": "%0",
|
||||||
|
"USER": "torkelo",
|
||||||
|
"USERNAME": "torkelo",
|
||||||
|
"VIRTUAL_ENV_DISABLE_PROMPT": "1",
|
||||||
|
"VTE_VERSION": "5202",
|
||||||
|
"WINDOWPATH": "2",
|
||||||
|
"XAUTHORITY": "/run/user/1000/gdm/Xauthority",
|
||||||
|
"XDG_CONFIG_DIRS": "/etc/xdg/xdg-i3:/etc/xdg",
|
||||||
|
"XDG_CURRENT_DESKTOP": "i3",
|
||||||
|
"XDG_DATA_DIRS": "/usr/share/i3:/usr/local/share:/usr/share:/var/lib/snapd/desktop",
|
||||||
|
"XDG_RUNTIME_DIR": "/run/user/1000",
|
||||||
|
"XDG_SEAT": "seat0",
|
||||||
|
"XDG_SESSION_DESKTOP": "i3",
|
||||||
|
"XDG_SESSION_ID": "2",
|
||||||
|
"XDG_SESSION_TYPE": "x11",
|
||||||
|
"XDG_VTNR": "2",
|
||||||
|
"_": "/usr/bin/nvim",
|
||||||
|
"is_vim": "echo \"#{pane_current_command}\" | grep -iqE \"(^|\\/)g?(view|n?vim?x?)(diff)?$\"",
|
||||||
|
"VIMRUNTIME": "/usr/share/nvim/runtime",
|
||||||
|
"NVIM_LISTEN_ADDRESS": "/tmp/nvimV1ROJn/0",
|
||||||
|
"VIM": "/usr/share/nvim",
|
||||||
|
"MYVIMRC": "/home/torkelo/.config/nvim/init.vim",
|
||||||
|
"FZF_DEFAULT_COMMAND": "ag --hidden --ignore .git -g \"\"",
|
||||||
|
"VIMCONFIG": "/home/torkelo/.config/nvim",
|
||||||
|
"TSS_LOG": "-level verbose -file /tmp/coc-nvim-tsc.log",
|
||||||
|
"NODE_PATH": "/home/torkelo/dev/go/src/github.com/grafana/grafana/node_modules"
|
||||||
|
},
|
||||||
|
"userLimits": {
|
||||||
|
"core_file_size_blocks": {
|
||||||
|
"soft": 0,
|
||||||
|
"hard": "unlimited"
|
||||||
|
},
|
||||||
|
"data_seg_size_kbytes": {
|
||||||
|
"soft": "unlimited",
|
||||||
|
"hard": "unlimited"
|
||||||
|
},
|
||||||
|
"file_size_blocks": {
|
||||||
|
"soft": "unlimited",
|
||||||
|
"hard": "unlimited"
|
||||||
|
},
|
||||||
|
"max_locked_memory_bytes": {
|
||||||
|
"soft": 16777216,
|
||||||
|
"hard": 16777216
|
||||||
|
},
|
||||||
|
"max_memory_size_kbytes": {
|
||||||
|
"soft": "unlimited",
|
||||||
|
"hard": "unlimited"
|
||||||
|
},
|
||||||
|
"open_files": {
|
||||||
|
"soft": 4096,
|
||||||
|
"hard": 4096
|
||||||
|
},
|
||||||
|
"stack_size_bytes": {
|
||||||
|
"soft": 8388608,
|
||||||
|
"hard": "unlimited"
|
||||||
|
},
|
||||||
|
"cpu_time_seconds": {
|
||||||
|
"soft": "unlimited",
|
||||||
|
"hard": "unlimited"
|
||||||
|
},
|
||||||
|
"max_user_processes": {
|
||||||
|
"soft": 62634,
|
||||||
|
"hard": 62634
|
||||||
|
},
|
||||||
|
"virtual_memory_kbytes": {
|
||||||
|
"soft": "unlimited",
|
||||||
|
"hard": "unlimited"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"sharedObjects": [
|
||||||
|
"linux-vdso.so.1",
|
||||||
|
"/lib/x86_64-linux-gnu/libdl.so.2",
|
||||||
|
"/usr/lib/x86_64-linux-gnu/libstdc++.so.6",
|
||||||
|
"/lib/x86_64-linux-gnu/libm.so.6",
|
||||||
|
"/lib/x86_64-linux-gnu/libgcc_s.so.1",
|
||||||
|
"/lib/x86_64-linux-gnu/libpthread.so.0",
|
||||||
|
"/lib/x86_64-linux-gnu/libc.so.6",
|
||||||
|
"/lib64/ld-linux-x86-64.so.2"
|
||||||
|
]
|
||||||
|
}
|
@ -3,7 +3,7 @@
|
|||||||
echo -e "Collecting code stats (typescript errors & more)"
|
echo -e "Collecting code stats (typescript errors & more)"
|
||||||
|
|
||||||
|
|
||||||
ERROR_COUNT_LIMIT=1025
|
ERROR_COUNT_LIMIT=1005
|
||||||
DIRECTIVES_LIMIT=172
|
DIRECTIVES_LIMIT=172
|
||||||
CONTROLLERS_LIMIT=139
|
CONTROLLERS_LIMIT=139
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user