Commit 9fec2026 by Torkel Ödegaard Committed by GitHub

Merge pull request #14565 from grafana/panel-help-view

Panel help view
parents fdb48b7b 659b5a3c
import React, { PureComponent } from 'react';
import Remarkable from 'remarkable';
import { getBackendSrv } from '../../services/backend_srv';
import { PluginMeta } from 'app/types';
interface Props {
plugin: PluginMeta;
type: string;
}
interface State {
isError: boolean;
isLoading: boolean;
help: string;
}
export default class PluginHelp extends PureComponent<Props, State> {
state = {
isError: false,
isLoading: false,
help: '',
};
componentDidMount(): void {
this.loadHelp();
}
constructPlaceholderInfo = () => {
const { plugin } = this.props;
const markdown = new Remarkable();
const fallBack = markdown.render(
`## ${plugin.name} \n by _${plugin.info.author.name} (<${plugin.info.author.url}>)_\n\n${
plugin.info.description
}\n\n${
plugin.info.links
? `### Links \n ${plugin.info.links.map(link => {
return `${link.name}: <${link.url}>\n`;
})}`
: ''
}`
);
return fallBack;
};
loadHelp = () => {
const { plugin, type } = this.props;
this.setState({ isLoading: true });
getBackendSrv()
.get(`/api/plugins/${plugin.id}/markdown/${type}`)
.then(response => {
const markdown = new Remarkable();
const helpHtml = markdown.render(response);
if (response === '' && type === 'help') {
this.setState({
isError: false,
isLoading: false,
help: this.constructPlaceholderInfo(),
});
} else {
this.setState({
isError: false,
isLoading: false,
help: helpHtml,
});
}
})
.catch(() => {
this.setState({
isError: true,
isLoading: false,
});
});
};
render() {
const { type } = this.props;
const { isError, isLoading, help } = this.state;
if (isLoading) {
return <h2>Loading help...</h2>;
}
if (isError) {
return <h3>'Error occurred when loading help'</h3>;
}
if (type === 'panel_help' && help === '') {
}
return <div className="markdown-html" dangerouslySetInnerHTML={{ __html: help }} />;
}
}
// Libraries // Libraries
import React, { SFC, PureComponent } from 'react'; import React, { SFC, PureComponent } from 'react';
import Remarkable from 'remarkable';
import _ from 'lodash'; import _ from 'lodash';
// Components // Components
...@@ -22,6 +21,7 @@ import config from 'app/core/config'; ...@@ -22,6 +21,7 @@ import config from 'app/core/config';
import { PanelModel } from '../panel_model'; import { PanelModel } from '../panel_model';
import { DashboardModel } from '../dashboard_model'; import { DashboardModel } from '../dashboard_model';
import { DataSourceSelectItem, DataQuery } from 'app/types'; import { DataSourceSelectItem, DataQuery } from 'app/types';
import PluginHelp from '../../../core/components/PanelHelp/PluginHelp';
interface Props { interface Props {
panel: PanelModel; panel: PanelModel;
...@@ -128,43 +128,13 @@ export class QueriesTab extends PureComponent<Props, State> { ...@@ -128,43 +128,13 @@ export class QueriesTab extends PureComponent<Props, State> {
}); });
}; };
loadHelp = () => {
const { currentDS } = this.state;
const hasHelp = currentDS.meta.hasQueryHelp;
if (hasHelp) {
this.setState({
helpContent: <h3>Loading help...</h3>,
isLoadingHelp: true,
});
this.backendSrv
.get(`/api/plugins/${currentDS.meta.id}/markdown/query_help`)
.then(res => {
const md = new Remarkable();
const helpHtml = md.render(res);
this.setState({
helpContent: <div className="markdown-html" dangerouslySetInnerHTML={{ __html: helpHtml }} />,
isLoadingHelp: false,
});
})
.catch(() => {
this.setState({
helpContent: <h3>'Error occured when loading help'</h3>,
isLoadingHelp: false,
});
});
}
};
renderQueryInspector = () => { renderQueryInspector = () => {
const { panel } = this.props; const { panel } = this.props;
return <QueryInspector panel={panel} LoadingPlaceholder={LoadingPlaceholder} />; return <QueryInspector panel={panel} LoadingPlaceholder={LoadingPlaceholder} />;
}; };
renderHelp = () => { renderHelp = () => {
const { helpContent, isLoadingHelp } = this.state; return <PluginHelp plugin={this.state.currentDS.meta} type="query_help" />;
return isLoadingHelp ? <LoadingPlaceholder text="Loading help..." /> : helpContent;
}; };
onAddQuery = (query?: Partial<DataQuery>) => { onAddQuery = (query?: Partial<DataQuery>) => {
...@@ -244,7 +214,6 @@ export class QueriesTab extends PureComponent<Props, State> { ...@@ -244,7 +214,6 @@ export class QueriesTab extends PureComponent<Props, State> {
heading: 'Help', heading: 'Help',
icon: 'fa fa-question', icon: 'fa fa-question',
disabled: !hasQueryHelp, disabled: !hasQueryHelp,
onClick: this.loadHelp,
render: this.renderHelp, render: this.renderHelp,
}; };
......
...@@ -3,10 +3,12 @@ import React, { PureComponent } from 'react'; ...@@ -3,10 +3,12 @@ import React, { PureComponent } from 'react';
// Utils & Services // Utils & Services
import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader'; import { getAngularLoader, AngularComponent } from 'app/core/services/AngularLoader';
import { getDatasourceSrv } from '../../plugins/datasource_srv';
// Components // Components
import { EditorTabBody } from './EditorTabBody'; import { EditorTabBody } from './EditorTabBody';
import { VizTypePicker } from './VizTypePicker'; import { VizTypePicker } from './VizTypePicker';
import PluginHelp from 'app/core/components/PanelHelp/PluginHelp';
import { FadeIn } from 'app/core/components/Animations/FadeIn'; import { FadeIn } from 'app/core/components/Animations/FadeIn';
import { PanelOptionSection } from './PanelOptionSection'; import { PanelOptionSection } from './PanelOptionSection';
...@@ -14,6 +16,7 @@ import { PanelOptionSection } from './PanelOptionSection'; ...@@ -14,6 +16,7 @@ import { PanelOptionSection } from './PanelOptionSection';
import { PanelModel } from '../panel_model'; import { PanelModel } from '../panel_model';
import { DashboardModel } from '../dashboard_model'; import { DashboardModel } from '../dashboard_model';
import { PanelPlugin } from 'app/types/plugins'; import { PanelPlugin } from 'app/types/plugins';
import { DataSourceSelectItem } from 'app/types';
interface Props { interface Props {
panel: PanelModel; panel: PanelModel;
...@@ -24,6 +27,7 @@ interface Props { ...@@ -24,6 +27,7 @@ interface Props {
} }
interface State { interface State {
currentDataSource: DataSourceSelectItem;
isVizPickerOpen: boolean; isVizPickerOpen: boolean;
searchQuery: string; searchQuery: string;
} }
...@@ -32,13 +36,16 @@ export class VisualizationTab extends PureComponent<Props, State> { ...@@ -32,13 +36,16 @@ export class VisualizationTab extends PureComponent<Props, State> {
element: HTMLElement; element: HTMLElement;
angularOptions: AngularComponent; angularOptions: AngularComponent;
searchInput: HTMLElement; searchInput: HTMLElement;
dataSources: DataSourceSelectItem[] = getDatasourceSrv().getMetricSources();
constructor(props) { constructor(props) {
super(props); super(props);
const { panel } = props;
this.state = { this.state = {
isVizPickerOpen: false, isVizPickerOpen: false,
searchQuery: '', searchQuery: '',
currentDataSource: this.dataSources.find(datasource => datasource.value === panel.datasource),
}; };
} }
...@@ -198,12 +205,20 @@ export class VisualizationTab extends PureComponent<Props, State> { ...@@ -198,12 +205,20 @@ export class VisualizationTab extends PureComponent<Props, State> {
} }
}; };
renderHelp = () => <PluginHelp plugin={this.state.currentDataSource.meta} type="help" />;
render() { render() {
const { plugin } = this.props; const { plugin } = this.props;
const { isVizPickerOpen, searchQuery } = this.state; const { isVizPickerOpen, searchQuery } = this.state;
const pluginHelp = {
heading: 'Help',
icon: 'fa fa-question',
render: this.renderHelp,
};
return ( return (
<EditorTabBody heading="Visualization" renderToolbar={this.renderToolbar}> <EditorTabBody heading="Visualization" renderToolbar={this.renderToolbar} toolbarItems={[pluginHelp]}>
<> <>
<FadeIn in={isVizPickerOpen} duration={200} unmountOnExit={true}> <FadeIn in={isVizPickerOpen} duration={200} unmountOnExit={true}>
<VizTypePicker <VizTypePicker
......
...@@ -61,7 +61,10 @@ exports[`Render should render alpha info text 1`] = ` ...@@ -61,7 +61,10 @@ exports[`Render should render alpha info text 1`] = `
}, },
"description": "pretty decent plugin", "description": "pretty decent plugin",
"links": Array [ "links": Array [
"one link", Object {
"name": "project",
"url": "one link",
},
], ],
"logos": Object { "logos": Object {
"large": "large/logo", "large": "large/logo",
...@@ -160,7 +163,10 @@ exports[`Render should render beta info text 1`] = ` ...@@ -160,7 +163,10 @@ exports[`Render should render beta info text 1`] = `
}, },
"description": "pretty decent plugin", "description": "pretty decent plugin",
"links": Array [ "links": Array [
"one link", Object {
"name": "project",
"url": "one link",
},
], ],
"logos": Object { "logos": Object {
"large": "large/logo", "large": "large/logo",
...@@ -254,7 +260,10 @@ exports[`Render should render component 1`] = ` ...@@ -254,7 +260,10 @@ exports[`Render should render component 1`] = `
}, },
"description": "pretty decent plugin", "description": "pretty decent plugin",
"links": Array [ "links": Array [
"one link", Object {
"name": "project",
"url": "one link",
},
], ],
"logos": Object { "logos": Object {
"large": "large/logo", "large": "large/logo",
...@@ -353,7 +362,10 @@ exports[`Render should render is ready only message 1`] = ` ...@@ -353,7 +362,10 @@ exports[`Render should render is ready only message 1`] = `
}, },
"description": "pretty decent plugin", "description": "pretty decent plugin",
"links": Array [ "links": Array [
"one link", Object {
"name": "project",
"url": "one link",
},
], ],
"logos": Object { "logos": Object {
"large": "large/logo", "large": "large/logo",
......
...@@ -73,7 +73,7 @@ export function getDataSourceLoadingNav(pageName: string): NavModel { ...@@ -73,7 +73,7 @@ export function getDataSourceLoadingNav(pageName: string): NavModel {
url: '', url: '',
}, },
description: '', description: '',
links: [''], links: [{ name: '', url: '' }],
logos: { logos: {
large: '', large: '',
small: '', small: '',
......
...@@ -70,7 +70,7 @@ export const getMockPlugin = () => { ...@@ -70,7 +70,7 @@ export const getMockPlugin = () => {
url: 'url/to/GrafanaLabs', url: 'url/to/GrafanaLabs',
}, },
description: 'pretty decent plugin', description: 'pretty decent plugin',
links: ['one link'], links: [{ name: 'project', url: 'one link' }],
logos: { small: 'small/logo', large: 'large/logo' }, logos: { small: 'small/logo', large: 'large/logo' },
screenshots: [{ path: `screenshot` }], screenshots: [{ path: `screenshot` }],
updated: '2018-09-26', updated: '2018-09-26',
......
...@@ -57,13 +57,18 @@ export interface PluginInclude { ...@@ -57,13 +57,18 @@ export interface PluginInclude {
path: string; path: string;
} }
interface PluginMetaInfoLink {
name: string;
url: string;
}
export interface PluginMetaInfo { export interface PluginMetaInfo {
author: { author: {
name: string; name: string;
url?: string; url?: string;
}; };
description: string; description: string;
links: string[]; links: PluginMetaInfoLink[];
logos: { logos: {
large: string; large: string;
small: string; small: string;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment