mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge branch 'master' of github.com:grafana/grafana
This commit is contained in:
commit
74ebc2d3b0
@ -1,6 +1,13 @@
|
|||||||
# http://editorconfig.org
|
# http://editorconfig.org
|
||||||
root = true
|
root = true
|
||||||
|
|
||||||
|
[*.go]
|
||||||
|
indent_style = tabs
|
||||||
|
indent_size = 2
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
|
|
||||||
[*]
|
[*]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
@ -74,6 +74,39 @@ page_keywords: grafana, admin, http, api, documentation, datasource
|
|||||||
"jsonData":null
|
"jsonData":null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
## Get a single data sources by Name
|
||||||
|
|
||||||
|
`GET /api/datasources/name/:name`
|
||||||
|
|
||||||
|
**Example Request**:
|
||||||
|
|
||||||
|
GET /api/datasources/name/test_datasource HTTP/1.1
|
||||||
|
Accept: application/json
|
||||||
|
Content-Type: application/json
|
||||||
|
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||||
|
|
||||||
|
**Example Response**:
|
||||||
|
|
||||||
|
HTTP/1.1 200
|
||||||
|
Content-Type: application/json
|
||||||
|
|
||||||
|
{
|
||||||
|
"id":1,
|
||||||
|
"orgId":1,
|
||||||
|
"name":"test_datasource",
|
||||||
|
"type":"graphite",
|
||||||
|
"access":"proxy",
|
||||||
|
"url":"http://mydatasource.com",
|
||||||
|
"password":"",
|
||||||
|
"user":"",
|
||||||
|
"database":"",
|
||||||
|
"basicAuth":false,
|
||||||
|
"basicAuthUser":"",
|
||||||
|
"basicAuthPassword":"",
|
||||||
|
"isDefault":false,
|
||||||
|
"jsonData":null
|
||||||
|
}
|
||||||
|
|
||||||
## Create data source
|
## Create data source
|
||||||
|
|
||||||
`POST /api/datasources`
|
`POST /api/datasources`
|
||||||
|
@ -53,7 +53,10 @@ Request object passed to datasource.query function
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Expected response from datasource.query
|
There are two different kind of results for datasources.
|
||||||
|
Time series and table. Time series is the most common format and is suppoert by all datasources and panels. Table format is only support by the Influxdb datasource and table panel. But we might se more of this in the future.
|
||||||
|
|
||||||
|
Time series response from datasource.query
|
||||||
An array of
|
An array of
|
||||||
```json
|
```json
|
||||||
[
|
[
|
||||||
@ -74,6 +77,42 @@ An array of
|
|||||||
]
|
]
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Table response from datasource.query
|
||||||
|
An array of
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"columns": [
|
||||||
|
{
|
||||||
|
"text": "Time",
|
||||||
|
"type": "time",
|
||||||
|
"sort": true,
|
||||||
|
"desc": true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "mean",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "sum",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"rows": [
|
||||||
|
[
|
||||||
|
1457425380000,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
],
|
||||||
|
[
|
||||||
|
1457425370000,
|
||||||
|
1002.76215352,
|
||||||
|
1002.76215352
|
||||||
|
],
|
||||||
|
],
|
||||||
|
"type": "table"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
### Annotation Query
|
### Annotation Query
|
||||||
|
|
||||||
Request object passed to datasource.annotationsQuery function
|
Request object passed to datasource.annotationsQuery function
|
||||||
|
@ -174,6 +174,10 @@ func Register(r *macaron.Macaron) {
|
|||||||
r.Get("/plugins", GetDataSourcePlugins)
|
r.Get("/plugins", GetDataSourcePlugins)
|
||||||
}, reqOrgAdmin)
|
}, reqOrgAdmin)
|
||||||
|
|
||||||
|
r.Group("/datasources/name/:name", func() {
|
||||||
|
r.Get("/", wrap(GetDataSourceByName))
|
||||||
|
}, reqOrgAdmin)
|
||||||
|
|
||||||
r.Get("/frontend/settings/", GetFrontendSettings)
|
r.Get("/frontend/settings/", GetFrontendSettings)
|
||||||
r.Any("/datasources/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest)
|
r.Any("/datasources/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest)
|
||||||
r.Any("/datasources/proxy/:id", reqSignedIn, ProxyDataSourceRequest)
|
r.Any("/datasources/proxy/:id", reqSignedIn, ProxyDataSourceRequest)
|
||||||
|
@ -52,24 +52,9 @@ func GetDataSourceById(c *middleware.Context) Response {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ds := query.Result
|
ds := query.Result
|
||||||
|
dtos := convertModelToDtos(ds)
|
||||||
|
|
||||||
return Json(200, &dtos.DataSource{
|
return Json(200, &dtos)
|
||||||
Id: ds.Id,
|
|
||||||
OrgId: ds.OrgId,
|
|
||||||
Name: ds.Name,
|
|
||||||
Url: ds.Url,
|
|
||||||
Type: ds.Type,
|
|
||||||
Access: ds.Access,
|
|
||||||
Password: ds.Password,
|
|
||||||
Database: ds.Database,
|
|
||||||
User: ds.User,
|
|
||||||
BasicAuth: ds.BasicAuth,
|
|
||||||
BasicAuthUser: ds.BasicAuthUser,
|
|
||||||
BasicAuthPassword: ds.BasicAuthPassword,
|
|
||||||
WithCredentials: ds.WithCredentials,
|
|
||||||
IsDefault: ds.IsDefault,
|
|
||||||
JsonData: ds.JsonData,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteDataSource(c *middleware.Context) {
|
func DeleteDataSource(c *middleware.Context) {
|
||||||
@ -132,3 +117,40 @@ func GetDataSourcePlugins(c *middleware.Context) {
|
|||||||
c.JSON(200, dsList)
|
c.JSON(200, dsList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get /api/datasources/name/:name
|
||||||
|
func GetDataSourceByName(c *middleware.Context) Response {
|
||||||
|
query := m.GetDataSourceByNameQuery{Name: c.Params(":name"), OrgId: c.OrgId}
|
||||||
|
|
||||||
|
if err := bus.Dispatch(&query); err != nil {
|
||||||
|
if err == m.ErrDataSourceNotFound {
|
||||||
|
return ApiError(404, "Data source not found", nil)
|
||||||
|
}
|
||||||
|
return ApiError(500, "Failed to query datasources", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ds := query.Result
|
||||||
|
dtos := convertModelToDtos(ds)
|
||||||
|
|
||||||
|
return Json(200, &dtos)
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertModelToDtos(ds m.DataSource) dtos.DataSource {
|
||||||
|
return dtos.DataSource{
|
||||||
|
Id: ds.Id,
|
||||||
|
OrgId: ds.OrgId,
|
||||||
|
Name: ds.Name,
|
||||||
|
Url: ds.Url,
|
||||||
|
Type: ds.Type,
|
||||||
|
Access: ds.Access,
|
||||||
|
Password: ds.Password,
|
||||||
|
Database: ds.Database,
|
||||||
|
User: ds.User,
|
||||||
|
BasicAuth: ds.BasicAuth,
|
||||||
|
BasicAuthUser: ds.BasicAuthUser,
|
||||||
|
BasicAuthPassword: ds.BasicAuthPassword,
|
||||||
|
WithCredentials: ds.WithCredentials,
|
||||||
|
IsDefault: ds.IsDefault,
|
||||||
|
JsonData: ds.JsonData,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -26,8 +26,8 @@ func validateInput(c CommandLine, pluginFolder string) error {
|
|||||||
return errors.New("missing path flag")
|
return errors.New("missing path flag")
|
||||||
}
|
}
|
||||||
|
|
||||||
fileinfo, err := os.Stat(pluginDir)
|
fileInfo, err := os.Stat(pluginDir)
|
||||||
if err != nil && !fileinfo.IsDir() {
|
if err != nil && !fileInfo.IsDir() {
|
||||||
return errors.New("path is not a directory")
|
return errors.New("path is not a directory")
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,11 +49,12 @@ func installCommand(c CommandLine) error {
|
|||||||
log.Infof("version: %v\n", version)
|
log.Infof("version: %v\n", version)
|
||||||
}
|
}
|
||||||
|
|
||||||
return InstallPlugin(pluginToInstall, pluginFolder, version, c.GlobalString("repo"))
|
return InstallPlugin(pluginToInstall, version, c)
|
||||||
}
|
}
|
||||||
|
|
||||||
func InstallPlugin(pluginName, pluginFolder, version, repoUrl string) error {
|
func InstallPlugin(pluginName, version string, c CommandLine) error {
|
||||||
plugin, err := s.GetPlugin(pluginName, repoUrl)
|
plugin, err := s.GetPlugin(pluginName, c.GlobalString("repo"))
|
||||||
|
pluginFolder := c.GlobalString("path")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -85,7 +86,7 @@ func InstallPlugin(pluginName, pluginFolder, version, repoUrl string) error {
|
|||||||
res, _ := s.ReadPlugin(pluginFolder, pluginName)
|
res, _ := s.ReadPlugin(pluginFolder, pluginName)
|
||||||
|
|
||||||
for _, v := range res.Dependency.Plugins {
|
for _, v := range res.Dependency.Plugins {
|
||||||
InstallPlugin(v.Id, pluginFolder, "", repoUrl)
|
InstallPlugin(v.Id, version, c)
|
||||||
log.Infof("Installed Dependency: %v ✔\n", v.Id)
|
log.Infof("Installed Dependency: %v ✔\n", v.Id)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,12 +107,26 @@ func SelectVersion(plugin m.Plugin, version string) (m.Version, error) {
|
|||||||
return m.Version{}, errors.New("Could not find the version your looking for")
|
return m.Version{}, errors.New("Could not find the version your looking for")
|
||||||
}
|
}
|
||||||
|
|
||||||
func RemoveGitBuildFromname(pluginname, filename string) string {
|
func RemoveGitBuildFromName(pluginName, filename string) string {
|
||||||
r := regexp.MustCompile("^[a-zA-Z0-9_.-]*/")
|
r := regexp.MustCompile("^[a-zA-Z0-9_.-]*/")
|
||||||
return r.ReplaceAllString(filename, pluginname+"/")
|
return r.ReplaceAllString(filename, pluginName+"/")
|
||||||
}
|
}
|
||||||
|
|
||||||
func downloadFile(pluginName, filepath, url string) (err error) {
|
var retryCount = 0
|
||||||
|
|
||||||
|
func downloadFile(pluginName, filePath, url string) (err error) {
|
||||||
|
defer func() {
|
||||||
|
if r := recover(); r != nil {
|
||||||
|
retryCount++
|
||||||
|
if retryCount == 1 {
|
||||||
|
log.Debug("\nFailed downloading. Will retry once.\n")
|
||||||
|
downloadFile(pluginName, filePath, url)
|
||||||
|
} else {
|
||||||
|
panic(r)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
resp, err := http.Get(url)
|
resp, err := http.Get(url)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@ -122,24 +137,18 @@ func downloadFile(pluginName, filepath, url string) (err error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
log.Infof("Got statuscode %s from %s\n", resp.Status, url)
|
|
||||||
|
|
||||||
if resp.StatusCode == 302 || resp.StatusCode == 301 {
|
|
||||||
str, _ := ioutil.ReadAll(resp.Body)
|
|
||||||
log.Info("body %s\n\n", string(str))
|
|
||||||
}
|
|
||||||
|
|
||||||
r, err := zip.NewReader(bytes.NewReader(body), resp.ContentLength)
|
r, err := zip.NewReader(bytes.NewReader(body), resp.ContentLength)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, zf := range r.File {
|
for _, zf := range r.File {
|
||||||
newfile := path.Join(filepath, RemoveGitBuildFromname(pluginName, zf.Name))
|
newFile := path.Join(filePath, RemoveGitBuildFromName(pluginName, zf.Name))
|
||||||
|
|
||||||
if zf.FileInfo().IsDir() {
|
if zf.FileInfo().IsDir() {
|
||||||
os.Mkdir(newfile, 0777)
|
os.Mkdir(newFile, 0777)
|
||||||
} else {
|
} else {
|
||||||
dst, err := os.Create(newfile)
|
dst, err := os.Create(newFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Errorf("%v", err)
|
log.Errorf("%v", err)
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ func TestFoldernameReplacement(t *testing.T) {
|
|||||||
|
|
||||||
Convey("should be replaced with plugin name", func() {
|
Convey("should be replaced with plugin name", func() {
|
||||||
for k, v := range paths {
|
for k, v := range paths {
|
||||||
So(RemoveGitBuildFromname(pluginName, k), ShouldEqual, v)
|
So(RemoveGitBuildFromName(pluginName, k), ShouldEqual, v)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -32,7 +32,7 @@ func TestFoldernameReplacement(t *testing.T) {
|
|||||||
|
|
||||||
Convey("should be replaced with plugin name", func() {
|
Convey("should be replaced with plugin name", func() {
|
||||||
for k, v := range paths {
|
for k, v := range paths {
|
||||||
So(RemoveGitBuildFromname(pluginName, k), ShouldEqual, v)
|
So(RemoveGitBuildFromName(pluginName, k), ShouldEqual, v)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
@ -54,7 +54,7 @@ func upgradeAllCommand(c CommandLine) error {
|
|||||||
log.Infof("Upgrading %v \n", p.Id)
|
log.Infof("Upgrading %v \n", p.Id)
|
||||||
|
|
||||||
s.RemoveInstalledPlugin(pluginDir, p.Id)
|
s.RemoveInstalledPlugin(pluginDir, p.Id)
|
||||||
InstallPlugin(p.Id, pluginDir, "", c.GlobalString("repo"))
|
InstallPlugin(p.Id, "", c)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
@ -24,7 +24,7 @@ func upgradeCommand(c CommandLine) error {
|
|||||||
if localPlugin.Id == v.Id {
|
if localPlugin.Id == v.Id {
|
||||||
if ShouldUpgrade(localPlugin.Info.Version, v) {
|
if ShouldUpgrade(localPlugin.Info.Version, v) {
|
||||||
s.RemoveInstalledPlugin(pluginDir, pluginName)
|
s.RemoveInstalledPlugin(pluginDir, pluginName)
|
||||||
return InstallPlugin(localPlugin.Id, pluginDir, "", c.GlobalString("repo"))
|
return InstallPlugin(localPlugin.Id, "", c)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -27,29 +27,71 @@ function (angular, _, kbn) {
|
|||||||
var queryParams = $location.search();
|
var queryParams = $location.search();
|
||||||
var promises = [];
|
var promises = [];
|
||||||
|
|
||||||
|
// use promises to delay processing variables that
|
||||||
|
// depend on other variables.
|
||||||
|
this.variableLock = {};
|
||||||
|
_.forEach(this.variables, function(variable) {
|
||||||
|
self.variableLock[variable.name] = $q.defer();
|
||||||
|
});
|
||||||
|
|
||||||
for (var i = 0; i < this.variables.length; i++) {
|
for (var i = 0; i < this.variables.length; i++) {
|
||||||
var variable = this.variables[i];
|
var variable = this.variables[i];
|
||||||
var urlValue = queryParams['var-' + variable.name];
|
promises.push(this.processVariable(variable, queryParams));
|
||||||
if (urlValue !== void 0) {
|
|
||||||
promises.push(this.setVariableFromUrl(variable, urlValue));
|
|
||||||
}
|
|
||||||
else if (variable.refresh) {
|
|
||||||
promises.push(this.updateOptions(variable));
|
|
||||||
}
|
|
||||||
else if (variable.type === 'interval') {
|
|
||||||
this.updateAutoInterval(variable);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return $q.all(promises);
|
return $q.all(promises);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setVariableFromUrl = function(variable, urlValue) {
|
this.processVariable = function(variable, queryParams) {
|
||||||
var option = _.findWhere(variable.options, { text: urlValue });
|
var dependencies = [];
|
||||||
option = option || { text: urlValue, value: urlValue };
|
var lock = self.variableLock[variable.name];
|
||||||
|
|
||||||
this.updateAutoInterval(variable);
|
// determine our dependencies.
|
||||||
return this.setVariableValue(variable, option);
|
if (variable.type === "query") {
|
||||||
|
_.forEach(this.variables, function(v) {
|
||||||
|
if (templateSrv.containsVariable(variable.query, v.name)) {
|
||||||
|
dependencies.push(self.variableLock[v.name].promise);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return $q.all(dependencies).then(function() {
|
||||||
|
var urlValue = queryParams['var-' + variable.name];
|
||||||
|
if (urlValue !== void 0) {
|
||||||
|
return self.setVariableFromUrl(variable, urlValue).then(lock.resolve);
|
||||||
|
}
|
||||||
|
else if (variable.refresh) {
|
||||||
|
return self.updateOptions(variable).then(function() {
|
||||||
|
if (_.isEmpty(variable.current) && variable.options.length) {
|
||||||
|
console.log("setting current for %s", variable.name);
|
||||||
|
self.setVariableValue(variable, variable.options[0]);
|
||||||
|
}
|
||||||
|
lock.resolve();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
else if (variable.type === 'interval') {
|
||||||
|
self.updateAutoInterval(variable);
|
||||||
|
lock.resolve();
|
||||||
|
} else {
|
||||||
|
lock.resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
this.setVariableFromUrl = function(variable, urlValue) {
|
||||||
|
var promise = $q.when(true);
|
||||||
|
|
||||||
|
if (variable.refresh) {
|
||||||
|
promise = this.updateOptions(variable);
|
||||||
|
}
|
||||||
|
|
||||||
|
return promise.then(function() {
|
||||||
|
var option = _.findWhere(variable.options, { text: urlValue });
|
||||||
|
option = option || { text: urlValue, value: urlValue };
|
||||||
|
|
||||||
|
self.updateAutoInterval(variable);
|
||||||
|
return self.setVariableValue(variable, option, true);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
this.updateAutoInterval = function(variable) {
|
this.updateAutoInterval = function(variable) {
|
||||||
@ -64,7 +106,7 @@ function (angular, _, kbn) {
|
|||||||
templateSrv.setGrafanaVariable('$__auto_interval', interval);
|
templateSrv.setGrafanaVariable('$__auto_interval', interval);
|
||||||
};
|
};
|
||||||
|
|
||||||
this.setVariableValue = function(variable, option) {
|
this.setVariableValue = function(variable, option, initPhase) {
|
||||||
variable.current = angular.copy(option);
|
variable.current = angular.copy(option);
|
||||||
|
|
||||||
if (_.isArray(variable.current.value)) {
|
if (_.isArray(variable.current.value)) {
|
||||||
@ -72,8 +114,14 @@ function (angular, _, kbn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.selectOptionsForCurrentValue(variable);
|
self.selectOptionsForCurrentValue(variable);
|
||||||
|
|
||||||
templateSrv.updateTemplateData();
|
templateSrv.updateTemplateData();
|
||||||
|
|
||||||
|
// on first load, variable loading is ordered to ensure
|
||||||
|
// that parents are updated before children.
|
||||||
|
if (initPhase) {
|
||||||
|
return $q.when();
|
||||||
|
}
|
||||||
|
|
||||||
return self.updateOptionsInChildVariables(variable);
|
return self.updateOptionsInChildVariables(variable);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -145,7 +193,7 @@ function (angular, _, kbn) {
|
|||||||
this.validateVariableSelectionState = function(variable) {
|
this.validateVariableSelectionState = function(variable) {
|
||||||
if (!variable.current) {
|
if (!variable.current) {
|
||||||
if (!variable.options.length) { return; }
|
if (!variable.options.length) { return; }
|
||||||
return self.setVariableValue(variable, variable.options[0]);
|
return self.setVariableValue(variable, variable.options[0], true);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_.isArray(variable.current.value)) {
|
if (_.isArray(variable.current.value)) {
|
||||||
@ -153,7 +201,7 @@ function (angular, _, kbn) {
|
|||||||
} else {
|
} else {
|
||||||
var currentOption = _.findWhere(variable.options, { text: variable.current.text });
|
var currentOption = _.findWhere(variable.options, { text: variable.current.text });
|
||||||
if (currentOption) {
|
if (currentOption) {
|
||||||
return self.setVariableValue(variable, currentOption);
|
return self.setVariableValue(variable, currentOption, true);
|
||||||
} else {
|
} else {
|
||||||
if (!variable.options.length) { return; }
|
if (!variable.options.length) { return; }
|
||||||
return self.setVariableValue(variable, variable.options[0]);
|
return self.setVariableValue(variable, variable.options[0]);
|
||||||
|
@ -1,74 +1,70 @@
|
|||||||
<section class="grafana-metric-options">
|
<section class="grafana-metric-options gf-form-group">
|
||||||
<div class="tight-form">
|
<div class="gf-form-inline">
|
||||||
<ul class="tight-form-list">
|
<div class="gf-form">
|
||||||
<li class="tight-form-item tight-form-item-icon">
|
<span class="gf-form-label">
|
||||||
<i class="fa fa-wrench"></i>
|
<i class="fa fa-wrench"></i>
|
||||||
</li>
|
</span>
|
||||||
<li class="tight-form-item">
|
<span class="gf-form-label width-8">Cache timeout</span>
|
||||||
Cache timeout
|
<input type="text"
|
||||||
</li>
|
class="gf-form-input"
|
||||||
<li>
|
ng-model="ctrl.panelCtrl.panel.cacheTimeout"
|
||||||
<input type="text"
|
bs-tooltip="'Graphite parameter to override memcache default timeout (unit is seconds)'"
|
||||||
class="input-mini tight-form-input"
|
data-placement="right"
|
||||||
ng-model="ctrl.panelCtrl.panel.cacheTimeout"
|
spellcheck='false'
|
||||||
bs-tooltip="'Graphite parameter to override memcache default timeout (unit is seconds)'"
|
placeholder="60">
|
||||||
data-placement="right"
|
</input>
|
||||||
spellcheck='false'
|
</div>
|
||||||
placeholder="60"></input>
|
<div class="gf-form">
|
||||||
</li>
|
<span class="gf-form-label width-10">Max data points</span>
|
||||||
<li class="tight-form-item">
|
<input type="text"
|
||||||
Max data points
|
class="gf-form-input"
|
||||||
</li>
|
ng-model="ctrl.panelCtrl.panel.maxDataPoints"
|
||||||
<li>
|
bs-tooltip="'Override max data points, automatically set to graph width in pixels.'"
|
||||||
<input type="text"
|
data-placement="right"
|
||||||
class="input-mini tight-form-input"
|
ng-model-onblur ng-change="ctrl.panelCtrl.refresh()"
|
||||||
ng-model="ctrl.panelCtrl.panel.maxDataPoints"
|
spellcheck='false'
|
||||||
bs-tooltip="'Override max data points, automatically set to graph width in pixels.'"
|
placeholder="auto">
|
||||||
data-placement="right"
|
</input>
|
||||||
ng-model-onblur ng-change="ctrl.panelCtrl.refresh()"
|
</div>
|
||||||
spellcheck='false'
|
|
||||||
placeholder="auto"></input>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
<div class="clearfix"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="tight-form last">
|
<div class="gf-form-inline">
|
||||||
<ul class="tight-form-list">
|
<div class="gf-form">
|
||||||
<li class="tight-form-item tight-form-item-icon">
|
<span class="gf-form-label width-12">
|
||||||
<i class="fa fa-info-circle"></i>
|
<i class="fa fa-info-circle"></i>
|
||||||
</li>
|
|
||||||
<li class="tight-form-item">
|
|
||||||
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(1);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||||
shorter legend names
|
shorter legend names
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</span>
|
||||||
<li class="tight-form-item">
|
<span class="gf-form-label width-12">
|
||||||
|
<i class="fa fa-info-circle"></i>
|
||||||
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(2);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(2);" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||||
series as parameters
|
series as parameters
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</span>
|
||||||
<li class="tight-form-item">
|
<span class="gf-form-label width-7">
|
||||||
|
<i class="fa fa-info-circle"></i>
|
||||||
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(3)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(3)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||||
stacking
|
stacking
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</span>
|
||||||
<li class="tight-form-item">
|
<span class="gf-form-label width-8">
|
||||||
|
<i class="fa fa-info-circle"></i>
|
||||||
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(4)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(4)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||||
templating
|
templating
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</span>
|
||||||
<li class="tight-form-item">
|
<span class="gf-form-label width-10">
|
||||||
|
<i class="fa fa-info-circle"></i>
|
||||||
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(5)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
<a ng-click="ctrl.panelCtrl.toggleEditorHelp(5)" bs-tooltip="'click to show helpful info'" data-placement="bottom">
|
||||||
max data points
|
max data points
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</span>
|
||||||
</ul>
|
</div>
|
||||||
<div class="clearfix"></div>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<div class="editor-row">
|
<div class="editor-row">
|
||||||
<div class="pull-left" style="margin-top: 30px;">
|
<div class="pull-left">
|
||||||
|
|
||||||
<div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 1">
|
<div class="grafana-info-box span8" ng-if="ctrl.panelCtrl.editorHelpIndex === 1">
|
||||||
<h5>Shorter legend names</h5>
|
<h5>Shorter legend names</h5>
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import './graph';
|
import './graph';
|
||||||
import './legend';
|
import './legend';
|
||||||
import './seriesOverridesCtrl';
|
import './series_overrides_ctrl';
|
||||||
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import kbn from 'app/core/utils/kbn';
|
import kbn from 'app/core/utils/kbn';
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<div class="editor-row">
|
<div class="editor-row gf-form-group">
|
||||||
<div class="section">
|
<div class="section">
|
||||||
<h5>Chart Options</h5>
|
<h5>Chart Options</h5>
|
||||||
<editor-opt-bool text="Bars" model="ctrl.panel.bars" change="ctrl.render()"></editor-opt-bool>
|
<editor-opt-bool text="Bars" model="ctrl.panel.bars" change="ctrl.render()"></editor-opt-bool>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
define([
|
define([
|
||||||
'./helpers',
|
'./helpers',
|
||||||
'app/plugins/panel/graph/seriesOverridesCtrl'
|
'app/plugins/panel/graph/series_overrides_ctrl'
|
||||||
], function(helpers) {
|
], function(helpers) {
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
|
@ -34,12 +34,13 @@ define([
|
|||||||
options: [{text: "test", value: "test"}]
|
options: [{text: "test", value: "test"}]
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function(done) {
|
||||||
var dashboard = { templating: { list: [variable] } };
|
var dashboard = { templating: { list: [variable] } };
|
||||||
var urlParams = {};
|
var urlParams = {};
|
||||||
urlParams["var-apps"] = "new";
|
urlParams["var-apps"] = "new";
|
||||||
ctx.$location.search = sinon.stub().returns(urlParams);
|
ctx.$location.search = sinon.stub().returns(urlParams);
|
||||||
ctx.service.init(dashboard);
|
ctx.service.init(dashboard).then(function() { done(); });
|
||||||
|
ctx.$rootScope.$digest();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update current value', function() {
|
it('should update current value', function() {
|
||||||
@ -56,12 +57,13 @@ define([
|
|||||||
options: [{text: "val1", value: "val1"}, {text: 'val2', value: 'val2'}, {text: 'val3', value: 'val3', selected: true}]
|
options: [{text: "val1", value: "val1"}, {text: 'val2', value: 'val2'}, {text: 'val3', value: 'val3', selected: true}]
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(function() {
|
beforeEach(function(done) {
|
||||||
var dashboard = { templating: { list: [variable] } };
|
var dashboard = { templating: { list: [variable] } };
|
||||||
var urlParams = {};
|
var urlParams = {};
|
||||||
urlParams["var-apps"] = ["val2", "val1"];
|
urlParams["var-apps"] = ["val2", "val1"];
|
||||||
ctx.$location.search = sinon.stub().returns(urlParams);
|
ctx.$location.search = sinon.stub().returns(urlParams);
|
||||||
ctx.service.init(dashboard);
|
ctx.service.init(dashboard).then(function() { done(); });
|
||||||
|
ctx.$rootScope.$digest();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should update current value', function() {
|
it('should update current value', function() {
|
||||||
|
Loading…
Reference in New Issue
Block a user