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
a13b4f2b
Unverified
Commit
a13b4f2b
authored
Jul 16, 2018
by
David
Committed by
GitHub
Jul 16, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #12596 from grafana/davkal/explore-datasource-selector
Explore Datasource selector
parents
0f6e5e29
eb2abe80
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
153 additions
and
32 deletions
+153
-32
pkg/plugins/datasource_plugin.go
+1
-0
public/app/containers/Explore/Explore.tsx
+84
-17
public/app/features/plugins/datasource_srv.ts
+14
-5
public/app/features/plugins/specs/datasource_srv.jest.ts
+27
-1
public/app/plugins/datasource/prometheus/datasource.ts
+1
-0
public/app/plugins/datasource/prometheus/plugin.json
+22
-9
public/sass/pages/_explore.scss
+4
-0
No files found.
pkg/plugins/datasource_plugin.go
View file @
a13b4f2b
...
@@ -22,6 +22,7 @@ type DataSourcePlugin struct {
...
@@ -22,6 +22,7 @@ type DataSourcePlugin struct {
Annotations
bool
`json:"annotations"`
Annotations
bool
`json:"annotations"`
Metrics
bool
`json:"metrics"`
Metrics
bool
`json:"metrics"`
Alerting
bool
`json:"alerting"`
Alerting
bool
`json:"alerting"`
Explore
bool
`json:"explore"`
QueryOptions
map
[
string
]
bool
`json:"queryOptions,omitempty"`
QueryOptions
map
[
string
]
bool
`json:"queryOptions,omitempty"`
BuiltIn
bool
`json:"builtIn,omitempty"`
BuiltIn
bool
`json:"builtIn,omitempty"`
Mixed
bool
`json:"mixed,omitempty"`
Mixed
bool
`json:"mixed,omitempty"`
...
...
public/app/containers/Explore/Explore.tsx
View file @
a13b4f2b
import
React
from
'react'
;
import
React
from
'react'
;
import
{
hot
}
from
'react-hot-loader'
;
import
{
hot
}
from
'react-hot-loader'
;
import
Select
from
'react-select'
;
import
colors
from
'app/core/utils/colors'
;
import
colors
from
'app/core/utils/colors'
;
import
TimeSeries
from
'app/core/time_series2'
;
import
TimeSeries
from
'app/core/time_series2'
;
import
{
decodePathComponent
}
from
'app/core/utils/location_util'
;
import
ElapsedTime
from
'./ElapsedTime'
;
import
ElapsedTime
from
'./ElapsedTime'
;
import
QueryRows
from
'./QueryRows'
;
import
QueryRows
from
'./QueryRows'
;
import
Graph
from
'./Graph'
;
import
Graph
from
'./Graph'
;
import
Table
from
'./Table'
;
import
Table
from
'./Table'
;
import
TimePicker
,
{
DEFAULT_RANGE
}
from
'./TimePicker'
;
import
TimePicker
,
{
DEFAULT_RANGE
}
from
'./TimePicker'
;
import
{
DatasourceSrv
}
from
'app/features/plugins/datasource_srv'
;
import
{
buildQueryOptions
,
ensureQueries
,
generateQueryKey
,
hasQuery
}
from
'./utils/query'
;
import
{
buildQueryOptions
,
ensureQueries
,
generateQueryKey
,
hasQuery
}
from
'./utils/query'
;
import
{
decodePathComponent
}
from
'app/core/utils/location_util'
;
function
makeTimeSeriesList
(
dataList
,
options
)
{
function
makeTimeSeriesList
(
dataList
,
options
)
{
return
dataList
.
map
((
seriesData
,
index
)
=>
{
return
dataList
.
map
((
seriesData
,
index
)
=>
{
...
@@ -34,6 +35,7 @@ function parseInitialState(initial) {
...
@@ -34,6 +35,7 @@ function parseInitialState(initial) {
try
{
try
{
const
parsed
=
JSON
.
parse
(
decodePathComponent
(
initial
));
const
parsed
=
JSON
.
parse
(
decodePathComponent
(
initial
));
return
{
return
{
datasource
:
parsed
.
datasource
,
queries
:
parsed
.
queries
.
map
(
q
=>
q
.
query
),
queries
:
parsed
.
queries
.
map
(
q
=>
q
.
query
),
range
:
parsed
.
range
,
range
:
parsed
.
range
,
};
};
...
@@ -46,8 +48,10 @@ function parseInitialState(initial) {
...
@@ -46,8 +48,10 @@ function parseInitialState(initial) {
interface
IExploreState
{
interface
IExploreState
{
datasource
:
any
;
datasource
:
any
;
datasourceError
:
any
;
datasourceError
:
any
;
datasourceLoading
:
any
;
datasourceLoading
:
boolean
|
null
;
datasourceMissing
:
boolean
;
graphResult
:
any
;
graphResult
:
any
;
initialDatasource
?:
string
;
latency
:
number
;
latency
:
number
;
loading
:
any
;
loading
:
any
;
queries
:
any
;
queries
:
any
;
...
@@ -61,16 +65,16 @@ interface IExploreState {
...
@@ -61,16 +65,16 @@ interface IExploreState {
// @observer
// @observer
export
class
Explore
extends
React
.
Component
<
any
,
IExploreState
>
{
export
class
Explore
extends
React
.
Component
<
any
,
IExploreState
>
{
datasourceSrv
:
DatasourceSrv
;
constructor
(
props
)
{
constructor
(
props
)
{
super
(
props
);
super
(
props
);
const
{
range
,
queries
}
=
parseInitialState
(
props
.
routeParams
.
initial
);
const
{
datasource
,
queries
,
range
}
=
parseInitialState
(
props
.
routeParams
.
initial
);
this
.
state
=
{
this
.
state
=
{
datasource
:
null
,
datasource
:
null
,
datasourceError
:
null
,
datasourceError
:
null
,
datasourceLoading
:
true
,
datasourceLoading
:
null
,
datasourceMissing
:
false
,
graphResult
:
null
,
graphResult
:
null
,
initialDatasource
:
datasource
,
latency
:
0
,
latency
:
0
,
loading
:
false
,
loading
:
false
,
queries
:
ensureQueries
(
queries
),
queries
:
ensureQueries
(
queries
),
...
@@ -85,19 +89,49 @@ export class Explore extends React.Component<any, IExploreState> {
...
@@ -85,19 +89,49 @@ export class Explore extends React.Component<any, IExploreState> {
}
}
async
componentDidMount
()
{
async
componentDidMount
()
{
const
datasource
=
await
this
.
props
.
datasourceSrv
.
get
();
const
{
datasourceSrv
}
=
this
.
props
;
const
testResult
=
await
datasource
.
testDatasource
();
const
{
initialDatasource
}
=
this
.
state
;
if
(
testResult
.
status
===
'success'
)
{
if
(
!
datasourceSrv
)
{
this
.
setState
({
datasource
,
datasourceError
:
null
,
datasourceLoading
:
false
},
()
=>
this
.
handleSubmit
());
throw
new
Error
(
'No datasource service passed as props.'
);
}
const
datasources
=
datasourceSrv
.
getExploreSources
();
if
(
datasources
.
length
>
0
)
{
this
.
setState
({
datasourceLoading
:
true
});
// Priority: datasource in url, default datasource, first explore datasource
let
datasource
;
if
(
initialDatasource
)
{
datasource
=
await
datasourceSrv
.
get
(
initialDatasource
);
}
else
{
datasource
=
await
datasourceSrv
.
get
();
}
if
(
!
datasource
.
meta
.
explore
)
{
datasource
=
await
datasourceSrv
.
get
(
datasources
[
0
].
name
);
}
this
.
setDatasource
(
datasource
);
}
else
{
}
else
{
this
.
setState
({
datasource
:
null
,
datasourceError
:
testResult
.
message
,
datasourceLoading
:
fals
e
});
this
.
setState
({
datasource
Missing
:
tru
e
});
}
}
}
}
componentDidCatch
(
error
)
{
componentDidCatch
(
error
)
{
this
.
setState
({
datasourceError
:
error
});
console
.
error
(
error
);
console
.
error
(
error
);
}
}
async
setDatasource
(
datasource
)
{
try
{
const
testResult
=
await
datasource
.
testDatasource
();
if
(
testResult
.
status
===
'success'
)
{
this
.
setState
({
datasource
,
datasourceError
:
null
,
datasourceLoading
:
false
},
()
=>
this
.
handleSubmit
());
}
else
{
this
.
setState
({
datasource
:
datasource
,
datasourceError
:
testResult
.
message
,
datasourceLoading
:
false
});
}
}
catch
(
error
)
{
const
message
=
(
error
&&
error
.
statusText
)
||
error
;
this
.
setState
({
datasource
:
datasource
,
datasourceError
:
message
,
datasourceLoading
:
false
});
}
}
handleAddQueryRow
=
index
=>
{
handleAddQueryRow
=
index
=>
{
const
{
queries
}
=
this
.
state
;
const
{
queries
}
=
this
.
state
;
const
nextQueries
=
[
const
nextQueries
=
[
...
@@ -108,6 +142,18 @@ export class Explore extends React.Component<any, IExploreState> {
...
@@ -108,6 +142,18 @@ export class Explore extends React.Component<any, IExploreState> {
this
.
setState
({
queries
:
nextQueries
});
this
.
setState
({
queries
:
nextQueries
});
};
};
handleChangeDatasource
=
async
option
=>
{
this
.
setState
({
datasource
:
null
,
datasourceError
:
null
,
datasourceLoading
:
true
,
graphResult
:
null
,
tableResult
:
null
,
});
const
datasource
=
await
this
.
props
.
datasourceSrv
.
get
(
option
.
value
);
this
.
setDatasource
(
datasource
);
};
handleChangeQuery
=
(
query
,
index
)
=>
{
handleChangeQuery
=
(
query
,
index
)
=>
{
const
{
queries
}
=
this
.
state
;
const
{
queries
}
=
this
.
state
;
const
nextQuery
=
{
const
nextQuery
=
{
...
@@ -226,11 +272,12 @@ export class Explore extends React.Component<any, IExploreState> {
...
@@ -226,11 +272,12 @@ export class Explore extends React.Component<any, IExploreState> {
};
};
render
()
{
render
()
{
const
{
position
,
split
}
=
this
.
props
;
const
{
datasourceSrv
,
position
,
split
}
=
this
.
props
;
const
{
const
{
datasource
,
datasource
,
datasourceError
,
datasourceError
,
datasourceLoading
,
datasourceLoading
,
datasourceMissing
,
graphResult
,
graphResult
,
latency
,
latency
,
loading
,
loading
,
...
@@ -247,6 +294,12 @@ export class Explore extends React.Component<any, IExploreState> {
...
@@ -247,6 +294,12 @@ export class Explore extends React.Component<any, IExploreState> {
const
graphButtonActive
=
showingBoth
||
showingGraph
?
'active'
:
''
;
const
graphButtonActive
=
showingBoth
||
showingGraph
?
'active'
:
''
;
const
tableButtonActive
=
showingBoth
||
showingTable
?
'active'
:
''
;
const
tableButtonActive
=
showingBoth
||
showingTable
?
'active'
:
''
;
const
exploreClass
=
split
?
'explore explore-split'
:
'explore'
;
const
exploreClass
=
split
?
'explore explore-split'
:
'explore'
;
const
datasources
=
datasourceSrv
.
getExploreSources
().
map
(
ds
=>
({
value
:
ds
.
name
,
label
:
ds
.
name
,
}));
const
selectedDatasource
=
datasource
?
datasource
.
name
:
undefined
;
return
(
return
(
<
div
className=
{
exploreClass
}
>
<
div
className=
{
exploreClass
}
>
<
div
className=
"navbar"
>
<
div
className=
"navbar"
>
...
@@ -264,6 +317,18 @@ export class Explore extends React.Component<any, IExploreState> {
...
@@ -264,6 +317,18 @@ export class Explore extends React.Component<any, IExploreState> {
</
button
>
</
button
>
</
div
>
</
div
>
)
}
)
}
{
!
datasourceMissing
?
(
<
div
className=
"navbar-buttons"
>
<
Select
className=
"datasource-picker"
clearable=
{
false
}
onChange=
{
this
.
handleChangeDatasource
}
options=
{
datasources
}
placeholder=
"Loading datasources..."
value=
{
selectedDatasource
}
/>
</
div
>
)
:
null
}
<
div
className=
"navbar__spacer"
/>
<
div
className=
"navbar__spacer"
/>
{
position
===
'left'
&&
!
split
?
(
{
position
===
'left'
&&
!
split
?
(
<
div
className=
"navbar-buttons"
>
<
div
className=
"navbar-buttons"
>
...
@@ -291,13 +356,15 @@ export class Explore extends React.Component<any, IExploreState> {
...
@@ -291,13 +356,15 @@ export class Explore extends React.Component<any, IExploreState> {
{
datasourceLoading
?
<
div
className=
"explore-container"
>
Loading datasource...
</
div
>
:
null
}
{
datasourceLoading
?
<
div
className=
"explore-container"
>
Loading datasource...
</
div
>
:
null
}
{
datasourceMissing
?
(
<
div
className=
"explore-container"
>
Please add a datasource that supports Explore (e.g., Prometheus).
</
div
>
)
:
null
}
{
datasourceError
?
(
{
datasourceError
?
(
<
div
className=
"explore-container"
title=
{
datasourceError
}
>
<
div
className=
"explore-container"
>
Error connecting to datasource. [
{
datasourceError
}
]
</
div
>
Error connecting to datasource.
</
div
>
)
:
null
}
)
:
null
}
{
datasource
?
(
{
datasource
&&
!
datasourceError
?
(
<
div
className=
"explore-container"
>
<
div
className=
"explore-container"
>
<
QueryRows
<
QueryRows
queries=
{
queries
}
queries=
{
queries
}
...
...
public/app/features/plugins/datasource_srv.ts
View file @
a13b4f2b
...
@@ -34,13 +34,13 @@ export class DatasourceSrv {
...
@@ -34,13 +34,13 @@ export class DatasourceSrv {
}
}
loadDatasource
(
name
)
{
loadDatasource
(
name
)
{
var
dsConfig
=
config
.
datasources
[
name
];
const
dsConfig
=
config
.
datasources
[
name
];
if
(
!
dsConfig
)
{
if
(
!
dsConfig
)
{
return
this
.
$q
.
reject
({
message
:
'Datasource named '
+
name
+
' was not found'
});
return
this
.
$q
.
reject
({
message
:
'Datasource named '
+
name
+
' was not found'
});
}
}
var
deferred
=
this
.
$q
.
defer
();
const
deferred
=
this
.
$q
.
defer
();
var
pluginDef
=
dsConfig
.
meta
;
const
pluginDef
=
dsConfig
.
meta
;
importPluginModule
(
pluginDef
.
module
)
importPluginModule
(
pluginDef
.
module
)
.
then
(
plugin
=>
{
.
then
(
plugin
=>
{
...
@@ -55,7 +55,7 @@ export class DatasourceSrv {
...
@@ -55,7 +55,7 @@ export class DatasourceSrv {
throw
new
Error
(
'Plugin module is missing Datasource constructor'
);
throw
new
Error
(
'Plugin module is missing Datasource constructor'
);
}
}
var
instance
=
this
.
$injector
.
instantiate
(
plugin
.
Datasource
,
{
instanceSettings
:
dsConfig
});
const
instance
=
this
.
$injector
.
instantiate
(
plugin
.
Datasource
,
{
instanceSettings
:
dsConfig
});
instance
.
meta
=
pluginDef
;
instance
.
meta
=
pluginDef
;
instance
.
name
=
name
;
instance
.
name
=
name
;
this
.
datasources
[
name
]
=
instance
;
this
.
datasources
[
name
]
=
instance
;
...
@@ -73,7 +73,7 @@ export class DatasourceSrv {
...
@@ -73,7 +73,7 @@ export class DatasourceSrv {
}
}
getAnnotationSources
()
{
getAnnotationSources
()
{
var
sources
=
[];
const
sources
=
[];
this
.
addDataSourceVariables
(
sources
);
this
.
addDataSourceVariables
(
sources
);
...
@@ -86,6 +86,14 @@ export class DatasourceSrv {
...
@@ -86,6 +86,14 @@ export class DatasourceSrv {
return
sources
;
return
sources
;
}
}
getExploreSources
()
{
const
{
datasources
}
=
config
;
const
es
=
Object
.
keys
(
datasources
)
.
map
(
name
=>
datasources
[
name
])
.
filter
(
ds
=>
ds
.
meta
&&
ds
.
meta
.
explore
);
return
_
.
sortBy
(
es
,
[
'name'
]);
}
getMetricSources
(
options
)
{
getMetricSources
(
options
)
{
var
metricSources
=
[];
var
metricSources
=
[];
...
@@ -155,3 +163,4 @@ export class DatasourceSrv {
...
@@ -155,3 +163,4 @@ export class DatasourceSrv {
}
}
coreModule
.
service
(
'datasourceSrv'
,
DatasourceSrv
);
coreModule
.
service
(
'datasourceSrv'
,
DatasourceSrv
);
export
default
DatasourceSrv
;
public/app/features/plugins/specs/datasource_srv.jest.ts
View file @
a13b4f2b
...
@@ -17,9 +17,35 @@ const templateSrv = {
...
@@ -17,9 +17,35 @@ const templateSrv = {
describe
(
'datasource_srv'
,
function
()
{
describe
(
'datasource_srv'
,
function
()
{
let
_datasourceSrv
=
new
DatasourceSrv
({},
{},
{},
templateSrv
);
let
_datasourceSrv
=
new
DatasourceSrv
({},
{},
{},
templateSrv
);
let
metricSources
;
describe
(
'when loading explore sources'
,
()
=>
{
beforeEach
(()
=>
{
config
.
datasources
=
{
explore1
:
{
name
:
'explore1'
,
meta
:
{
explore
:
true
,
metrics
:
true
},
},
explore2
:
{
name
:
'explore2'
,
meta
:
{
explore
:
true
,
metrics
:
false
},
},
nonExplore
:
{
name
:
'nonExplore'
,
meta
:
{
explore
:
false
,
metrics
:
true
},
},
};
});
it
(
'should return list of explore sources'
,
()
=>
{
const
exploreSources
=
_datasourceSrv
.
getExploreSources
();
expect
(
exploreSources
.
length
).
toBe
(
2
);
expect
(
exploreSources
[
0
].
name
).
toBe
(
'explore1'
);
expect
(
exploreSources
[
1
].
name
).
toBe
(
'explore2'
);
});
});
describe
(
'when loading metric sources'
,
()
=>
{
describe
(
'when loading metric sources'
,
()
=>
{
let
metricSources
;
let
unsortedDatasources
=
{
let
unsortedDatasources
=
{
mmm
:
{
mmm
:
{
type
:
'test-db'
,
type
:
'test-db'
,
...
...
public/app/plugins/datasource/prometheus/datasource.ts
View file @
a13b4f2b
...
@@ -357,6 +357,7 @@ export class PrometheusDatasource {
...
@@ -357,6 +357,7 @@ export class PrometheusDatasource {
state = {
state = {
...state,
...state,
queries,
queries,
datasource: this.name,
};
};
}
}
return state;
return state;
...
...
public/app/plugins/datasource/prometheus/plugin.json
View file @
a13b4f2b
...
@@ -2,21 +2,30 @@
...
@@ -2,21 +2,30 @@
"type"
:
"datasource"
,
"type"
:
"datasource"
,
"name"
:
"Prometheus"
,
"name"
:
"Prometheus"
,
"id"
:
"prometheus"
,
"id"
:
"prometheus"
,
"includes"
:
[
"includes"
:
[
{
"type"
:
"dashboard"
,
"name"
:
"Prometheus Stats"
,
"path"
:
"dashboards/prometheus_stats.json"
},
{
{
"type"
:
"dashboard"
,
"name"
:
"Prometheus 2.0 Stats"
,
"path"
:
"dashboards/prometheus_2_stats.json"
},
"type"
:
"dashboard"
,
{
"type"
:
"dashboard"
,
"name"
:
"Grafana Stats"
,
"path"
:
"dashboards/grafana_stats.json"
}
"name"
:
"Prometheus Stats"
,
"path"
:
"dashboards/prometheus_stats.json"
},
{
"type"
:
"dashboard"
,
"name"
:
"Prometheus 2.0 Stats"
,
"path"
:
"dashboards/prometheus_2_stats.json"
},
{
"type"
:
"dashboard"
,
"name"
:
"Grafana Stats"
,
"path"
:
"dashboards/grafana_stats.json"
}
],
],
"metrics"
:
true
,
"metrics"
:
true
,
"alerting"
:
true
,
"alerting"
:
true
,
"annotations"
:
true
,
"annotations"
:
true
,
"explore"
:
true
,
"queryOptions"
:
{
"queryOptions"
:
{
"minInterval"
:
true
"minInterval"
:
true
},
},
"info"
:
{
"info"
:
{
"description"
:
"Prometheus Data Source for Grafana"
,
"description"
:
"Prometheus Data Source for Grafana"
,
"author"
:
{
"author"
:
{
...
@@ -28,8 +37,11 @@
...
@@ -28,8 +37,11 @@
"large"
:
"img/prometheus_logo.svg"
"large"
:
"img/prometheus_logo.svg"
},
},
"links"
:
[
"links"
:
[
{
"name"
:
"Prometheus"
,
"url"
:
"https://prometheus.io/"
}
{
"name"
:
"Prometheus"
,
"url"
:
"https://prometheus.io/"
}
],
],
"version"
:
"5.0.0"
"version"
:
"5.0.0"
}
}
}
}
\ No newline at end of file
public/sass/pages/_explore.scss
View file @
a13b4f2b
...
@@ -60,6 +60,10 @@
...
@@ -60,6 +60,10 @@
flex-wrap
:
wrap
;
flex-wrap
:
wrap
;
}
}
.datasource-picker
{
min-width
:
10rem
;
}
.timepicker
{
.timepicker
{
display
:
flex
;
display
:
flex
;
...
...
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