mirror of
https://github.com/grafana/grafana.git
synced 2025-07-29 22:22:25 +08:00
Rewrote and redesign how the data source edit views look and work so they conform better to how account views look, removed tabs and put top nav items to add data source etc, made list, edit and new seperate url routes, #1483
This commit is contained in:
@ -75,6 +75,7 @@ func Register(r *macaron.Macaron) {
|
|||||||
r.Group("/datasources", func() {
|
r.Group("/datasources", func() {
|
||||||
r.Combo("/").Get(GetDataSources).Put(AddDataSource).Post(UpdateDataSource)
|
r.Combo("/").Get(GetDataSources).Put(AddDataSource).Post(UpdateDataSource)
|
||||||
r.Delete("/:id", DeleteDataSource)
|
r.Delete("/:id", DeleteDataSource)
|
||||||
|
r.Get("/:id", GetDataSourceById)
|
||||||
}, reqAccountAdmin)
|
}, reqAccountAdmin)
|
||||||
|
|
||||||
r.Any("/datasources/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest)
|
r.Any("/datasources/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest)
|
||||||
|
@ -9,9 +9,8 @@ import (
|
|||||||
|
|
||||||
func GetDataSources(c *middleware.Context) {
|
func GetDataSources(c *middleware.Context) {
|
||||||
query := m.GetDataSourcesQuery{AccountId: c.AccountId}
|
query := m.GetDataSourcesQuery{AccountId: c.AccountId}
|
||||||
err := bus.Dispatch(&query)
|
|
||||||
|
|
||||||
if err != nil {
|
if err := bus.Dispatch(&query); err != nil {
|
||||||
c.JsonApiErr(500, "Failed to query datasources", err)
|
c.JsonApiErr(500, "Failed to query datasources", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -36,6 +35,34 @@ func GetDataSources(c *middleware.Context) {
|
|||||||
c.JSON(200, result)
|
c.JSON(200, result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetDataSourceById(c *middleware.Context) {
|
||||||
|
query := m.GetDataSourceByIdQuery{
|
||||||
|
Id: c.ParamsInt64(":id"),
|
||||||
|
AccountId: c.AccountId,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := bus.Dispatch(&query); err != nil {
|
||||||
|
c.JsonApiErr(500, "Failed to query datasources", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ds := query.Result
|
||||||
|
|
||||||
|
c.JSON(200, &dtos.DataSource{
|
||||||
|
Id: ds.Id,
|
||||||
|
AccountId: ds.AccountId,
|
||||||
|
Name: ds.Name,
|
||||||
|
Url: ds.Url,
|
||||||
|
Type: ds.Type,
|
||||||
|
Access: ds.Access,
|
||||||
|
Password: ds.Password,
|
||||||
|
Database: ds.Database,
|
||||||
|
User: ds.User,
|
||||||
|
BasicAuth: ds.BasicAuth,
|
||||||
|
IsDefault: ds.IsDefault,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
func DeleteDataSource(c *middleware.Context) {
|
func DeleteDataSource(c *middleware.Context) {
|
||||||
id := c.ParamsInt64(":id")
|
id := c.ParamsInt64(":id")
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@ function (angular, _, $, config) {
|
|||||||
|
|
||||||
if (contextSrv.user.isGrafanaAdmin) {
|
if (contextSrv.user.isGrafanaAdmin) {
|
||||||
$scope.menu.push({
|
$scope.menu.push({
|
||||||
text: "Admin", href: $scope.getUrl("/admin/users"),
|
text: "Admin", href: $scope.getUrl("/admin/settings"),
|
||||||
icon: "fa fa-cube",
|
icon: "fa fa-cube",
|
||||||
requireSignedIn: true,
|
requireSignedIn: true,
|
||||||
});
|
});
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
define([
|
define([
|
||||||
'./accountUsersCtrl',
|
'./accountUsersCtrl',
|
||||||
'./datasourcesCtrl',
|
'./datasourcesCtrl',
|
||||||
|
'./datasourceEditCtrl',
|
||||||
'./apiKeysCtrl',
|
'./apiKeysCtrl',
|
||||||
'./importCtrl',
|
'./importCtrl',
|
||||||
'./accountCtrl',
|
'./accountCtrl',
|
||||||
|
69
src/app/features/account/datasourceEditCtrl.js
Normal file
69
src/app/features/account/datasourceEditCtrl.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
define([
|
||||||
|
'angular',
|
||||||
|
'lodash',
|
||||||
|
],
|
||||||
|
function (angular) {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var module = angular.module('grafana.controllers');
|
||||||
|
|
||||||
|
module.controller('DataSourceEditCtrl', function($scope, $http, backendSrv, $routeParams, $location) {
|
||||||
|
|
||||||
|
var defaults = {
|
||||||
|
name: '',
|
||||||
|
type: 'graphite',
|
||||||
|
url: '',
|
||||||
|
access: 'proxy'
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.types = [
|
||||||
|
{ name: 'Graphite', type: 'graphite' },
|
||||||
|
{ name: 'InfluxDB', type: 'influxdb' },
|
||||||
|
{ name: 'Elasticsearch', type: 'elasticsearch' },
|
||||||
|
{ name: 'OpenTSDB', type: 'opentsdb' },
|
||||||
|
];
|
||||||
|
|
||||||
|
$scope.init = function() {
|
||||||
|
$scope.isNew = true;
|
||||||
|
$scope.datasources = [];
|
||||||
|
|
||||||
|
if ($routeParams.id) {
|
||||||
|
$scope.isNew = false;
|
||||||
|
$scope.getDatasourceById($routeParams.id);
|
||||||
|
} else {
|
||||||
|
$scope.current = angular.copy(defaults);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.getDatasourceById = function(id) {
|
||||||
|
backendSrv.get('/api/datasources/' + id).then(function(ds) {
|
||||||
|
$scope.current = ds;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.update = function() {
|
||||||
|
if (!$scope.editForm.$valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
backendSrv.post('/api/datasources', $scope.current).then(function() {
|
||||||
|
$location.path("account/datasources");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.add = function() {
|
||||||
|
if (!$scope.editForm.$valid) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
backendSrv.put('/api/datasources', $scope.current)
|
||||||
|
.then(function() {
|
||||||
|
$scope.editor.index = 0;
|
||||||
|
$scope.getDatasources();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
$scope.init();
|
||||||
|
|
||||||
|
});
|
||||||
|
});
|
@ -1,5 +1,6 @@
|
|||||||
define([
|
define([
|
||||||
'angular',
|
'angular',
|
||||||
|
'lodash',
|
||||||
],
|
],
|
||||||
function (angular) {
|
function (angular) {
|
||||||
'use strict';
|
'use strict';
|
||||||
@ -8,47 +9,9 @@ function (angular) {
|
|||||||
|
|
||||||
module.controller('DataSourcesCtrl', function($scope, $http, backendSrv) {
|
module.controller('DataSourcesCtrl', function($scope, $http, backendSrv) {
|
||||||
|
|
||||||
var defaults = {
|
|
||||||
name: '',
|
|
||||||
type: 'graphite',
|
|
||||||
url: '',
|
|
||||||
access: 'proxy'
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.types = [
|
|
||||||
{ name: 'Graphite', type: 'graphite' },
|
|
||||||
{ name: 'InfluxDB', type: 'influxdb' },
|
|
||||||
{ name: 'Elasticsearch', type: 'elasticsearch' },
|
|
||||||
{ name: 'OpenTSDB', type: 'opentsdb' },
|
|
||||||
];
|
|
||||||
|
|
||||||
$scope.init = function() {
|
$scope.init = function() {
|
||||||
$scope.reset();
|
|
||||||
$scope.editor = {index: 0};
|
|
||||||
$scope.datasources = [];
|
$scope.datasources = [];
|
||||||
$scope.getDatasources();
|
$scope.getDatasources();
|
||||||
|
|
||||||
$scope.$watch('editor.index', function(newVal) {
|
|
||||||
if (newVal !== 2) {
|
|
||||||
$scope.reset();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.reset = function() {
|
|
||||||
$scope.current = angular.copy(defaults);
|
|
||||||
$scope.currentIsNew = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.edit = function(ds) {
|
|
||||||
$scope.current = ds;
|
|
||||||
$scope.currentIsNew = false;
|
|
||||||
$scope.editor.index = 2;
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.cancel = function() {
|
|
||||||
$scope.reset();
|
|
||||||
$scope.editor.index = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.getDatasources = function() {
|
$scope.getDatasources = function() {
|
||||||
@ -63,25 +26,6 @@ function (angular) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
$scope.update = function() {
|
|
||||||
backendSrv.post('/api/datasources', $scope.current).then(function() {
|
|
||||||
$scope.editor.index = 0;
|
|
||||||
$scope.getDatasources();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.add = function() {
|
|
||||||
if (!$scope.editForm.$valid) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
backendSrv.put('/api/datasources', $scope.current)
|
|
||||||
.then(function() {
|
|
||||||
$scope.editor.index = 0;
|
|
||||||
$scope.getDatasources();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.init();
|
$scope.init();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
74
src/app/features/account/partials/datasourceEdit.html
Normal file
74
src/app/features/account/partials/datasourceEdit.html
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<topnav title="Data sources" icon="fa fa-database" subnav="true">
|
||||||
|
<ul class="nav">
|
||||||
|
<li><a href="account/datasources">Overview</a></li>
|
||||||
|
<li ng-class="{active: isNew}"><a href="account/datasources/new">Add new</a></li>
|
||||||
|
<li class="active" ng-show="!isNew"><a href="account/datasources/edit/{{current.name}}">Edit</a></li>
|
||||||
|
</ul>
|
||||||
|
</topnav>
|
||||||
|
|
||||||
|
<div class="page-container">
|
||||||
|
<div class="page">
|
||||||
|
<h2 ng-show="isNew">Add data source</h2>
|
||||||
|
<h2 ng-show="!isNew">Edit {{current.name}}</h2>
|
||||||
|
|
||||||
|
<form name="editForm">
|
||||||
|
<div class="editor-row">
|
||||||
|
<div class="editor-option">
|
||||||
|
<label class="small">Data source name</label>
|
||||||
|
<input type="text" class="input-large" ng-model='current.name' placeholder="production" required></input>
|
||||||
|
</div>
|
||||||
|
<div class="editor-option">
|
||||||
|
<label class="small">Type</label>
|
||||||
|
<select class="input-medium" ng-model="current.type" ng-options="f.type as f.name for f in types" ng-change="typeChanged()"></select>
|
||||||
|
</div>
|
||||||
|
<editor-opt-bool text="Mark as default" model="current.isDefault" change="render()"></editor-opt-bool>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="editor-row">
|
||||||
|
<div class="editor-option">
|
||||||
|
<label class="small">Url</label>
|
||||||
|
<input type="text" class="input-xxlarge" ng-model='current.url' placeholder="http://my.graphite.com:8080" required></input>
|
||||||
|
</div>
|
||||||
|
<div class="editor-option">
|
||||||
|
<label class="small">Access method <tip>Direct = url is used directly from browser, Proxy = Grafana backend will proxy the request</label>
|
||||||
|
<select class="input-medium" ng-model="current.access" ng-options="f for f in ['direct', 'proxy']"></select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="editor-row" ng-if="current.type === 'influxdb'">
|
||||||
|
<div class="section">
|
||||||
|
<h5>InfluxDB Details</h5>
|
||||||
|
<div class="editor-option">
|
||||||
|
<label class="small">Database name</label>
|
||||||
|
<input type="text" class="input-large" required ng-model='current.database' placeholder=""></input>
|
||||||
|
</div>
|
||||||
|
<div class="editor-option">
|
||||||
|
<label class="small">User</label>
|
||||||
|
<input type="text" class="input-large" ng-model='current.user' placeholder=""></input>
|
||||||
|
</div>
|
||||||
|
<div class="editor-option">
|
||||||
|
<label class="small">Password</label>
|
||||||
|
<input type="password" class="input-large" ng-model='current.password' placeholder=""></input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="editor-row" ng-if="current.type === 'elasticsearch'">
|
||||||
|
<div class="section">
|
||||||
|
<h5>Elastic search details</h5>
|
||||||
|
<div class="editor-option">
|
||||||
|
<label class="small">Index name</label>
|
||||||
|
<input type="text" class="input-large" required ng-model='current.database' placeholder=""></input>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-success" ng-show="isNew" ng-click="add()">Add</button>
|
||||||
|
<button type="submit" class="btn btn-success" ng-show="!isNew" ng-click="update()">Update</button>
|
||||||
|
<a class="btn btn-inverse" ng-show="!isNew" href="account/datasources">Cancel</a>
|
||||||
|
<br>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -1,117 +1,52 @@
|
|||||||
<topnav title="Data sources"
|
<topnav title="Data sources" icon="fa fa-database" subnav="true">
|
||||||
icon="fa fa-database">
|
<ul class="nav">
|
||||||
|
<li class="active" ><a href="account/datasources">Overview</a></li>
|
||||||
|
<li><a href="account/datasources/new">Add new</a></li>
|
||||||
|
</ul>
|
||||||
</topnav>
|
</topnav>
|
||||||
|
|
||||||
<div class="gf-box" style="min-height: 500px; max-width: 900px">
|
<div class="page-container">
|
||||||
<div class="gf-box-header">
|
<div class="page">
|
||||||
<div ng-model="editor.index" bs-tabs style="text-transform:capitalize;">
|
<h2>Data sources</h2>
|
||||||
<div ng-repeat="tab in ['Overview', 'Add', 'Edit']" data-title="{{tab}}">
|
|
||||||
</div>
|
<div ng-if="datasources.length === 0">
|
||||||
|
<em>No datasources defined</em>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<form name="editForm">
|
<table class="grafana-options-table" ng-if="datasources.length > 0">
|
||||||
<div class="gf-box-body">
|
<tr>
|
||||||
<div class="editor-row row" ng-if="editor.index == 0">
|
<td><strong>Name</strong></td>
|
||||||
<div class="span8">
|
<td><strong>Url</strong></td>
|
||||||
<div ng-if="datasources.length === 0">
|
<td></td>
|
||||||
<em>No datasources defined</em>
|
<td></td>
|
||||||
</div>
|
<td></td>
|
||||||
<table class="grafana-options-table" ng-if="datasources.length > 0">
|
</tr>
|
||||||
<tr>
|
<tr ng-repeat="ds in datasources">
|
||||||
<td><strong>Name</strong></td>
|
<td style="width:1%">
|
||||||
<td><strong>Url</strong></td>
|
<i class="fa fa-database"></i>
|
||||||
<td></td>
|
{{ds.name}}
|
||||||
<td></td>
|
</td>
|
||||||
<td></td>
|
<td style="width:90%">
|
||||||
</tr>
|
{{ds.url}}
|
||||||
<tr ng-repeat="ds in datasources">
|
</td>
|
||||||
<td style="width:1%">
|
<td style="width:2%" class="text-center">
|
||||||
<i class="fa fa-database"></i>
|
<span ng-if="ds.isDefault">
|
||||||
{{ds.name}}
|
<span class="label label-info">default</span>
|
||||||
</td>
|
</span>
|
||||||
<td style="width:90%">
|
</td>
|
||||||
{{ds.url}}
|
<td style="width: 1%">
|
||||||
</td>
|
<a href="account/datasources/edit/{{ds.id}}" class="btn btn-inverse btn-mini">
|
||||||
<td style="width:2%" class="text-center">
|
<i class="fa fa-edit"></i>
|
||||||
<span ng-if="ds.isDefault">
|
Edit
|
||||||
<span class="label label-info">default</span>
|
</a>
|
||||||
</span>
|
</td>
|
||||||
</td>
|
<td style="width: 1%">
|
||||||
<td style="width: 1%">
|
<a ng-click="remove(ds)" class="btn btn-danger btn-mini">
|
||||||
<a ng-click="edit(ds)" class="btn btn-success btn-mini">
|
<i class="fa fa-remove"></i>
|
||||||
<i class="fa fa-edit"></i>
|
</a>
|
||||||
Edit
|
</td>
|
||||||
</a>
|
</tr>
|
||||||
</td>
|
</table>
|
||||||
<td style="width: 1%">
|
|
||||||
<a ng-click="remove(ds)" class="btn btn-danger btn-mini">
|
|
||||||
<i class="fa fa-remove"></i>
|
|
||||||
</a>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div ng-if="editor.index == 1 || (editor.index == 2 && !currentIsNew)">
|
|
||||||
<div class="editor-row">
|
|
||||||
<div class="editor-option">
|
|
||||||
<label class="small">Data source name</label>
|
|
||||||
<input type="text" class="input-large" ng-model='current.name' placeholder="production" required></input>
|
|
||||||
</div>
|
|
||||||
<div class="editor-option">
|
|
||||||
<label class="small">Type</label>
|
|
||||||
<select class="input-medium" ng-model="current.type" ng-options="f.type as f.name for f in types" ng-change="typeChanged()"></select>
|
|
||||||
</div>
|
|
||||||
<editor-opt-bool text="Mark as default" model="current.isDefault" change="render()"></editor-opt-bool>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="editor-row">
|
|
||||||
<div class="editor-option">
|
|
||||||
<label class="small">Url</label>
|
|
||||||
<input type="text" class="input-xxlarge" ng-model='current.url' placeholder="http://my.graphite.com:8080" required></input>
|
|
||||||
</div>
|
|
||||||
<div class="editor-option">
|
|
||||||
<label class="small">Access method <tip>Direct = url is used directly from browser, Proxy = Grafana backend will proxy the request</label>
|
|
||||||
<select class="input-medium" ng-model="current.access" ng-options="f for f in ['direct', 'proxy']"></select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="editor-row" ng-if="current.type === 'influxdb'">
|
|
||||||
<div class="section">
|
|
||||||
<h5>InfluxDB Details</h5>
|
|
||||||
<div class="editor-option">
|
|
||||||
<label class="small">Database name</label>
|
|
||||||
<input type="text" class="input-large" required ng-model='current.database' placeholder=""></input>
|
|
||||||
</div>
|
|
||||||
<div class="editor-option">
|
|
||||||
<label class="small">User</label>
|
|
||||||
<input type="text" class="input-large" ng-model='current.user' placeholder=""></input>
|
|
||||||
</div>
|
|
||||||
<div class="editor-option">
|
|
||||||
<label class="small">Password</label>
|
|
||||||
<input type="password" class="input-large" ng-model='current.password' placeholder=""></input>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="editor-row" ng-if="current.type === 'elasticsearch'">
|
|
||||||
<div class="section">
|
|
||||||
<h5>Elastic search details</h5>
|
|
||||||
<div class="editor-option">
|
|
||||||
<label class="small">Index name</label>
|
|
||||||
<input type="text" class="input-large" required ng-model='current.database' placeholder=""></input>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<br>
|
|
||||||
<button type="submit" class="btn btn-success" ng-show="editor.index === 1" ng-click="add()">Add</button>
|
|
||||||
<button type="submit" class="btn btn-success" ng-show="editor.index === 2 && !currentIsNew" ng-click="update()">Update</button>
|
|
||||||
<button type="submit" class="btn btn-inverse" ng-show="editor.index === 2 && !currentIsNew" ng-click="cancel()">Cancel</button>
|
|
||||||
<br>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -38,6 +38,14 @@ define([
|
|||||||
templateUrl: 'app/features/account/partials/datasources.html',
|
templateUrl: 'app/features/account/partials/datasources.html',
|
||||||
controller : 'DataSourcesCtrl',
|
controller : 'DataSourcesCtrl',
|
||||||
})
|
})
|
||||||
|
.when('/account/datasources/edit/:id', {
|
||||||
|
templateUrl: 'app/features/account/partials/datasourceEdit.html',
|
||||||
|
controller : 'DataSourceEditCtrl',
|
||||||
|
})
|
||||||
|
.when('/account/datasources/new', {
|
||||||
|
templateUrl: 'app/features/account/partials/datasourceEdit.html',
|
||||||
|
controller : 'DataSourceEditCtrl',
|
||||||
|
})
|
||||||
.when('/account/users', {
|
.when('/account/users', {
|
||||||
templateUrl: 'app/features/account/partials/users.html',
|
templateUrl: 'app/features/account/partials/users.html',
|
||||||
controller : 'AccountUsersCtrl',
|
controller : 'AccountUsersCtrl',
|
||||||
|
Reference in New Issue
Block a user