Commit f8a10fa7 by Torkel Ödegaard

Updated account and profile pages, very temporary solution, do not like it at all

parent e3764ad9
...@@ -12,6 +12,7 @@ var ( ...@@ -12,6 +12,7 @@ var (
type Account struct { type Account struct {
Id int64 Id int64
Version int
Name string Name string
Created time.Time Created time.Time
Updated time.Time Updated time.Time
......
...@@ -17,6 +17,7 @@ type Dashboard struct { ...@@ -17,6 +17,7 @@ type Dashboard struct {
Id int64 Id int64
Slug string Slug string
AccountId int64 AccountId int64
Version int
Created time.Time Created time.Time
Updated time.Time Updated time.Time
......
...@@ -23,6 +23,7 @@ type DsAccess string ...@@ -23,6 +23,7 @@ type DsAccess string
type DataSource struct { type DataSource struct {
Id int64 Id int64
Version int
AccountId int64 AccountId int64
Name string Name string
......
...@@ -12,6 +12,7 @@ var ( ...@@ -12,6 +12,7 @@ var (
type User struct { type User struct {
Id int64 Id int64
Version int
Email string Email string
Name string Name string
Login string Login string
......
...@@ -33,11 +33,13 @@ func addUserMigrations(mg *Migrator) { ...@@ -33,11 +33,13 @@ func addUserMigrations(mg *Migrator) {
mg.AddMigration("create user table", new(AddTableMigration). mg.AddMigration("create user table", new(AddTableMigration).
Name("user").WithColumns( Name("user").WithColumns(
&Column{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, &Column{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
&Column{Name: "version", Type: DB_Int, Nullable: false},
&Column{Name: "login", Type: DB_NVarchar, Length: 255, Nullable: false}, &Column{Name: "login", Type: DB_NVarchar, Length: 255, Nullable: false},
&Column{Name: "email", Type: DB_NVarchar, Length: 255, Nullable: false}, &Column{Name: "email", Type: DB_NVarchar, Length: 255, Nullable: false},
&Column{Name: "name", Type: DB_NVarchar, Length: 255, Nullable: true}, &Column{Name: "name", Type: DB_NVarchar, Length: 255, Nullable: true},
&Column{Name: "password", Type: DB_NVarchar, Length: 255, Nullable: true}, &Column{Name: "password", Type: DB_NVarchar, Length: 255, Nullable: true},
&Column{Name: "salt", Type: DB_NVarchar, Length: 50, Nullable: true}, &Column{Name: "salt", Type: DB_NVarchar, Length: 50, Nullable: true},
&Column{Name: "rands", Type: DB_NVarchar, Length: 50, Nullable: true},
&Column{Name: "company", Type: DB_NVarchar, Length: 255, Nullable: true}, &Column{Name: "company", Type: DB_NVarchar, Length: 255, Nullable: true},
&Column{Name: "account_id", Type: DB_BigInt, Nullable: false}, &Column{Name: "account_id", Type: DB_BigInt, Nullable: false},
&Column{Name: "is_admin", Type: DB_Bool, Nullable: false}, &Column{Name: "is_admin", Type: DB_Bool, Nullable: false},
...@@ -50,9 +52,6 @@ func addUserMigrations(mg *Migrator) { ...@@ -50,9 +52,6 @@ func addUserMigrations(mg *Migrator) {
Table("user").Columns("login").Unique()) Table("user").Columns("login").Unique())
mg.AddMigration("add unique index user.email", new(AddIndexMigration). mg.AddMigration("add unique index user.email", new(AddIndexMigration).
Table("user").Columns("email").Unique()) Table("user").Columns("email").Unique())
mg.AddMigration("add column user.rands", new(AddColumnMigration).
Table("user").Column(&Column{Name: "rands", Type: DB_NVarchar, Length: 255, Nullable: true}))
} }
func addStarMigrations(mg *Migrator) { func addStarMigrations(mg *Migrator) {
...@@ -71,6 +70,7 @@ func addAccountMigrations(mg *Migrator) { ...@@ -71,6 +70,7 @@ func addAccountMigrations(mg *Migrator) {
mg.AddMigration("create account table", new(AddTableMigration). mg.AddMigration("create account table", new(AddTableMigration).
Name("account").WithColumns( Name("account").WithColumns(
&Column{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, &Column{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
&Column{Name: "version", Type: DB_Int, Nullable: false},
&Column{Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false}, &Column{Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false},
&Column{Name: "created", Type: DB_DateTime, Nullable: false}, &Column{Name: "created", Type: DB_DateTime, Nullable: false},
&Column{Name: "updated", Type: DB_DateTime, Nullable: false}, &Column{Name: "updated", Type: DB_DateTime, Nullable: false},
...@@ -98,6 +98,7 @@ func addDashboardMigration(mg *Migrator) { ...@@ -98,6 +98,7 @@ func addDashboardMigration(mg *Migrator) {
mg.AddMigration("create dashboard table", new(AddTableMigration). mg.AddMigration("create dashboard table", new(AddTableMigration).
Name("dashboard").WithColumns( Name("dashboard").WithColumns(
&Column{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, &Column{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
&Column{Name: "version", Type: DB_Int, Nullable: false},
&Column{Name: "slug", Type: DB_NVarchar, Length: 255, Nullable: false}, &Column{Name: "slug", Type: DB_NVarchar, Length: 255, Nullable: false},
&Column{Name: "title", Type: DB_NVarchar, Length: 255, Nullable: false}, &Column{Name: "title", Type: DB_NVarchar, Length: 255, Nullable: false},
&Column{Name: "data", Type: DB_Text, Nullable: false}, &Column{Name: "data", Type: DB_Text, Nullable: false},
...@@ -129,6 +130,7 @@ func addDataSourceMigration(mg *Migrator) { ...@@ -129,6 +130,7 @@ func addDataSourceMigration(mg *Migrator) {
Name("data_source").WithColumns( Name("data_source").WithColumns(
&Column{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true}, &Column{Name: "id", Type: DB_BigInt, IsPrimaryKey: true, IsAutoIncrement: true},
&Column{Name: "account_id", Type: DB_BigInt, Nullable: false}, &Column{Name: "account_id", Type: DB_BigInt, Nullable: false},
&Column{Name: "version", Type: DB_Int, Nullable: false},
&Column{Name: "type", Type: DB_NVarchar, Length: 255, Nullable: false}, &Column{Name: "type", Type: DB_NVarchar, Length: 255, Nullable: false},
&Column{Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false}, &Column{Name: "name", Type: DB_NVarchar, Length: 255, Nullable: false},
&Column{Name: "access", Type: DB_NVarchar, Length: 255, Nullable: false}, &Column{Name: "access", Type: DB_NVarchar, Length: 255, Nullable: false},
......
...@@ -17,10 +17,9 @@ function (angular, _, $, config) { ...@@ -17,10 +17,9 @@ function (angular, _, $, config) {
$scope.menu = []; $scope.menu = [];
$scope.menu.push({ $scope.menu.push({
text: "Dashbords", text: "Dashboards",
icon: "fa fa-th-large", icon: "fa fa-th-large",
href: $scope.getUrl("/"), href: $scope.getUrl("/"),
//startsWith: config.appSubUrl + '/dashboard/',
}); });
if ($scope.grafana.user.accountRole === 'Admin') { if ($scope.grafana.user.accountRole === 'Admin') {
...@@ -34,16 +33,6 @@ function (angular, _, $, config) { ...@@ -34,16 +33,6 @@ function (angular, _, $, config) {
requireRole: "Admin", requireRole: "Admin",
icon: "fa fa-shield", icon: "fa fa-shield",
}); });
$scope.menu.push({
text: "Users", href: $scope.getUrl("/account/users"),
requireRole: "Admin",
icon: "fa fa-users",
});
$scope.menu.push({
text: "API Keys", href: $scope.getUrl("/account/apikeys"),
requireRole: "Admin",
icon: "fa fa-key",
});
} }
if ($scope.grafana.user.isGrafanaAdmin) { if ($scope.grafana.user.isGrafanaAdmin) {
......
...@@ -13,7 +13,6 @@ function (angular) { ...@@ -13,7 +13,6 @@ function (angular) {
transclude: true, transclude: true,
scope: { scope: {
title: "@", title: "@",
section: "@",
titleAction: "&", titleAction: "&",
toggle: "&", toggle: "&",
showMenuBtn: "=", showMenuBtn: "=",
...@@ -23,16 +22,11 @@ function (angular) { ...@@ -23,16 +22,11 @@ function (angular) {
'<div class="top-nav">' + '<div class="top-nav">' +
'<a class="top-nav-menu-btn pointer" ng-if="showMenuBtn" ng-click="toggle()">' + '<a class="top-nav-menu-btn pointer" ng-if="showMenuBtn" ng-click="toggle()">' +
'<img class="logo-icon" src="img/fav32.png"></img> ' + '<img class="logo-icon" src="img/fav32.png"></img> ' +
'<i class="fa fa-angle-right"></i>' + '<i class="fa fa-bars"></i>' +
'</a>' + '</a>' +
'<span class="top-nav-breadcrumb">' + '<span class="icon-circle top-nav-icon"">' +
'<i class="top-nav-icon" ng-class="icon"></i>' + '<i ng-class="icon"></i>' +
'</span>' +
'<span class="top-nav-section" ng-show="section">' +
'{{section}}' +
'<i class="fa fa-angle-right"></i>' +
'</span>' + '</span>' +
'<a ng-click="titleAction()" class="top-nav-title">' + '<a ng-click="titleAction()" class="top-nav-title">' +
......
<topnav toggle="toggleSideMenu()" icon="fa fa-shield" section="Account" show-menu-btn="!grafana.sidemenu"> <topnav toggle="toggleSideMenu()" icon="fa fa-shield" title="Account" show-menu-btn="!grafana.sidemenu">
</topnav> </topnav>
<div class="gf-box" style="min-height: 500px"> <div class="admin-page">
<h2>
Account Info
</h2>
<div class="gf-box" style="">
<div class="gf-box-body"> <div class="gf-box-body">
<div class="row editor-row">
<div class="section">
<form name="accountForm"> <form name="accountForm">
<div> <div>
<div class="tight-form"> <div class="tight-form">
...@@ -27,6 +29,158 @@ ...@@ -27,6 +29,158 @@
</form> </form>
</div> </div>
</div> </div>
<h2>
Account users
</h2>
<div class="gf-box" ng-controller="AccountUsersCtrl">
<div class="gf-box-body">
<div class="editor-row">
<div class="section">
<form name="form">
<div class="tight-form">
<ul class="tight-form-list">
<li class="tight-form-item" style="width: 160px">
<strong>Username or Email</strong>
</li>
<li>
<input type="text" ng-model="user.loginOrEmail" required class="input-xlarge tight-form-input" placeholder="user@email.com or username">
</li>
<li class="tight-form-item">
role
</li>
<li>
<select type="text" ng-model="user.role" class="input-small tight-form-input" ng-options="f for f in ['Viewer', 'Editor', 'Admin']">
</select>
</li>
<li>
<button class="btn btn-success tight-form-btn" ng-click="addUser()">Add</button>
</li>
</ul>
<div class="clearfix"></div>
</div>
</form>
</div>
</div>
<div class="editor-row row">
<table class="grafana-options-table span5">
<tr ng-repeat="user in users">
<td>{{user.email}}</td>
<td>
{{user.role}}
</td>
<td style="width: 1%">
<a ng-click="removeUser(user)" class="btn btn-danger btn-mini">
<i class="fa fa-remove"></i>
</a>
</td>
</tr>
</table>
</div>
</div>
</div>
<h2>
API Keys
</h2>
<div class="gf-box" ng-controller="ApiKeysCtrl">
<div class="gf-box-body">
<div class="editor-row">
<div class="section">
<form name="addTokenrForm" class="form-inline tight-form">
<ul class="tight-form-list">
<li class="tight-form-item">
Add a key
</li>
<li>
<input type="text" class="input-xlarge tight-form-input" ng-model='token.name' placeholder="Name"></input>
</li>
<li class="tight-form-item">
Role
</li>
<li>
<select class="input-small tight-form-input" ng-model="token.role" ng-options="r for r in roleTypes"></select>
</li>
<li>
<button class="btn btn-success tight-form-btn" ng-click="addToken()">Add</button>
</li>
</ul>
<div class="clearfix"></div>
</form>
</div>
</div>
<div class="editor-row">
<div class="section">
<table class="grafana-options-table">
<tr ng-repeat="t in tokens">
<td>{{t.name}}</td>
<td>{{t.role}}</td>
<td>{{t.key}}</td>
<td style="width: 1%">
<a ng-click="removeToken(t.id)" class="btn btn-danger btn-mini">
<i class="fa fa-remove"></i>
</a>
</td>
</tr>
</table>
</div>
</div>
</div>
</div>
<h2>Import dashboards</h2>
<div class="gf-box" ng-controller="ImportCtrl">
<div class="gf-box-body">
<div class="editor-row">
<div class="section">
<div class="tight-form">
<ul class="tight-form-list">
<li class="tight-form-item" style="width: 150px">
<strong>Dashboard source</strong>
</li>
<li>
<select type="text" ng-model="sourceName" class="input-medium tight-form-input" ng-options="f for f in datasources">
</select>
</li>
<li class="tight-form-item">
<strong>Destination</strong>
</li>
<li>
<select type="text" ng-model="destName" class="input-medium tight-form-input" ng-options="f for f in datasources">
</select>
</li>
<li>
<button class="btn btn-success tight-form-btn" ng-click="startImport()">Import</button>
</li>
</ul>
<div class="clearfix"></div>
</div>
</div>
</div>
<div class="editor-row" ng-if="importing">
<section class="section">
<h5>{{infoText}}</h5>
<div class="editor-row row">
<table class="grafana-options-table span5">
<tr ng-repeat="dash in imported">
<td>{{dash.name}}</td>
<td>
{{dash.info}}
</td>
</tr>
</table>
</div>
</section>
</div>
</div>
</div> </div>
</div> </div>
......
<topnav toggle="toggleSideMenu()" <topnav toggle="toggleSideMenu()"
title="Data sources" title="Data sources"
icon="fa fa-shield" icon="fa fa-database"
section="Account"
show-menu-btn="!grafana.sidemenu"> show-menu-btn="!grafana.sidemenu">
</topnav> </topnav>
<div class="gf-box" style="min-height: 500px"> <div class="gf-box" style="min-height: 500px; max-width: 900px">
<div class="gf-box-header"> <div class="gf-box-header">
<div ng-model="editor.index" bs-tabs style="text-transform:capitalize;"> <div ng-model="editor.index" bs-tabs style="text-transform:capitalize;">
<div ng-repeat="tab in ['Overview', 'Add', 'Edit']" data-title="{{tab}}"> <div ng-repeat="tab in ['Overview', 'Add', 'Edit']" data-title="{{tab}}">
...@@ -117,3 +116,4 @@ ...@@ -117,3 +116,4 @@
</form> </form>
</div> </div>
</div> </div>
...@@ -27,7 +27,6 @@ function (angular) { ...@@ -27,7 +27,6 @@ function (angular) {
backendSrv.delete('/api/admin/users/delete/' + user.id); backendSrv.delete('/api/admin/users/delete/' + user.id);
} }
}); });
}; };
$scope.init(); $scope.init();
......
<topnav toggle="toggleSideMenu()" <topnav toggle="toggleSideMenu()"
title="Users" title="Admin"
icon="fa fa-cube" icon="fa fa-cube"
section="Admin"
show-menu-btn="!grafana.sidemenu"> show-menu-btn="!grafana.sidemenu">
</topnav> </topnav>
......
<topnav toggle="toggleSideMenu()" <topnav toggle="toggleSideMenu()"
title="Users" title="Admin"
icon="fa fa-cube" icon="fa fa-cube"
section="Admin"
show-menu-btn="!grafana.sidemenu"> show-menu-btn="!grafana.sidemenu">
</topnav> </topnav>
<div class="gf-box" style="min-height: 500px"> <div class="admin-page">
<h2> Users </h2>
<div class="gf-box" style="min-height: 500px">
<div class="gf-box-body"> <div class="gf-box-body">
<div class="editor-row row"> <div class="editor-row row">
...@@ -40,4 +41,5 @@ ...@@ -40,4 +41,5 @@
</div> </div>
</div> </div>
</div> </div>
</div>
</div> </div>
<topnav toggle="toggleSideMenu()" <topnav toggle="toggleSideMenu()"
title="Details" title="Profile"
icon="fa fa-user" icon="fa fa-user"
section="Profile"
show-menu-btn="!grafana.sidemenu"> show-menu-btn="!grafana.sidemenu">
</topnav> </topnav>
<div class="admin-page">
<div class="editor-row"> <h2>Personal information</h2>
<div class="section">
<div class="gf-box"> <div class="gf-box">
<div class="gf-box-header"> <div class="gf-box-body editor-row">
<div class="gf-box-title"> <div class="section">
<i class="fa fa-user"></i>
Personal information
</div>
</div>
<div class="gf-box-body">
<div class="row">
<form name="userForm"> <form name="userForm">
<div> <div>
<div class="tight-form"> <div class="tight-form">
...@@ -62,29 +53,20 @@ ...@@ -62,29 +53,20 @@
</div> </div>
</div> </div>
</div> </div>
</div>
<div class="section"> <h2>Your accounts</h2>
<div class="gf-box"> <div class="gf-box">
<div class="gf-box-header">
<div class="gf-box-title">
<i class="fa fa-shield"></i>
Your accounts
</div>
</div>
<div class="gf-box-body"> <div class="gf-box-body">
<table class="grafana-options-table"> <table class="grafana-options-table">
<tr ng-repeat="ac in accounts"> <tr ng-repeat="ac in accounts">
<td>Name: {{ac.name}}</td> <td style="width: 98%">Name: {{ac.name}}</td>
<td>Role: {{ac.role}}</td> <td>Role: {{ac.role}}</td>
<td ng-show="ac.isUsing"> <td>
<span class="label label-info"> <span class="btn btn-primary" ng-show="ac.isUsing">
active now Current
</span> </span>
</td> <a ng-click="setUsingAccount(ac)" class="btn btn-inverse" ng-show="!ac.isUsing">
<td ng-show="!ac.isUsing">
<a ng-click="setUsingAccount(ac)" class="btn btn-success btn-mini">
Select Select
</a> </a>
</td> </td>
...@@ -92,36 +74,32 @@ ...@@ -92,36 +74,32 @@
</table> </table>
</div> </div>
</div> </div>
</div>
<div class="section"> <h2>Add account</h2>
<div class="gf-box"> <div class="gf-box">
<div class="gf-box-header"> <div class="gf-box-body editor-row">
<div class="gf-box-title"> <div class="section">
<i class="fa fa-plus-square"></i>
Add account
</div>
</div>
<div class="gf-box-body">
<form name="form"> <form name="form">
<div>
<div class="tight-form"> <div class="tight-form">
<ul class="tight-form-list"> <ul class="tight-form-list">
<li class="tight-form-item"> <li class="tight-form-item">
<strong>Account name</strong> <strong>Account name</strong>
</li> </li>
<li> <li>
<input type="text" ng-model="newAccount.name" required class="input-xlarge tight-form-input" placeholder="account name"> <input type="text" ng-model="newAccount.name" required class="input-xxlarge tight-form-input last" placeholder="account name">
</li> </li>
<li> <li>
<button class="btn btn-success tight-form-btn" ng-click="createAccount()">Create</button>
</li> </li>
</ul> </ul>
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
</form> </div>
<br>
<button class="btn btn-success pull-right" ng-click="createAccount()">Create</button>
</div> </div>
</div> </div>
</form>
</div> </div>
</div> </div>
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<li ng-repeat="item in menu"> <li ng-repeat="item in menu">
<a href="{{item.href}}" class="sidemenu-item" target="{{item.target}}"> <a href="{{item.href}}" class="sidemenu-item" target="{{item.target}}">
<span class="sidemenu-icon"><i class="{{item.icon}}"></i></span> <span class="icon-circle sidemenu-icon"><i class="{{item.icon}}"></i></span>
<span class="sidemenu-item-text">{{item.text}}</span> <span class="sidemenu-item-text">{{item.text}}</span>
</a> </a>
</li> </li>
......
...@@ -59,3 +59,22 @@ ...@@ -59,3 +59,22 @@
} }
} }
.admin-page {
max-width: 800px;
margin-left: 10px;
.gf-box {
margin-top: 0;
}
.gf-box-body {
min-height: 0;
}
h2 {
margin-left: 15px;
margin-bottom: 0px;
font-size: @fontSizeLarge;
color: @textColor;
i {
padding-right: 6px;
}
}
}
...@@ -37,13 +37,13 @@ ...@@ -37,13 +37,13 @@
font-size: 150%; font-size: 150%;
opacity: 0; opacity: 0;
position: absolute; position: absolute;
transition: opacity .35s ease-in-out; transition: opacity .20s ease-in-out;
} }
img { img {
width: 30px; width: 30px;
position: absolute; position: absolute;
opacity: 1; opacity: 1;
transition: opacity .35s ease-in-out; transition: opacity .20s ease-in-out;
} }
&:hover { &:hover {
.fa { .fa {
...@@ -68,7 +68,7 @@ ...@@ -68,7 +68,7 @@
a { a {
display: inline-block; display: inline-block;
background: @grafanaTargetFuncBackground; background: @grafanaTargetFuncBackground;
padding: 5px 4px 5px 13px; padding: 5px 15px 5px 10px;
border: 1px solid #000; border: 1px solid #000;
border-radius: 3px; border-radius: 3px;
color: #a2a2a2; color: #a2a2a2;
...@@ -88,16 +88,10 @@ ...@@ -88,16 +88,10 @@
} }
} }
.top-nav-breadcrumb { .top-nav-icon {
display: block; line-height: 34px;
float: left; float: left;
padding: 18px 9px 8px 12px; margin: 5px 11px;
font-size: 1.4em;
font-weight: bold;
color: darken(@gray, 10%);
i {
padding-left: 9px;
}
} }
.top-nav-section { .top-nav-section {
......
...@@ -72,7 +72,7 @@ ...@@ -72,7 +72,7 @@
} }
} }
.sidemenu-icon { .icon-circle {
border-radius: 50%; border-radius: 50%;
background: #000; background: #000;
box-shadow: 0 0 14px 2px rgba(255,255,255, 0.05); box-shadow: 0 0 14px 2px rgba(255,255,255, 0.05);
...@@ -89,6 +89,9 @@ ...@@ -89,6 +89,9 @@
} }
} }
.sidemenu-icon {
}
.sidemenu-item { .sidemenu-item {
color: #f80; color: #f80;
line-height: 34px; line-height: 34px;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment