mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06: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:
parent
ed0fabd9de
commit
f6c07fdabd
@ -75,6 +75,7 @@ func Register(r *macaron.Macaron) {
|
||||
r.Group("/datasources", func() {
|
||||
r.Combo("/").Get(GetDataSources).Put(AddDataSource).Post(UpdateDataSource)
|
||||
r.Delete("/:id", DeleteDataSource)
|
||||
r.Get("/:id", GetDataSourceById)
|
||||
}, reqAccountAdmin)
|
||||
|
||||
r.Any("/datasources/proxy/:id/*", reqSignedIn, ProxyDataSourceRequest)
|
||||
|
@ -9,9 +9,8 @@ import (
|
||||
|
||||
func GetDataSources(c *middleware.Context) {
|
||||
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)
|
||||
return
|
||||
}
|
||||
@ -36,6 +35,34 @@ func GetDataSources(c *middleware.Context) {
|
||||
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) {
|
||||
id := c.ParamsInt64(":id")
|
||||
|
||||
|
@ -37,7 +37,7 @@ function (angular, _, $, config) {
|
||||
|
||||
if (contextSrv.user.isGrafanaAdmin) {
|
||||
$scope.menu.push({
|
||||
text: "Admin", href: $scope.getUrl("/admin/users"),
|
||||
text: "Admin", href: $scope.getUrl("/admin/settings"),
|
||||
icon: "fa fa-cube",
|
||||
requireSignedIn: true,
|
||||
});
|
||||
|
@ -1,6 +1,7 @@
|
||||
define([
|
||||
'./accountUsersCtrl',
|
||||
'./datasourcesCtrl',
|
||||
'./datasourceEditCtrl',
|
||||
'./apiKeysCtrl',
|
||||
'./importCtrl',
|
||||
'./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([
|
||||
'angular',
|
||||
'lodash',
|
||||
],
|
||||
function (angular) {
|
||||
'use strict';
|
||||
@ -8,47 +9,9 @@ function (angular) {
|
||||
|
||||
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.reset();
|
||||
$scope.editor = {index: 0};
|
||||
$scope.datasources = [];
|
||||
$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() {
|
||||
@ -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();
|
||||
|
||||
});
|
||||
|
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"
|
||||
icon="fa fa-database">
|
||||
<topnav title="Data sources" icon="fa fa-database" subnav="true">
|
||||
<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>
|
||||
|
||||
<div class="gf-box" style="min-height: 500px; max-width: 900px">
|
||||
<div class="gf-box-header">
|
||||
<div ng-model="editor.index" bs-tabs style="text-transform:capitalize;">
|
||||
<div ng-repeat="tab in ['Overview', 'Add', 'Edit']" data-title="{{tab}}">
|
||||
</div>
|
||||
<div class="page-container">
|
||||
<div class="page">
|
||||
<h2>Data sources</h2>
|
||||
|
||||
<div ng-if="datasources.length === 0">
|
||||
<em>No datasources defined</em>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form name="editForm">
|
||||
<div class="gf-box-body">
|
||||
<div class="editor-row row" ng-if="editor.index == 0">
|
||||
<div class="span8">
|
||||
<div ng-if="datasources.length === 0">
|
||||
<em>No datasources defined</em>
|
||||
</div>
|
||||
<table class="grafana-options-table" ng-if="datasources.length > 0">
|
||||
<tr>
|
||||
<td><strong>Name</strong></td>
|
||||
<td><strong>Url</strong></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr ng-repeat="ds in datasources">
|
||||
<td style="width:1%">
|
||||
<i class="fa fa-database"></i>
|
||||
{{ds.name}}
|
||||
</td>
|
||||
<td style="width:90%">
|
||||
{{ds.url}}
|
||||
</td>
|
||||
<td style="width:2%" class="text-center">
|
||||
<span ng-if="ds.isDefault">
|
||||
<span class="label label-info">default</span>
|
||||
</span>
|
||||
</td>
|
||||
<td style="width: 1%">
|
||||
<a ng-click="edit(ds)" class="btn btn-success btn-mini">
|
||||
<i class="fa fa-edit"></i>
|
||||
Edit
|
||||
</a>
|
||||
</td>
|
||||
<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>
|
||||
<table class="grafana-options-table" ng-if="datasources.length > 0">
|
||||
<tr>
|
||||
<td><strong>Name</strong></td>
|
||||
<td><strong>Url</strong></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr ng-repeat="ds in datasources">
|
||||
<td style="width:1%">
|
||||
<i class="fa fa-database"></i>
|
||||
{{ds.name}}
|
||||
</td>
|
||||
<td style="width:90%">
|
||||
{{ds.url}}
|
||||
</td>
|
||||
<td style="width:2%" class="text-center">
|
||||
<span ng-if="ds.isDefault">
|
||||
<span class="label label-info">default</span>
|
||||
</span>
|
||||
</td>
|
||||
<td style="width: 1%">
|
||||
<a href="account/datasources/edit/{{ds.id}}" class="btn btn-inverse btn-mini">
|
||||
<i class="fa fa-edit"></i>
|
||||
Edit
|
||||
</a>
|
||||
</td>
|
||||
<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 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>
|
||||
|
||||
|
@ -38,6 +38,14 @@ define([
|
||||
templateUrl: 'app/features/account/partials/datasources.html',
|
||||
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', {
|
||||
templateUrl: 'app/features/account/partials/users.html',
|
||||
controller : 'AccountUsersCtrl',
|
||||
|
Loading…
Reference in New Issue
Block a user