Browse Source

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

Panel help view
Torkel Ödegaard 7 years ago
parent
commit
9fec202668

+ 96 - 0
public/app/core/components/PanelHelp/PluginHelp.tsx

@@ -0,0 +1,96 @@
+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 }} />;
+  }
+}

+ 2 - 33
public/app/features/dashboard/dashgrid/QueriesTab.tsx

@@ -1,6 +1,5 @@
 // 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';
 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> {
     });
     });
   };
   };
 
 
-  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 isLoadingHelp ? <LoadingPlaceholder text="Loading help..." /> : helpContent;
+    return <PluginHelp plugin={this.state.currentDS.meta} type="query_help" />;
   };
   };
 
 
   onAddQuery = (query?: Partial<DataQuery>) => {
   onAddQuery = (query?: Partial<DataQuery>) => {
@@ -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,
     };
     };
 
 

+ 16 - 1
public/app/features/dashboard/dashgrid/VisualizationTab.tsx

@@ -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';
 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 {
 }
 }
 
 
 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> {
   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> {
     }
     }
   };
   };
 
 
+  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

+ 16 - 4
public/app/features/datasources/settings/__snapshots__/DataSourceSettings.test.tsx.snap

@@ -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`] = `
                 },
                 },
                 "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`] = `
                 },
                 },
                 "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`] = `
                 },
                 },
                 "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",

+ 1 - 1
public/app/features/datasources/state/navModel.ts

@@ -73,7 +73,7 @@ export function getDataSourceLoadingNav(pageName: string): NavModel {
           url: '',
           url: '',
         },
         },
         description: '',
         description: '',
-        links: [''],
+        links: [{ name: '', url: '' }],
         logos: {
         logos: {
           large: '',
           large: '',
           small: '',
           small: '',

+ 1 - 1
public/app/features/plugins/__mocks__/pluginMocks.ts

@@ -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',

+ 6 - 1
public/app/types/plugins.ts

@@ -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;