Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
nexpie-grafana-theme
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Registry
Registry
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Kornkitt Poolsup
nexpie-grafana-theme
Commits
7aeae84c
Unverified
Commit
7aeae84c
authored
Apr 24, 2019
by
Dominik Prokop
Committed by
GitHub
Apr 24, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Feature: Enable React based options editors for Datasource plugins (#16748)
parent
2d6b33ab
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
106 additions
and
24 deletions
+106
-24
packages/grafana-ui/src/types/datasource.ts
+14
-4
public/app/features/datasources/settings/DataSourceSettingsPage.test.tsx
+9
-3
public/app/features/datasources/settings/DataSourceSettingsPage.tsx
+28
-9
public/app/features/datasources/settings/PluginSettings.tsx
+29
-6
public/app/features/datasources/settings/__snapshots__/DataSourceSettingsPage.test.tsx.snap
+24
-0
public/app/features/plugins/plugin_loader.ts
+2
-2
public/app/plugins/datasource/testdata/module.tsx
+0
-0
No files found.
packages/grafana-ui/src/types/datasource.ts
View file @
7aeae84c
...
...
@@ -4,15 +4,24 @@ import { PluginMeta } from './plugin';
import
{
TableData
,
TimeSeries
,
SeriesData
}
from
'./data'
;
import
{
PanelData
}
from
'./panel'
;
export
class
DataSourcePlugin
<
TQuery
extends
DataQuery
=
DataQuery
>
{
export
interface
DataSourcePluginOptionsEditorProps
<
TOptions
>
{
options
:
TOptions
;
onOptionsChange
:
(
options
:
TOptions
)
=>
void
;
}
export
class
DataSourcePlugin
<
TOptions
=
{},
TQuery
extends
DataQuery
=
DataQuery
>
{
DataSourceClass
:
DataSourceConstructor
<
TQuery
>
;
components
:
DataSourcePluginComponents
<
TQuery
>
;
components
:
DataSourcePluginComponents
<
T
Options
,
T
Query
>
;
constructor
(
DataSourceClass
:
DataSourceConstructor
<
TQuery
>
)
{
this
.
DataSourceClass
=
DataSourceClass
;
this
.
components
=
{};
}
setConfigEditor
(
editor
:
React
.
ComponentType
<
DataSourcePluginOptionsEditorProps
<
TOptions
>>
)
{
this
.
components
.
ConfigEditor
=
editor
;
return
this
;
}
setConfigCtrl
(
ConfigCtrl
:
any
)
{
this
.
components
.
ConfigCtrl
=
ConfigCtrl
;
return
this
;
...
...
@@ -59,7 +68,7 @@ export class DataSourcePlugin<TQuery extends DataQuery = DataQuery> {
}
}
export
interface
DataSourcePluginComponents
<
TQuery
extends
DataQuery
=
DataQuery
>
{
export
interface
DataSourcePluginComponents
<
T
Options
=
{},
T
Query
extends
DataQuery
=
DataQuery
>
{
QueryCtrl
?:
any
;
ConfigCtrl
?:
any
;
AnnotationsQueryCtrl
?:
any
;
...
...
@@ -67,9 +76,10 @@ export interface DataSourcePluginComponents<TQuery extends DataQuery = DataQuery
QueryEditor
?:
ComponentClass
<
QueryEditorProps
<
DataSourceApi
,
TQuery
>>
;
ExploreQueryField
?:
ComponentClass
<
ExploreQueryFieldProps
<
DataSourceApi
,
TQuery
>>
;
ExploreStartPage
?:
ComponentClass
<
ExploreStartPageProps
>
;
ConfigEditor
?:
React
.
ComponentType
<
DataSourcePluginOptionsEditorProps
<
TOptions
>>
;
}
interface
DataSourceConstructor
<
TQuery
extends
DataQuery
=
DataQuery
>
{
export
interface
DataSourceConstructor
<
TQuery
extends
DataQuery
=
DataQuery
>
{
new
(
instanceSettings
:
DataSourceInstanceSettings
,
...
args
:
any
[]):
DataSourceApi
<
TQuery
>
;
}
...
...
public/app/features/datasources/settings/DataSourceSettingsPage.test.tsx
View file @
7aeae84c
...
...
@@ -2,11 +2,13 @@ import React from 'react';
import
{
shallow
}
from
'enzyme'
;
import
{
DataSourceSettingsPage
,
Props
}
from
'./DataSourceSettingsPage'
;
import
{
NavModel
}
from
'app/types'
;
import
{
DataSourceSettings
}
from
'@grafana/ui'
;
import
{
DataSourceSettings
,
DataSourcePlugin
,
DataSourceConstructor
}
from
'@grafana/ui'
;
import
{
getMockDataSource
}
from
'../__mocks__/dataSourcesMocks'
;
import
{
getMockPlugin
}
from
'../../plugins/__mocks__/pluginMocks'
;
import
{
setDataSourceName
,
setIsDefault
}
from
'../state/actions'
;
const
pluginMock
=
new
DataSourcePlugin
({}
as
DataSourceConstructor
<
any
>
);
const
setup
=
(
propOverrides
?:
object
)
=>
{
const
props
:
Props
=
{
navModel
:
{}
as
NavModel
,
...
...
@@ -18,10 +20,10 @@ const setup = (propOverrides?: object) => {
setDataSourceName
,
updateDataSource
:
jest
.
fn
(),
setIsDefault
,
plugin
:
pluginMock
,
...
propOverrides
,
};
Object
.
assign
(
props
,
propOverrides
);
return
shallow
(<
DataSourceSettingsPage
{
...
props
}
/>);
};
...
...
@@ -35,6 +37,7 @@ describe('Render', () => {
it
(
'should render loader'
,
()
=>
{
const
wrapper
=
setup
({
dataSource
:
{}
as
DataSourceSettings
,
plugin
:
pluginMock
,
});
expect
(
wrapper
).
toMatchSnapshot
();
...
...
@@ -43,6 +46,7 @@ describe('Render', () => {
it
(
'should render beta info text'
,
()
=>
{
const
wrapper
=
setup
({
dataSourceMeta
:
{
...
getMockPlugin
(),
state
:
'beta'
},
plugin
:
pluginMock
,
});
expect
(
wrapper
).
toMatchSnapshot
();
...
...
@@ -51,6 +55,7 @@ describe('Render', () => {
it
(
'should render alpha info text'
,
()
=>
{
const
wrapper
=
setup
({
dataSourceMeta
:
{
...
getMockPlugin
(),
state
:
'alpha'
},
plugin
:
pluginMock
,
});
expect
(
wrapper
).
toMatchSnapshot
();
...
...
@@ -59,6 +64,7 @@ describe('Render', () => {
it
(
'should render is ready only message'
,
()
=>
{
const
wrapper
=
setup
({
dataSource
:
{
...
getMockDataSource
(),
readOnly
:
true
},
plugin
:
pluginMock
,
});
expect
(
wrapper
).
toMatchSnapshot
();
...
...
public/app/features/datasources/settings/DataSourceSettingsPage.tsx
View file @
7aeae84c
...
...
@@ -22,9 +22,10 @@ import { getRouteParamsId } from 'app/core/selectors/location';
// Types
import
{
NavModel
,
Plugin
,
StoreState
}
from
'app/types/'
;
import
{
DataSourceSettings
}
from
'@grafana/ui/src/types/'
;
import
{
DataSourceSettings
,
DataSourcePlugin
}
from
'@grafana/ui/src/types/'
;
import
{
getDataSourceLoadingNav
}
from
'../state/navModel'
;
import
PluginStateinfo
from
'app/features/plugins/PluginStateInfo'
;
import
{
importDataSourcePlugin
}
from
'app/features/plugins/plugin_loader'
;
export
interface
Props
{
navModel
:
NavModel
;
...
...
@@ -36,10 +37,12 @@ export interface Props {
setDataSourceName
:
typeof
setDataSourceName
;
updateDataSource
:
typeof
updateDataSource
;
setIsDefault
:
typeof
setIsDefault
;
plugin
?:
DataSourcePlugin
;
}
interface
State
{
dataSource
:
DataSourceSettings
;
plugin
:
DataSourcePlugin
;
isTesting
?:
boolean
;
testingMessage
?:
string
;
testingStatus
?:
string
;
...
...
@@ -50,14 +53,30 @@ export class DataSourceSettingsPage extends PureComponent<Props, State> {
super
(
props
);
this
.
state
=
{
dataSource
:
{}
as
DataSourceSettings
,
dataSource
:
props
.
dataSource
,
plugin
:
props
.
plugin
,
};
}
async
loadPlugin
(
pluginId
?:
string
)
{
const
{
dataSourceMeta
}
=
this
.
props
;
let
importedPlugin
:
DataSourcePlugin
;
try
{
importedPlugin
=
await
importDataSourcePlugin
(
dataSourceMeta
.
module
);
}
catch
(
e
)
{
console
.
log
(
'Failed to import plugin module'
,
e
);
}
this
.
setState
({
plugin
:
importedPlugin
});
}
async
componentDidMount
()
{
const
{
loadDataSource
,
pageId
}
=
this
.
props
;
await
loadDataSource
(
pageId
);
if
(
!
this
.
state
.
plugin
)
{
await
this
.
loadPlugin
();
}
}
componentDidUpdate
(
prevProps
:
Props
)
{
...
...
@@ -71,7 +90,7 @@ export class DataSourceSettingsPage extends PureComponent<Props, State> {
onSubmit
=
async
(
evt
:
React
.
FormEvent
<
HTMLFormElement
>
)
=>
{
evt
.
preventDefault
();
await
this
.
props
.
updateDataSource
({
...
this
.
state
.
dataSource
,
name
:
this
.
props
.
dataSource
.
name
});
await
this
.
props
.
updateDataSource
({
...
this
.
state
.
dataSource
});
this
.
testDataSource
();
};
...
...
@@ -156,8 +175,8 @@ export class DataSourceSettingsPage extends PureComponent<Props, State> {
}
render
()
{
const
{
dataSource
,
dataSource
Meta
,
navModel
,
setDataSourceName
,
setIsDefault
}
=
this
.
props
;
const
{
testingMessage
,
testingStatus
}
=
this
.
state
;
const
{
dataSourceMeta
,
navModel
,
setDataSourceName
,
setIsDefault
}
=
this
.
props
;
const
{
testingMessage
,
testingStatus
,
plugin
,
dataSource
}
=
this
.
state
;
return
(
<
Page
navModel=
{
navModel
}
>
...
...
@@ -175,9 +194,10 @@ export class DataSourceSettingsPage extends PureComponent<Props, State> {
onNameChange=
{
name
=>
setDataSourceName
(
name
)
}
/>
{
dataSourceMeta
.
module
&&
(
{
dataSourceMeta
.
module
&&
plugin
&&
(
<
PluginSettings
dataSource=
{
dataSource
}
plugin=
{
plugin
}
dataSource=
{
this
.
state
.
dataSource
}
dataSourceMeta=
{
dataSourceMeta
}
onModelChange=
{
this
.
onModelChange
}
/>
...
...
@@ -218,7 +238,6 @@ export class DataSourceSettingsPage extends PureComponent<Props, State> {
function
mapStateToProps
(
state
:
StoreState
)
{
const
pageId
=
getRouteParamsId
(
state
.
location
);
const
dataSource
=
getDataSource
(
state
.
dataSources
,
pageId
);
return
{
navModel
:
getNavModel
(
state
.
navIndex
,
`datasource-settings-
${
pageId
}
`
,
getDataSourceLoadingNav
(
'settings'
)),
dataSource
:
getDataSource
(
state
.
dataSources
,
pageId
),
...
...
public/app/features/datasources/settings/PluginSettings.tsx
View file @
7aeae84c
import
React
,
{
PureComponent
}
from
'react'
;
import
_
from
'lodash'
;
import
{
Plugin
}
from
'app/types'
;
import
{
DataSourceSettings
}
from
'@grafana/ui/src/types'
;
import
{
DataSourceSettings
,
DataSourcePlugin
}
from
'@grafana/ui/src/types'
;
import
{
getAngularLoader
,
AngularComponent
}
from
'app/core/services/AngularLoader'
;
export
interface
Props
{
plugin
:
DataSourcePlugin
;
dataSource
:
DataSourceSettings
;
dataSourceMeta
:
Plugin
;
onModelChange
:
(
dataSource
:
DataSourceSettings
)
=>
void
;
...
...
@@ -25,21 +26,29 @@ export class PluginSettings extends PureComponent<Props> {
ctrl
:
{
datasourceMeta
:
props
.
dataSourceMeta
,
current
:
_
.
cloneDeep
(
props
.
dataSource
)
},
onModelChanged
:
this
.
onModelChanged
,
};
this
.
onModelChanged
=
this
.
onModelChanged
.
bind
(
this
);
}
componentDidMount
()
{
const
{
plugin
}
=
this
.
props
;
if
(
!
this
.
element
)
{
return
;
}
const
loader
=
getAngularLoader
();
const
template
=
'<plugin-component type="datasource-config-ctrl" />'
;
if
(
!
plugin
.
components
.
ConfigEditor
)
{
// React editor is not specified, let's render angular editor
// How to apprach this better? Introduce ReactDataSourcePlugin interface and typeguard it here?
const
loader
=
getAngularLoader
();
const
template
=
'<plugin-component type="datasource-config-ctrl" />'
;
this
.
component
=
loader
.
load
(
this
.
element
,
this
.
scopeProps
,
template
);
this
.
component
=
loader
.
load
(
this
.
element
,
this
.
scopeProps
,
template
);
}
}
componentDidUpdate
(
prevProps
)
{
if
(
this
.
props
.
dataSource
!==
prevProps
.
dataSource
)
{
const
{
plugin
}
=
this
.
props
;
if
(
!
plugin
.
components
.
ConfigEditor
&&
this
.
props
.
dataSource
!==
prevProps
.
dataSource
)
{
this
.
scopeProps
.
ctrl
.
current
=
_
.
cloneDeep
(
this
.
props
.
dataSource
);
this
.
component
.
digest
();
...
...
@@ -57,7 +66,21 @@ export class PluginSettings extends PureComponent<Props> {
};
render
()
{
return
<
div
ref=
{
element
=>
(
this
.
element
=
element
)
}
/>;
const
{
plugin
,
dataSource
}
=
this
.
props
;
if
(
!
plugin
)
{
return
null
;
}
return
(
<
div
ref=
{
element
=>
(
this
.
element
=
element
)
}
>
{
plugin
.
components
.
ConfigEditor
&&
React
.
createElement
(
plugin
.
components
.
ConfigEditor
,
{
options
:
dataSource
,
onOptionsChange
:
this
.
onModelChanged
,
})
}
</
div
>
);
}
}
...
...
public/app/features/datasources/settings/__snapshots__/DataSourceSettingsPage.test.tsx.snap
View file @
7aeae84c
...
...
@@ -85,6 +85,12 @@ exports[`Render should render alpha info text 1`] = `
}
}
onModelChange={[Function]}
plugin={
DataSourcePlugin {
"DataSourceClass": Object {},
"components": Object {},
}
}
/>
<div
className="gf-form-group"
...
...
@@ -186,6 +192,12 @@ exports[`Render should render beta info text 1`] = `
}
}
onModelChange={[Function]}
plugin={
DataSourcePlugin {
"DataSourceClass": Object {},
"components": Object {},
}
}
/>
<div
className="gf-form-group"
...
...
@@ -284,6 +296,12 @@ exports[`Render should render component 1`] = `
}
}
onModelChange={[Function]}
plugin={
DataSourcePlugin {
"DataSourceClass": Object {},
"components": Object {},
}
}
/>
<div
className="gf-form-group"
...
...
@@ -387,6 +405,12 @@ exports[`Render should render is ready only message 1`] = `
}
}
onModelChange={[Function]}
plugin={
DataSourcePlugin {
"DataSourceClass": Object {},
"components": Object {},
}
}
/>
<div
className="gf-form-group"
...
...
public/app/features/plugins/plugin_loader.ts
View file @
7aeae84c
...
...
@@ -160,10 +160,10 @@ export function importPluginModule(path: string): Promise<any> {
return
System
.
import
(
path
);
}
export
function
importDataSourcePlugin
(
path
:
string
):
Promise
<
DataSourcePlugin
>
{
export
function
importDataSourcePlugin
(
path
:
string
):
Promise
<
DataSourcePlugin
<
any
>
>
{
return
importPluginModule
(
path
).
then
(
pluginExports
=>
{
if
(
pluginExports
.
plugin
)
{
return
pluginExports
.
plugin
as
DataSourcePlugin
;
return
pluginExports
.
plugin
as
DataSourcePlugin
<
any
>
;
}
if
(
pluginExports
.
Datasource
)
{
...
...
public/app/plugins/datasource/testdata/module.ts
→
public/app/plugins/datasource/testdata/module.ts
x
View file @
7aeae84c
File moved
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment