Refactoring views to use modals for create/edit instead of their own pages.

This commit is contained in:
kevgliss 2015-07-10 17:08:39 -07:00
parent 1e902750c3
commit c79905cd92
31 changed files with 533 additions and 529 deletions

View File

@ -2,17 +2,6 @@
angular.module('lemur') angular.module('lemur')
.config(function config($routeProvider) {
$routeProvider.when('/authorities/create', {
templateUrl: '/angular/authorities/authority/authorityWizard.tpl.html',
controller: 'AuthorityCreateController'
});
$routeProvider.when('/authorities/:id/edit', {
templateUrl: '/angular/authorities/authority/authorityEdit.tpl.html',
controller: 'AuthorityEditController'
});
})
.controller('AuthorityEditController', function ($scope, $routeParams, AuthorityApi, AuthorityService, RoleService){ .controller('AuthorityEditController', function ($scope, $routeParams, AuthorityApi, AuthorityService, RoleService){
AuthorityApi.get($routeParams.id).then(function (authority) { AuthorityApi.get($routeParams.id).then(function (authority) {
AuthorityService.getRoles(authority); AuthorityService.getRoles(authority);
@ -24,16 +13,21 @@ angular.module('lemur')
$scope.roleService = RoleService; $scope.roleService = RoleService;
}) })
.controller('AuthorityCreateController', function ($scope, $modal, AuthorityService, LemurRestangular, RoleService) { .controller('AuthorityCreateController', function ($scope, $modalInstance, AuthorityService, LemurRestangular, RoleService, PluginService, WizardHandler) {
$scope.authority = LemurRestangular.restangularizeElement(null, {}, 'authorities'); $scope.authority = LemurRestangular.restangularizeElement(null, {}, 'authorities');
$scope.save = function (authority) { $scope.loading = false;
var loadingModal = $modal.open({backdrop: 'static', template: '<wave-spinner></wave-spinner>', windowTemplateUrl: 'angular/loadingModal.html', size: 'large'}); $scope.create = function (authority) {
return AuthorityService.create(authority).then(function (response) { WizardHandler.wizard().context.loading = true;
loadingModal.close(); AuthorityService.create(authority).then(function (resposne) {
}); WizardHandler.wizard().context.loading = false;
$modalInstance.close();
})
}; };
PluginService.get('issuer').then(function (plugins) {
$scope.plugins = plugins;
});
$scope.roleService = RoleService; $scope.roleService = RoleService;

View File

@ -1,17 +1,21 @@
<h2 class="featurette-heading"><span ng-show="!authority.id">Create</span><span ng-show="authority.id">Edit</span> Authority <span class="text-muted"><small>The nail that sticks out farthest gets hammered the hardest <div class="modal-header">
<div> <h3 class="modal-title"><span ng-show="!authority.id">Create</span><span ng-show="authority.id">Edit</span> Authority <span class="text-muted"><small>The nail that sticks out farthest gets hammered the hardest</small></span></h3>
<wizard on-finish="save(authority)" template="angular/wizard.html"> </div>
<wz-step title="Tracking" canexit="exitTracking"> <div class="modal-body">
<ng-include src="'angular/authorities/authority/tracking.tpl.html'"></ng-include> <div>
</wz-step> <wizard on-finish="create(authority)" template="angular/wizard.html">
<wz-step title="Distinguished Name" canenter="exitTracking" canexit="exitDN"> <wz-step title="Tracking" canexit="exitTracking">
<ng-include src="'angular/authorities/authority/distinguishedName.tpl.html'"></ng-include> <ng-include src="'angular/authorities/authority/tracking.tpl.html'"></ng-include>
</wz-step> </wz-step>
<wz-step title="Options" canenter="exitDN" canexit="exitOptions"> <wz-step title="Options" canenter="exitDN" canexit="exitOptions">
<ng-include src="'angular/authorities/authority/options.tpl.html'"></ng-include> <ng-include src="'angular/authorities/authority/options.tpl.html'"></ng-include>
</wz-step> </wz-step>
<wz-step title="Extensions" canenter="exitOptions" canexit="exitExtensions"> <wz-step title="Distinguished Name" canenter="exitTracking" canexit="exitDN">
<ng-include src="'angular/authorities/authority/extensions.tpl.html'"></ng-include> <ng-include src="'angular/authorities/authority/distinguishedName.tpl.html'"></ng-include>
</wz-step> </wz-step>
</wizard> <wz-step title="Extensions" canenter="exitOptions" canexit="exitExtensions">
<ng-include src="'angular/authorities/authority/extensions.tpl.html'"></ng-include>
</wz-step>
</wizard>
</div>
</div> </div>

View File

@ -15,7 +15,7 @@
<input type="text" ng-model="authority.caParent" placeholder="Parent Authority Name" <input type="text" ng-model="authority.caParent" placeholder="Parent Authority Name"
typeahead="authority.name for authority in authorityService.findAuthorityByName($viewValue)" typeahead-loading="loadingAuthorities" typeahead="authority.name for authority in authorityService.findAuthorityByName($viewValue)" typeahead-loading="loadingAuthorities"
class="form-control input-md" typeahead-min-wait="50" class="form-control input-md" typeahead-min-wait="50"
tooltip="When you specifiy a subordinate certificate authority you must specific the parent authority" tooltip="When you specify a subordinate certificate authority you must specific the parent authority"
tooltip-trigger="focus" tooltip-placement="top"> tooltip-trigger="focus" tooltip-placement="top">
</div> </div>
</div> </div>
@ -69,10 +69,10 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-sm-2"> <label class="control-label col-sm-2">
Plugin Name Plugin
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<select class="form-control" ng-model="authority.pluginName" ng-options="option for option in ['cloudca', 'verisign']" ng-init="authority.pluginName = 'cloudca'" required></select> <select class="form-control" ng-model="authority.pluginName" ng-options="plugin.slug as plugin.title for plugin in plugins" ng-init="authority.pluginName = 'cloudca-issuer'" required></select>
</div> </div>
</div> </div>
</div> </div>

View File

@ -31,37 +31,40 @@
</div> </div>
</div> </div>
<div class="form-group" <div class="form-group"
ng-class="{'has-error': trackingForm.commonName.$invalid, 'has-success': !trackingForm.$invalid&&trackingForm.commanName.$dirty}"> ng-class="{'has-error': trackingForm.commonName.$invalid, 'has-success': !trackingForm.$invalid&&trackingForm.commonName.$dirty}">
<label class="control-label col-sm-2"> <label class="control-label col-sm-2">
Common Name Common Name
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<input name="commonName" ng-model="authority.caDN.commonName" placeholder="Common Name" class="form-control" required/> <input name="commonName" ng-model="authority.caDN.commonName" placeholder="Common Name" class="form-control" required/>
<p ng-show="trackingForm.commandName.$invalid && !trackingForm.commonName.$pristine" class="help-block">You must enter a common name</p> <p ng-show="trackingForm.commonName.$invalid && !trackingForm.commonName.$pristine" class="help-block">You must enter a common name</p>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group"
ng-class="{'has-error': trackingForm.validityEnd.$invalid || trackingForm.validityStart.$invalid, 'has-success': !trackingForm.$invalid&&trackingForm.validityEnd.$dirty&&trackingForm.validityStart.$dirty}">
<label class="control-label col-sm-2"> <label class="control-label col-sm-2">
Validity Range Validity Range
</label> </label>
<div class="col-sm-4"> <div class="col-sm-4">
<div> <div>
<div class="input-group"> <div class="input-group">
<input tooltip="Starting Date" class="form-control" datepicker-popup="yyyy/MM/dd" is-open="opened1" ng-model="authority.validityStart" /> <input name="validityStart" tooltip="Starting Date" class="form-control" datepicker-popup="yyyy/MM/dd" is-open="opened1" ng-model="authority.validityStart" required/>
<span class="input-group-btn"> <p ng-show="trackingForm.validityStart.$invalid && !trackingForm.validityStart.$pristine" class="help-block">A start date is required!</p>
<button class="btn btn-default" ng-click="open($event)"><i class="glyphicon glyphicon-calendar"></i></button> <span class="input-group-btn">
</span> <button class="btn btn-default" ng-click="open($event)"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</div> </div>
</div> </div>
</div> </div>
<span class="text-center col-sm-2"><label><span class="glyphicon glyphicon-resize-horizontal"></span></label></span> <span style="padding-top: 15px" class="text-center col-sm-2"><label><span class="glyphicon glyphicon-resize-horizontal"></span></label></span>
<div class="col-sm-4"> <div class="col-sm-4">
<div> <div>
<div class="input-group"> <div class="input-group">
<input tooltip="Ending Date" class="form-control" datepicker-popup="yyyy/MM/dd" is-open="opened2" ng-model="authority.validityEnd" /> <input name="validityEnd" tooltip="Ending Date" class="form-control" datepicker-popup="yyyy/MM/dd" is-open="opened2" ng-model="authority.validityEnd" required/>
<span class="input-group-btn"> <p ng-show="trackingForm.validityEnd.$invalid && !trackingForm.validityEnd.$pristine" class="help-block">A end date is required!</p>
<button class="btn btn-default" ng-click="open2($event)"><i class="glyphicon glyphicon-calendar"></i></button> <span class="input-group-btn">
</span> <button class="btn btn-default" ng-click="open2($event)"><i class="glyphicon glyphicon-calendar"></i></button>
</span>
</div> </div>
</div> </div>
</div> </div>

View File

@ -9,7 +9,7 @@ angular.module('lemur')
}); });
}) })
.controller('AuthoritiesViewController', function ($scope, $q, AuthorityApi, AuthorityService, ngTableParams) { .controller('AuthoritiesViewController', function ($scope, $q, $modal, AuthorityApi, AuthorityService, ngTableParams) {
$scope.filter = {}; $scope.filter = {};
$scope.authoritiesTable = new ngTableParams({ $scope.authoritiesTable = new ngTableParams({
page: 1, // show first page page: 1, // show first page
@ -43,4 +43,36 @@ angular.module('lemur')
params.settings().$scope.show_filter = !params.settings().$scope.show_filter; params.settings().$scope.show_filter = !params.settings().$scope.show_filter;
}; };
$scope.edit = function (authorityId) {
var modalInstance = $modal.open({
animation: true,
templateUrl: '/angular/authorities/authority/authorityWizard.tpl.html',
controller: 'AuthorityEditController',
size: 'lg',
resolve: {
editId: function () {
return authorityId;
}
}
});
modalInstance.result.then(function () {
$scope.authoritiesTable.reload();
});
};
$scope.create = function () {
var modalInstance = $modal.open({
animation: true,
controller: 'AuthorityCreateController',
templateUrl: '/angular/authorities/authority/authorityWizard.tpl.html',
size: 'lg'
});
modalInstance.result.then(function () {
$scope.authoritiesTable.reload();
});
};
}); });

View File

@ -5,7 +5,7 @@
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<div class="btn-group pull-right"> <div class="btn-group pull-right">
<a href="#/authorities/create" class="btn btn-primary">Create</a> <button class="btn btn-primary" ng-click="create()">Create</button>
</div> </div>
<div class="btn-group"> <div class="btn-group">
<button ng-click="toggleFilter(authoritiesTable)" class="btn btn-default">Filter</button> <button ng-click="toggleFilter(authoritiesTable)" class="btn btn-default">Filter</button>
@ -36,9 +36,9 @@
</td> </td>
<td data-title="''"> <td data-title="''">
<div class="btn-group-vertical pull-right"> <div class="btn-group-vertical pull-right">
<a tooltip="Edit Authority" href="#/authorities/{{ authority.id }}/edit" class="btn btn-sm btn-info"> <button tooltip="Edit Authority" ng-click="edit(authority.id)" class="btn btn-sm btn-info">
Edit Edit
</a> </button>
</div> </div>
</td> </td>
</tr> </tr>

View File

@ -1,18 +1,6 @@
'use strict'; 'use strict';
angular.module('lemur') angular.module('lemur')
.config(function config($routeProvider) {
$routeProvider.when('/certificates/create', {
templateUrl: '/angular/certificates/certificate/certificateWizard.tpl.html',
controller: 'CertificateCreateController'
});
$routeProvider.when('/certificates/:id/edit', {
templateUrl: '/angular/certificates/certificate/edit.tpl.html',
controller: 'CertificateEditController'
});
})
.controller('CertificateEditController', function ($scope, $routeParams, CertificateApi, CertificateService, MomentService) { .controller('CertificateEditController', function ($scope, $routeParams, CertificateApi, CertificateService, MomentService) {
CertificateApi.get($routeParams.id).then(function (certificate) { CertificateApi.get($routeParams.id).then(function (certificate) {
$scope.certificate = certificate; $scope.certificate = certificate;
@ -23,13 +11,14 @@ angular.module('lemur')
}) })
.controller('CertificateCreateController', function ($scope, $modal, CertificateApi, CertificateService, AccountService, ELBService, AuthorityService, MomentService, LemurRestangular) { .controller('CertificateCreateController', function ($scope, $modalInstance, CertificateApi, CertificateService, DestinationService, ELBService, AuthorityService, PluginService, MomentService, WizardHandler, LemurRestangular) {
$scope.certificate = LemurRestangular.restangularizeElement(null, {}, 'certificates'); $scope.certificate = LemurRestangular.restangularizeElement(null, {}, 'certificates');
$scope.save = function (certificate) { $scope.create = function (certificate) {
var loadingModal = $modal.open({backdrop: 'static', template: '<wave-spinner></wave-spinner>', windowTemplateUrl: 'angular/loadingModal.html', size: 'large'}); WizardHandler.wizard().context.loading = true;
CertificateService.create(certificate).then(function (response) { CertificateService.create(certificate).then(function (response) {
loadingModal.close(); WizardHandler.wizard().context.loading = false;
$modalInstance.close();
}); });
}; };
@ -88,7 +77,11 @@ angular.module('lemur')
}; };
PluginService.get('destination').then(function (plugins) {
$scope.plugins = plugins;
});
$scope.elbService = ELBService; $scope.elbService = ELBService;
$scope.authorityService = AuthorityService; $scope.authorityService = AuthorityService;
$scope.accountService = AccountService; $scope.destinationService = DestinationService;
}); });

View File

@ -1,20 +0,0 @@
<h2 class="featurette-heading">Create a certificate <span class="text-muted"><small>encrypt all the things
</small></span></h2>
<div class="panel panel-default">
<div class="panel-heading">
<a href="/#/certificates/" class="btn btn-danger pull-right">Cancel</a>
<div class="clearfix"></div>
</div>
<div class="panel-body">
<form name="createForm" class="form-horizontal" role="form" ng-submit="submitCreate()" novalidate>
</form>
</div>
<div class="panel-footer">
<button type="submit" ng-disabled="createForm.$invalid" class="btn btn-success pull-right"><span
ng-show="!loading"> Create </span><span ng-show="loading">Creating <i ng-show="loading"
class="fa fa-cog fa-spin"></i></span>
</button>
<div class="clearfix"></div>
</div>
</div>

View File

@ -1,17 +1,23 @@
<h2 class="featurette-heading"><span ng-show="!certificate.id">Create</span><span ng-show="certificate.id">Edit</span> Certificate <span class="text-muted"><small>encrypt all the things <div class="modal-header">
<div> <h3 class="modal-title"><span ng-show="!certificate.id">Create</span><span ng-show="certificate.id">Edit</span> Certificate <span class="text-muted"><small>encrypt all the things</small></h3>
<wizard on-finish="save(certificate)" template="angular/wizard.html"> </div>
<wz-step title="Tracking" canexit="trackingForm.$valid"> <div class="modal-body">
<ng-include src="'angular/certificates/certificate/tracking.tpl.html'"></ng-include> <div>
</wz-step> <wizard on-finish="create(certificate)" template="angular/wizard.html">
<wz-step title="Distinguished Name" canenter="exitTracking" canexit="exitDN"> <wz-step title="Tracking" canexit="trackingForm.$valid">
<ng-include src="'angular/certificates/certificate/distinguishedName.tpl.html'"></ng-include> <ng-include src="'angular/certificates/certificate/tracking.tpl.html'"></ng-include>
</wz-step> </wz-step>
<wz-step title="Options" canenter="enterValidation"> <wz-step title="Options" canenter="enterValidation">
<ng-include src="'angular/certificates/certificate/options.tpl.html'"></ng-include> <ng-include src="'angular/certificates/certificate/options.tpl.html'"></ng-include>
</wz-step> </wz-step>
<wz-step title="Destinations" canenter="enterValidation"> <wz-step title="Distinguished Name" canenter="exitTracking" canexit="exitDN">
<ng-include src="'angular/certificates/certificate/destinations.tpl.html'"></ng-include> <ng-include src="'angular/certificates/certificate/distinguishedName.tpl.html'"></ng-include>
</wz-step> </wz-step>
</wizard> <wz-step title="Destinations" canenter="enterValidation">
</div> <ng-include src="'angular/certificates/certificate/destinations.tpl.html'"></ng-include>
</wz-step>
</wizard>
</div>
</div>

View File

@ -1,62 +1,28 @@
<p>Destinations are purely optional, if you think the created certificate will be used in AWS select one or more accounts and Lemur will upload it for you.</p> <div class="form-group">
<div class="form-horizontal">
<div class="form-group">
<label class="control-label col-sm-2"> <label class="control-label col-sm-2">
Accounts Destinations
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<div class="input-group"> <div class="input-group">
<input type="text" ng-model="certificate.selectedAccount" placeholder="Account Name" <input type="text" ng-model="certificate.selectedDestination" placeholder="AWS, TheSecret..."
typeahead="account.label for account in accountService.findAccountsByName($viewValue)" typeahead-loading="loadingAccounts" typeahead="destination.label for destination in destinationService.findDestinationsByName($viewValue)" typeahead-loading="loadingDestinations"
class="form-control input-md" typeahead-on-select="certificate.attachAccount($item)" typeahead-min-wait="50" class="form-control input-md" typeahead-on-select="certificate.attachDestination($item)" typeahead-min-wait="50"
tooltip="Lemur can upload the certificate to any AWS account." tooltip="Lemur can upload certificates to any pre-defined destination"
tooltip-trigger="focus" tooltip-placement="top"> tooltip-trigger="focus" tooltip-placement="top">
<span class="input-group-btn"> <span class="input-group-btn">
<button ng-model="accounts.show" class="btn btn-md btn-default" btn-checkbox btn-checkbox-true="1" btn-checkbox-false="0"> <button ng-model="destinations.show" class="btn btn-md btn-default" btn-checkbox btn-checkbox-true="1" btn-checkbox-false="0">
<span class="badge">{{ certificate.accounts.length || 0 }}</span> <span class="badge">{{ certificate.destinations.length || 0 }}</span>
</button> </button>
</span> </span>
</div> </div>
<table class="table"> <table class="table">
<tr ng-repeat="account in certificate.accounts track by $index"> <tr ng-repeat="destination in certificate.destinations track by $index">
<td><a class="btn btn-sm btn-info" href="#/accounts/{{ account.id }}/certificates">{{ account.label }}</a></td> <td><a class="btn btn-sm btn-info" href="#/destinations/{{ destination.id }}/certificates">{{ destination.label }}</a></td>
<td><span class="text-muted">{{ account.comments }}</span></td> <td><span class="text-muted">{{ destination.description }}</span></td>
<td> <td>
<button type="button" ng-click="certificate.removeAccount($index)" class="btn btn-danger btn-sm pull-right">Remove</button> <button type="button" ng-click="certificate.removeDestination($index)" class="btn btn-danger btn-sm pull-right">Remove</button>
</td> </td>
</tr> </tr>
</table> </table>
</div> </div>
</div>
<!--<div ng-show="certificate.accounts" class="form-group">
<label class="control-label col-sm-2">
ELBs
</label>
<div class="col-sm-10">
<div class="input-group">
<input type="text" ng-model="certificate.selectedELB" placeholder="ELB Name"
typeahead="elb.name for elb in elbService.findELBByName($viewValue)" typeahead-loading="loadingAccounts"
class="form-control col-md-4" typeahead-min-wait="50"
tooltip="Lemur can upload a certificate to one or more ELBs"
tooltip-trigger="focus" tooltip-placement="top"/>
<input class="form-control col-md-2" type="integer" ng-model="certificate.selectedPort" placeholder="Port"/>
<select class="form-control col-md-2" ng-options="item for item in ['https', 'tcp']"></select>
<span class="input-group-btn">
<button ng-click="certificate.attachELB()" class="btn btn-info">Add</button>
</span>
</div>
<table class="table">
<tr ng-repeat="elb in certificate.elbs track by $index">
<td><a class="btn btn-sm btn-info" href="#/accounts/{{ elb.id }}/elbs">{{ elb.name }}</a></td>
<td>{{ elb.region }}</td>
<td>{{ elb.scheme }}</td>
<td>{{ elb.vpcId }}</td>
<td>{{ elb.listener.scheme }}</td>
<td>{{ elb.listener.port }}</td>
<td>
<button type="button" ng-click="certificate.removeELB($index)" class="btn btn-danger btn-sm pull-right">remove</button>
</td>
</tr>
</table>
</div>-->
</div> </div>

View File

@ -47,7 +47,7 @@
Common Name Common Name
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<input name="commonName" tooltip="If you need a certificate with multiple domains enter your primary domain here and the rest under 'Subject Alternate Names' in the options panel" ng-model="certificate.commonName" placeholder="Common Name" class="form-control" required/> <input name="commonName" tooltip="If you need a certificate with multiple domains enter your primary domain here and the rest under 'Subject Alternate Names' in the next panel" ng-model="certificate.commonName" placeholder="Common Name" class="form-control" required/>
<p ng-show="trackingForm.commonName.$invalid && !trackingForm.commonName.$pristine" class="help-block">You must enter a common name</p> <p ng-show="trackingForm.commonName.$invalid && !trackingForm.commonName.$pristine" class="help-block">You must enter a common name</p>
</div> </div>
</div> </div>
@ -65,7 +65,7 @@
</div> </div>
</div> </div>
</div> </div>
<span class="text-center col-sm-2"><label><span class="glyphicon glyphicon-resize-horizontal"></span></label></span> <span style="padding-top: 15px" class="text-center col-sm-2"><label><span class="glyphicon glyphicon-resize-horizontal"></span></label></span>
<div class="col-sm-4"> <div class="col-sm-4">
<div> <div>
<div class="input-group"> <div class="input-group">

View File

@ -2,20 +2,16 @@
angular.module('lemur') angular.module('lemur')
.config(function config($routeProvider) { .controller('CertificateUploadController', function ($scope, $modalInstance, CertificateService, LemurRestangular, DestinationService, ELBService, PluginService) {
$routeProvider.when('/certificates/upload', {
templateUrl: '/angular/certificates/certificate/upload.tpl.html',
controller: 'CertificatesUploadController'
});
})
.controller('CertificatesUploadController', function ($scope, CertificateService, LemurRestangular, AccountService, ELBService) {
$scope.certificate = LemurRestangular.restangularizeElement(null, {}, 'certificates'); $scope.certificate = LemurRestangular.restangularizeElement(null, {}, 'certificates');
$scope.upload = CertificateService.upload; $scope.upload = CertificateService.upload;
$scope.accountService = AccountService; $scope.destinationService = DestinationService;
$scope.elbService = ELBService; $scope.elbService = ELBService;
PluginService.get('destination').then(function (plugins) {
$scope.plugins = plugins;
});
$scope.attachELB = function (elb) { $scope.attachELB = function (elb) {
$scope.certificate.attachELB(elb); $scope.certificate.attachELB(elb);
@ -23,4 +19,9 @@ angular.module('lemur')
$scope.certificate.elb.listeners = listeners; $scope.certificate.elb.listeners = listeners;
}); });
}; };
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
}); });

View File

@ -1,136 +1,71 @@
<h2 class="featurette-heading">Upload a certificate <span class="text-muted"><small>encrypt all the things <div class="modal-header">
</small></span></h2> <div class="modal-title">
<div class="panel panel-default"> <h3 class="modal-header">Upload a certificate <span class="text-muted"><small>encrypt all the things</small></span></h3>
<div class="panel-heading"> </div>
<a href="/#/certificates/" class="btn btn-danger pull-right">Cancel</a> <div class="modal-body">
<div class="clearfix"></div> <form name="uploadForm" class="form-horizontal" role="form" novalidate>
</div> <div class="form-group"
<div class="panel-body"> ng-class="{'has-error': uploadForm.owner.$invalid, 'has-success': !uploadForm.owner.$invalid&&uploadForm.owner.$dirty}">
<form name="uploadForm" class="form-horizontal" role="form" novalidate> <label class="control-label col-sm-2">
<div class="form-group" Owner
ng-class="{'has-error': uploadForm.owner.$invalid, 'has-success': !uploadForm.owner.$invalid&&uploadForm.owner.$dirty}"> </label>
<label class="control-label col-sm-2">
Owner
</label>
<div class="col-sm-10"> <div class="col-sm-10">
<input type="email" name="owner" ng-model="certificate.owner" placeholder="owner@netflix.com" <input type="email" name="owner" ng-model="certificate.owner" placeholder="owner@netflix.com"
class="form-control" required/> class="form-control" required/>
<p ng-show="uploadForm.owner.$invalid && !uploadForm.owner.$pristine" class="help-block">Enter a valid <p ng-show="uploadForm.owner.$invalid && !uploadForm.owner.$pristine" class="help-block">Enter a valid
email.</p> email.</p>
</div> </div>
</div> </div>
<div class="form-group" <div class="form-group"
ng-class="{'has-error': uploadForm.publicCert.$invalid, 'has-success': !uploadForm.publicCert.$invalid&&uploadForm.publicCert.$dirty}"> ng-class="{'has-error': uploadForm.publicCert.$invalid, 'has-success': !uploadForm.publicCert.$invalid&&uploadForm.publicCert.$dirty}">
<label class="control-label col-sm-2"> <label class="control-label col-sm-2">
Public Certificate Public Certificate
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<textarea name="publicCert" ng-model="certificate.publicCert" placeholder="PEM encoded string..." <textarea name="publicCert" ng-model="certificate.publicCert" placeholder="PEM encoded string..."
class="form-control" ng-pattern="/^-----BEGIN CERTIFICATE-----/" required></textarea> class="form-control" ng-pattern="/^-----BEGIN CERTIFICATE-----/" required></textarea>
<p ng-show="uploadForm.publicCert.$invalid && !uploadForm.publicCert.$pristine" class="help-block">Enter <p ng-show="uploadForm.publicCert.$invalid && !uploadForm.publicCert.$pristine" class="help-block">Enter
a valid certificate.</p> a valid certificate.</p>
</div> </div>
</div> </div>
<div class="form-group" <div class="form-group"
ng-class="{'has-error': uploadForm.privateKey.$invalid&&uploadForm.privateKey.$dirty, 'has-success': !uploadForm.privateKey.$invalid&&uploadForm.privateKey.$dirty}"> ng-class="{'has-error': uploadForm.privateKey.$invalid&&uploadForm.privateKey.$dirty, 'has-success': !uploadForm.privateKey.$invalid&&uploadForm.privateKey.$dirty}">
<label class="control-label col-sm-2"> <label class="control-label col-sm-2">
Private Key Private Key
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<textarea name="privateKey" ng-model="certificate.privateKey" placeholder="PEM encoded string..." <textarea name="privateKey" ng-model="certificate.privateKey" placeholder="PEM encoded string..."
class="form-control" ng-pattern="/^-----BEGIN RSA PRIVATE KEY-----/"></textarea> class="form-control" ng-pattern="/^-----BEGIN RSA PRIVATE KEY-----/"></textarea>
<p ng-show="uploadForm.privateKey.$invalid && !uploadForm.privateKey.$pristine" class="help-block">Enter <p ng-show="uploadForm.privateKey.$invalid && !uploadForm.privateKey.$pristine" class="help-block">Enter
a valid certificate.</p> a valid certificate.</p>
</div> </div>
</div> </div>
<div class="form-group" <div class="form-group"
ng-class="{'has-error': uploadForm.owner.$invalid&&uploadform.intermediateCert.$dirty, 'has-success': !uploadForm.intermediateCert.$invalid&&uploadForm.intermediateCert.$dirty}"> ng-class="{'has-error': uploadForm.owner.$invalid&&uploadform.intermediateCert.$dirty, 'has-success': !uploadForm.intermediateCert.$invalid&&uploadForm.intermediateCert.$dirty}">
<label class="control-label col-sm-2"> <label class="control-label col-sm-2">
Intermediate Certificate Intermediate Certificate
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<textarea name="intermediateCert" ng-model="certificate.intermediateCert" <textarea name="intermediateCert" ng-model="certificate.intermediateCert"
placeholder="PEM encoded string..." class="form-control" placeholder="PEM encoded string..." class="form-control"
ng-pattern="/^-----BEGIN CERTIFICATE-----/"></textarea> ng-pattern="/^-----BEGIN CERTIFICATE-----/"></textarea>
<p ng-show="uploadForm.intermediateCert.$invalid && !uploadForm.intemediateCert.$pristine" <p ng-show="uploadForm.intermediateCert.$invalid && !uploadForm.intemediateCert.$pristine"
class="help-block">Enter a valid certificate.</p> class="help-block">Enter a valid certificate.</p>
</div> </div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">
Accounts
</label>
<div class="col-sm-10">
<div class="input-group">
<input type="text" ng-model="certificate.selectedAccount" placeholder="Account Name"
typeahead="account.label for account in accountService.findAccountsByName($viewValue)" typeahead-loading="loadingAccounts"
class="form-control" typeahead-on-select="certificate.attachAccount($item)" typeahead-min-wait="50"
tooltip="Lemur can upload the certificate to any AWS account."
tooltip-trigger="focus" tooltip-placement="top">
<span class="input-group-btn">
<button ng-model="certificate.accounts" class="btn btn-default" btn-checkbox btn-checkbox-true="1" btn-checkbox-false="0">
<span class="badge">{{ certificate.accounts.length || 0 }}</span>
</button>
</span>
</div>
<table ng-show="certificate.accounts" class="table">
<tr ng-repeat="account in certificate.accounts track by $index">
<td><a class="btn btn-sm btn-info" href="#/accounts/{{ account.id }}/certificates">{{ account.label }}</a></td>
<td><span class="text-muted">{{ account.comments }}</span></td>
<td>
<button type="button" ng-click="certificate.removeAccount($index)" class="btn btn-danger btn-sm pull-right">
Remove
</button>
</td>
</tr>
</table>
</div>
</div>
<!--<div class="form-group">
<label class="control-label col-sm-2">
ELBs
</label>
<div class="col-sm-10">
<div class="input-group">
<input type="text" ng-model="certificate.selectedELB" placeholder="ELB Name"
typeahead="elb.name for elb in elbService.findELBByName($viewValue)" typeahead-loading="loadingAccounts"
class="form-control" typeahead-on-select="attachELB($item)" typeahead-min-wait="50"
tooltip="Lemur can upload a certificate to one or more ELBs searching will be limited to the accounts selected above"
tooltip-trigger="focus" tooltip-placement="top">
<span class="input-group-btn">
<button ng-model="certificate.elbs" class="btn btn-default" btn-checkbox btn-checkbox-true="1" btn-checkbox-false="0">
<span class="badge">{{ certificate.elbs.length || 0 }}</span>
</button>
</span>
</div> </div>
<table ng-show="certificate.elbs" class="table"> <div ng-include="'angular/certificates/certificate/destinations.tpl.html'"></div>
<tr ng-repeat="elb in certificate.elbs track by $index"> </form>
<td><a class="btn btn-sm btn-info" href="#/accounts/{{ elb.id }}/elbs">{{ elb.name }}</a></td> </div>
<td>{{ elb.region }}</td> <div class="modal-footer">
<td>{{ elb.scheme }}</td> <button type="submit" ng-click="upload(certificate)" ng-disabled="uploadForm.$invalid" class="btn btn-success">Import</button>
<td>{{ elb.vpcId }}</td> <button ng-click="cancel()" class="btn btn-danger">Cancel</button>
<td><a class="btn btn-info" ng-model="elb.showListeners" btn-checkbox btn-checkbox-true="1" btn-checkbox-false="0">View Listeners</a></td> </div>
<td>
<button type="button" ng-click="certificate.removeAccount($index)" class="btn btn-danger btn-sm pull-right">
Remove
</button>
</td>
</tr>
</table>
</div>
</div>-->
</form>
</div>
<div class="panel-footer">
<button type="submit" ng-click="upload(certificate)" ng-disabled="uploadForm.$invalid" class="btn btn-success pull-right">Upload</button>
<div class="clearfix"></div>
</div>
</div> </div>

View File

@ -58,15 +58,15 @@ angular.module('lemur')
removeCustom: function (index) { removeCustom: function (index) {
this.extensions.custom.splice(index, 1); this.extensions.custom.splice(index, 1);
}, },
attachAccount: function (account) { attachDestination: function (destination) {
this.selectedAccount = null; this.selectedDestination = null;
if (this.accounts === undefined) { if (this.destinations === undefined) {
this.accounts = []; this.destinations = [];
} }
this.accounts.push(account); this.destinations.push(destination);
}, },
removeAccount: function (index) { removeDestination: function (index) {
this.accounts.splice(index, 1); this.destinations.splice(index, 1);
}, },
attachELB: function (elb) { attachELB: function (elb) {
this.selectedELB = null; this.selectedELB = null;
@ -99,13 +99,6 @@ angular.module('lemur')
}); });
}; };
CertificateService.getARNs = function (certificate) {
certificate.arns = [];
_.each(certificate.accounts, function (account) {
certificate.arns.push('arn:aws:iam::' + account.accountNumber + ':server-certificate/' + certificate.name);
});
};
CertificateService.create = function (certificate) { CertificateService.create = function (certificate) {
certificate.attachSubAltName(); certificate.attachSubAltName();
return CertificateApi.post(certificate).then( return CertificateApi.post(certificate).then(
@ -191,10 +184,9 @@ angular.module('lemur')
}); });
}; };
CertificateService.getAccounts = function (certificate) { CertificateService.getDestinations = function (certificate) {
certificate.getList('accounts').then(function (accounts) { certificate.getList('destinations').then(function (destinations) {
certificate.accounts = accounts; certificate.destinations = destinations;
CertificateService.getARNs(certificate);
}); });
}; };

View File

@ -9,7 +9,7 @@ angular.module('lemur')
}); });
}) })
.controller('CertificatesViewController', function ($q, $scope, CertificateApi, CertificateService, MomentService, ngTableParams) { .controller('CertificatesViewController', function ($q, $scope, $modal, CertificateApi, CertificateService, MomentService, ngTableParams) {
$scope.filter = {}; $scope.filter = {};
$scope.certificateTable = new ngTableParams({ $scope.certificateTable = new ngTableParams({
page: 1, // show first page page: 1, // show first page
@ -26,7 +26,7 @@ angular.module('lemur')
// TODO we should attempt to resolve all of these in parallel // TODO we should attempt to resolve all of these in parallel
_.each(data, function (certificate) { _.each(data, function (certificate) {
CertificateService.getDomains(certificate); CertificateService.getDomains(certificate);
CertificateService.getAccounts(certificate); CertificateService.getDestinations(certificate);
CertificateService.getListeners(certificate); CertificateService.getListeners(certificate);
CertificateService.getAuthority(certificate); CertificateService.getAuthority(certificate);
CertificateService.getCreator(certificate); CertificateService.getCreator(certificate);
@ -60,4 +60,30 @@ angular.module('lemur')
$scope.toggleFilter = function (params) { $scope.toggleFilter = function (params) {
params.settings().$scope.show_filter = !params.settings().$scope.show_filter; params.settings().$scope.show_filter = !params.settings().$scope.show_filter;
}; };
$scope.create = function () {
var modalInstance = $modal.open({
animation: true,
controller: 'CertificateCreateController',
templateUrl: '/angular/certificates/certificate/certificateWizard.tpl.html',
size: 'lg'
});
modalInstance.result.then(function () {
$scope.certificateTable.reload();
});
};
$scope.import = function () {
var modalInstance = $modal.open({
animation: true,
controller: 'CertificateUploadController',
templateUrl: '/angular/certificates/certificate/upload.tpl.html',
size: 'lg'
});
modalInstance.result.then(function () {
$scope.certificateTable.reload();
});
};
}); });

View File

@ -5,14 +5,14 @@
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<div class="btn-group pull-right"> <div class="btn-group pull-right">
<a data-placement="left" data-title="Create Certificate" bs-tooltip href="#/certificates/create" <button data-placement="left" data-title="Create Certificate" bs-tooltip ng-click="create()"
class="btn btn-primary"> class="btn btn-primary">
Create Create
</a> </button>
<a data-placement="left" data-title="Upload Certificate" bs-tooltip href="#/certificates/upload" <button data-placement="left" data-title="Import Certificate" bs-tooltip ng-click="import()"
class="btn btn-info"> class="btn btn-info">
Upload Import
</a> </button>
</div> </div>
<div class="btn-group"> <div class="btn-group">
<button ng-click="toggleFilter(certificateTable)" class="btn btn-default">Filter</button> <button ng-click="toggleFilter(certificateTable)" class="btn btn-default">Filter</button>
@ -30,9 +30,9 @@
<li><span class="text-muted">{{ certificate.owner }}</span></li> <li><span class="text-muted">{{ certificate.owner }}</span></li>
</ul> </ul>
</td> </td>
<td data-title="'Accounts'" filter="{ 'account': 'select' }" filter-date="getAccountDropDown()"> <td data-title="'Destinations'" filter="{ 'destination': 'select' }" filter-date="getDestinationDropDown()">
<div class="btn-group"> <div class="btn-group">
<a href="#/accounts/{{ account.id }}/edit" class="btn btn-sm btn-default" ng-repeat="account in certificate.accounts">{{ account.label }}</a> <a href="#/destinations/{{ destination.id }}/edit" class="btn btn-sm btn-default" ng-repeat="account in certificate.destinations">{{ destination.label }}</a>
</div> </div>
</td> </td>
<td data-title="'Active'" filter="{ 'active': 'select' }" filter-data="getCertificateStatus()"> <td data-title="'Active'" filter="{ 'active': 'select' }" filter-data="getCertificateStatus()">
@ -106,7 +106,7 @@
<div class="list-group"> <div class="list-group">
<a href="#/domains/{{ domain.id }}" class="list-group-item" ng-repeat="domain in certificate.domains">{{ domain.name }}</a> <a href="#/domains/{{ domain.id }}" class="list-group-item" ng-repeat="domain in certificate.domains">{{ domain.name }}</a>
</div> </div>
<h4 ng-show="certificate.accounts.total">ARNs</h4> <h4 ng-show="certificate.destinations.total">ARNs</h4>
<ul class="list-group"> <ul class="list-group">
<li class="list-group-item" ng-repeat="arn in certificate.arns">{{ arn }}</li> <li class="list-group-item" ng-repeat="arn in certificate.arns">{{ arn }}</li>
</ul> </ul>

View File

@ -1,8 +1,8 @@
angular.module('lemur'). angular.module('lemur').
filter('titleCase', function () { filter('titleCase', function () {
return function (str) { return function (str) {
return (str === undefined || str === null) ? '' : str.replace(/_|-/, ' ').replace(/\w\S*/g, function (txt) { return (str === undefined || str === null) ? '' : str.replace(/([A-Z])/g, ' $1').replace(/^./, function (txt) {
return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase(); return txt.toUpperCase();
}); });
}; };
}); });

View File

@ -1,6 +0,0 @@
<div tabindex="-1" role="dialog" class="modal fade" ng-class="{in: animate}" ng-style="{'z-index': 1050 + index*10, display: 'block'}">
<div class="modal-dialog-center">
<div modal-transclude>
</div>
</div>
</div>

View File

@ -2,29 +2,37 @@
angular.module('lemur') angular.module('lemur')
.config(function config($routeProvider) { .controller('RolesEditController', function ($scope, $modalInstance, RoleApi, RoleService, UserService, editId) {
$routeProvider.when('/roles/create', { RoleApi.get(editId).then(function (role) {
templateUrl: '/angular/roles/role/role.tpl.html',
controller: 'RoleCreateController'
});
$routeProvider.when('/roles/:id/edit', {
templateUrl: '/angular/roles/role/role.tpl.html',
controller: 'RoleEditController'
});
})
.controller('RoleEditController', function ($scope, $routeParams, RoleApi, RoleService, UserService) {
RoleApi.get($routeParams.id).then(function (role) {
$scope.role = role; $scope.role = role;
RoleService.getUsers(role); RoleService.getUsers(role);
}); });
$scope.save = RoleService.update; $scope.save = function (role) {
RoleService.update(role).then(function () {
$modalInstance.close();
});
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
$scope.userService = UserService; $scope.userService = UserService;
$scope.roleService = RoleService; $scope.roleService = RoleService;
}) })
.controller('RoleCreateController', function ($scope, RoleApi, RoleService, UserService, LemurRestangular ) { .controller('RolesCreateController', function ($scope,$modalInstance, RoleApi, RoleService, UserService, LemurRestangular) {
$scope.role = LemurRestangular.restangularizeElement(null, {}, 'roles'); $scope.role = LemurRestangular.restangularizeElement(null, {}, 'roles');
$scope.userService = UserService; $scope.userService = UserService;
$scope.save = RoleService.create;
$scope.save = function (role) {
RoleService.create(role).then(function () {
$modalInstance.close();
});
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
}); });

View File

@ -1,85 +1,82 @@
<h2 class="featurette-heading"><span ng-show="!role.fromServer">Create</span><span ng-show="role.fromServer">Edit</span> Role <span class="text-muted"><small>The nail that sticks out farthest gets hammered the hardest <div class="modal-header">
</small></span></h2> <div class="modal-title">
<div class="panel panel-default"> <h3 class="modal-header"><span ng-show="!role.fromServer">Create</span><span ng-show="role.fromServer">Edit</span> Role <span class="text-muted"><small>The nail that sticks out farthest gets hammered the hardest</small></span></h3>
<div class="panel-heading"> </div>
<button ng-click="roleService.loadPassword(role)" class="btn btn-warning">Show Credentials</button> <div class="modal-body">
<a href="/#/roles" class="btn btn-danger pull-right">Cancel</a> <form name="createForm" class="form-horizontal" ng-submit="save(role)" role="form" novalidate>
<div class="clearfix"></div> <div class="form-group"
</div> ng-class="{'has-error': createForm.name.$invalid, 'has-success': !createForm.name.$invalid&&createForm.name.$dirty}">
<div class="panel-body"> <label class="control-label col-sm-2">
<form name="createForm" class="form-horizontal" ng-submit="save(role)" role="form" novalidate> Name
<div class="form-group" </label>
ng-class="{'has-error': createForm.name.$invalid, 'has-success': !createForm.name.$invalid&&createForm.name.$dirty}"> <div class="col-sm-10">
<label class="control-label col-sm-2"> <input name="name" ng-model="role.name" placeholder="Name" class="form-control" required/>
Name <p ng-show="createForm.name.$invalid && !createForm.name.$pristine" class="help-block">You must enter an role name</p>
</label> </div>
<div class="col-sm-10"> </div>
<input name="name" ng-model="role.name" placeholder="Name" class="form-control" required/> <div class="form-group">
<p ng-show="createForm.name.$invalid && !createForm.name.$pristine" class="help-block">You must enter an role name</p> <label class="control-label col-sm-2">
</div> Description
</div> </label>
<div class="form-group"> <div class="col-sm-10">
<label class="control-label col-sm-2"> <textarea name="description" ng-model="role.description" placeholder="Something elegant" class="form-control" ></textarea>
Description </div>
</label> </div>
<div class="col-sm-10"> <div class="form-group">
<textarea name="description" ng-model="role.description" placeholder="Something elegant" class="form-control" ></textarea> <label class="control-label col-sm-2">
</div> Username
</div> </label>
<div class="form-group"> <div class="col-sm-10">
<label class="control-label col-sm-2"> <input ng-show="!role.fromServer" name="username" ng-model="role.username" placeholder="Username" class="form-control" required/>
Username <div class="well">
</label>
<div class="col-sm-10">
<input ng-show="!role.fromServer" name="username" ng-model="role.username" placeholder="Username" class="form-control" required/>
<div class="well">
<span ng-show="role.password"> <span ng-show="role.password">
{{ role.username }} {{ role.username }}
</span> </span>
<span ng-show="!role.password"> <span ng-show="!role.password">
****************** ******************
</span> </span>
</div> </div>
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<label class="control-label col-sm-2"> <label class="control-label col-sm-2">
Password Password
</label> </label>
<div class="col-sm-10"> <div class="col-sm-10">
<input ng-show="!role.fromServer" type="password" name="password" ng-model="role.password" placeholder="hunter2" class="form-control" required/> <input ng-show="!role.fromServer" type="password" name="password" ng-model="role.password" placeholder="hunter2" class="form-control" required/>
<p ng-show="createForm.password.$invalid && !createForm.password.$pristine" class="help-block">You must enter an password</p> <p ng-show="createForm.password.$invalid && !createForm.password.$pristine" class="help-block">You must enter an password</p>
<div class="well"> <div class="well">
<span ng-show="role.password"> <span ng-show="role.password">
{{ role.password }} {{ role.password }}
</span> </span>
<span ng-show="!role.password"> <span ng-show="!role.password">
***************** *****************
</span> </span>
</div> </div>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2">User(s)</label>
<div class="col-sm-10">
<input tooltip="You can attach any user to this role, once attached they will have access as defined by this role"
typeahead="user.username for user in userService.findUserByName($viewValue)" typeahead-loading="loadingUsers"
typeahead-min-wait="100" typeahead-on-select="role.addUser($item)"
type="text" name="user" ng-model="role.selectedUser" placeholder="Username..." class="form-control" required/>
<table ng-show="role.users" class="table">
<tr ng-repeat="user in role.users track by $index">
<td>{{ user.username }}</td>
<td>
<button type="button" ng-click="role.removeUser($index)" class="btn btn-danger btn-sm pull-right">Remove</button>
</td>
</tr>
</table>
</div>
</div>
</form>
<div class="modal-footer">
<button ng-click="roleService.loadPassword(role)" class="btn btn-warning pull-left">Show Credentials</button>
<button ng-click="save(role)" type="submit" ng-disabled="createForm.$invalid" class="btn btn-primary">Save</button>
<button ng-click="cancel()" class="btn btn-danger">Cancel</button>
</div> </div>
</div> </div>
<div class="form-group">
<label class="control-label col-sm-2">User(s)</label>
<div class="col-sm-10">
<input tooltip="You can attach any user to this role, once attached they will have access as defined by this role"
typeahead="user.username for user in userService.findUserByName($viewValue)" typeahead-loading="loadingUsers"
typeahead-min-wait="100" typeahead-on-select="role.addUser($item)"
type="text" name="user" ng-model="role.selectedUser" placeholder="Username..." class="form-control" required/>
<table ng-show="role.users" class="table">
<tr ng-repeat="user in role.users track by $index">
<td>{{ user.username }}</td>
<td>
<button type="button" ng-click="role.removeUser($index)" class="btn btn-danger btn-sm pull-right">Remove</button>
</td>
</tr>
</table>
</div>
</div>
</form>
</div>
<div class="panel-footer">
<button ng-click="save(role)" class="btn btn-success pull-right">Save</button>
<div class="clearfix"></div>
</div>
</div> </div>

View File

@ -38,7 +38,7 @@ angular.module('lemur')
}; };
RoleService.create = function (role) { RoleService.create = function (role) {
RoleApi.post(role).then( return RoleApi.post(role).then(
function () { function () {
toaster.pop({ toaster.pop({
type: 'success', type: 'success',
@ -57,7 +57,7 @@ angular.module('lemur')
}; };
RoleService.update = function (role) { RoleService.update = function (role) {
role.put().then( return role.put().then(
function () { function () {
toaster.pop({ toaster.pop({
type: 'success', type: 'success',

View File

@ -9,7 +9,7 @@ angular.module('lemur')
}); });
}) })
.controller('RolesViewController', function ($scope, RoleApi, RoleService, ngTableParams) { .controller('RolesViewController', function ($scope, $modal, RoleApi, RoleService, ngTableParams) {
$scope.filter = {}; $scope.filter = {};
$scope.rolesTable = new ngTableParams({ $scope.rolesTable = new ngTableParams({
page: 1, // show first page page: 1, // show first page
@ -39,4 +39,38 @@ angular.module('lemur')
params.settings().$scope.show_filter = !params.settings().$scope.show_filter; params.settings().$scope.show_filter = !params.settings().$scope.show_filter;
}; };
$scope.edit = function (roleId) {
var modalInstance = $modal.open({
animation: true,
templateUrl: '/angular/roles/role/role.tpl.html',
controller: 'RolesEditController',
size: 'lg',
resolve: {
editId: function () {
return roleId;
}
}
});
modalInstance.result.then(function () {
$scope.rolesTable.reload();
});
};
$scope.create = function () {
var modalInstance = $modal.open({
animation: true,
controller: 'RolesCreateController',
templateUrl: '/angular/roles/role/role.tpl.html',
size: 'lg'
});
modalInstance.result.then(function () {
$scope.rolesTable.reload();
});
};
}); });

View File

@ -5,7 +5,7 @@
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<div class="btn-group pull-right"> <div class="btn-group pull-right">
<a data-placement="left" data-title="Create Role" bs-tooltip href="#/roles/create" class="btn btn-primary">Create</a> <button ng-click="create()" class="btn btn-primary">Create</button>
</div> </div>
<div class="btn-group"> <div class="btn-group">
<button ng-click="toggleFilter(rolesTable)" class="btn btn-default">Filter</button> <button ng-click="toggleFilter(rolesTable)" class="btn btn-default">Filter</button>
@ -24,9 +24,9 @@
</td> </td>
<td data-title="''"> <td data-title="''">
<div class="btn-group-vertical pull-right"> <div class="btn-group-vertical pull-right">
<a href="#/roles/{{ role.id }}/edit" class="btn btn-sm btn-info"> <button ng-click="edit(role.id)" class="btn btn-sm btn-info">
Edit Edit
</a> </button>
<a ng-click="remove(role)" class="btn btn-sm btn-danger"> <a ng-click="remove(role)" class="btn btn-sm btn-danger">
Remove Remove
</a> </a>

View File

@ -50,7 +50,7 @@ angular.module('lemur')
}; };
UserService.create = function (user) { UserService.create = function (user) {
UserApi.post(user).then( return UserApi.post(user).then(
function () { function () {
toaster.pop({ toaster.pop({
type: 'success', type: 'success',
@ -69,7 +69,7 @@ angular.module('lemur')
}; };
UserService.update = function (user) { UserService.update = function (user) {
user.put().then( return user.put().then(
function () { function () {
toaster.pop({ toaster.pop({
type: 'success', type: 'success',

View File

@ -2,19 +2,8 @@
angular.module('lemur') angular.module('lemur')
.config(function config($routeProvider) { .controller('UsersEditController', function ($scope, $modalInstance, UserApi, UserService, RoleService, editId) {
$routeProvider.when('/users/create', { UserApi.get(editId).then(function (user) {
templateUrl: '/angular/users/user/user.tpl.html',
controller: 'UsersCreateController'
});
$routeProvider.when('/users/:id/edit', {
templateUrl: '/angular/users/user/user.tpl.html',
controller: 'UsersEditController'
});
})
.controller('UsersEditController', function ($scope, $routeParams, UserApi, UserService, RoleService) {
UserApi.get($routeParams.id).then(function (user) {
UserService.getRoles(user); UserService.getRoles(user);
$scope.user = user; $scope.user = user;
}); });
@ -24,15 +13,36 @@ angular.module('lemur')
$scope.rolePage = 1; $scope.rolePage = 1;
$scope.save = function (user) {
UserService.update(user).then(function () {
$modalInstance.close();
});
}
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
$scope.loadMoreRoles = function () { $scope.loadMoreRoles = function () {
$scope.rolePage += 1; $scope.rolePage += 1;
UserService.loadMoreRoles($scope.user, $scope.rolePage); UserService.loadMoreRoles($scope.user, $scope.rolePage);
}; };
}) })
.controller('UsersCreateController', function ($scope, UserService, LemurRestangular, RoleService) { .controller('UsersCreateController', function ($scope, $modalInstance, UserService, LemurRestangular, RoleService) {
$scope.user = LemurRestangular.restangularizeElement(null, {}, 'users'); $scope.user = LemurRestangular.restangularizeElement(null, {}, 'users');
$scope.save = UserService.create; $scope.save = UserService.create;
$scope.roleService = RoleService; $scope.roleService = RoleService;
$scope.create = function (user) {
UserService.create(user).then(function () {
$modalInstance.close();
});
};
$scope.cancel = function () {
$modalInstance.dismiss('cancel');
};
}); });

View File

@ -1,89 +1,86 @@
<h2 class="featurette-heading"><span ng-show="!user.fromServer">Create</span><span ng-show="user.fromServer">Edit</span> User <span class="text-muted"><small>what was your name again? <div class="modal-header">
</small></span></h2> <div class="modal-title">
<div class="panel panel-default"> <h3 class="modal-header"><span ng-show="!user.fromServer">Create</span><span ng-show="user.fromServer">Edit</span> User <span class="text-muted"><small>what was your name again?</small></span></h3>
<div class="panel-heading"> </div>
<a href="#/users" class="btn btn-danger pull-right">Cancel</a> <div class="modal-body">
<div class="clearfix"></div> <form name="createForm" class="form-horizontal" role="form" novalidate>
</div> <div class="form-group"
<div class="panel-body"> ng-class="{'has-error': createForm.username.$invalid, 'has-success': !createForm.username.$invalid&&createForm.username.$dirty}">
<form name="createForm" class="form-horizontal" role="form" novalidate> <label class="control-label col-sm-2">
<div class="form-group" Name
ng-class="{'has-error': createForm.username.$invalid, 'has-success': !createForm.username.$invalid&&createForm.username.$dirty}"> </label>
<label class="control-label col-sm-2"> <div class="col-sm-10">
Name <input name="username" ng-model="user.username" placeholder="Name" class="form-control" required/>
</label> <p ng-show="createForm.username.$invalid && !createForm.username.$pristine" class="help-block">You must enter a username</p>
<div class="col-sm-10"> </div>
<input name="username" ng-model="user.username" placeholder="Name" class="form-control" required/> </div>
<p ng-show="createForm.username.$invalid && !createForm.username.$pristine" class="help-block">You must enter a username</p> <div class="form-group"
</div> ng-class="{'has-error': createForm.email.$invalid, 'has-success': !createForm.email.$invalid&&createForm.email.$dirty}">
</div> <label class="control-label col-sm-2">
<div class="form-group" Email
ng-class="{'has-error': createForm.email.$invalid, 'has-success': !createForm.email.$invalid&&createForm.email.$dirty}"> </label>
<label class="control-label col-sm-2"> <div class="col-sm-10">
Email <input type="email" name="email" ng-model="user.email" placeholder="hi@example.com" class="form-control" required/>
</label> <p ng-show="createForm.email.$invalid && !createForm.email.$pristine" class="help-block">You must enter an email</p>
<div class="col-sm-10"> </div>
<input type="email" name="email" ng-model="user.email" placeholder="hi@example.com" class="form-control" required/> </div>
<p ng-show="createForm.email.$invalid && !createForm.email.$pristine" class="help-block">You must enter an email</p> <div ng-if="!user.id" class="form-group"
</div> ng-class="{'has-error': createForm.password.$invalid, 'has-success': !createForm.password.$invalid&&createForm.password.$dirty}">
</div> <label class="control-label col-sm-2">
<div ng-if="!user.id" class="form-group" Password
ng-class="{'has-error': createForm.password.$invalid, 'has-success': !createForm.password.$invalid&&createForm.password.$dirty}"> </label>
<label class="control-label col-sm-2"> <div class="col-sm-10">
Password <input type="password" name="password" ng-model="user.password" placeholder="hunter2" class="form-control" required/>
</label> <p ng-show="createForm.password.$invalid && !createForm.password.$pristine" class="help-block">You must enter an password</p>
<div class="col-sm-10"> </div>
<input type="password" name="password" ng-model="user.password" placeholder="hunter2" class="form-control" required/> </div>
<p ng-show="createForm.password.$invalid && !createForm.password.$pristine" class="help-block">You must enter an password</p> <div class="form-group">
</div> <label class="control-label col-sm-2">
</div> Active
<div class="form-group"> </label>
<label class="control-label col-sm-2"> <div class="col-sm-10">
Active <div class="checkbox col-sm-10">
</label> <switch ng-model="user.active" id="active" name="active" ng-init="user.active=true" class="green small"></switch>
<div class="col-sm-10"> </div>
<div class="checkbox col-sm-10"> </div>
<input ng-model="user.active" type="checkbox" value="true"> </div>
</div> <div class="form-group">
</div> <label class="control-label col-sm-2">
</div> Roles
<div class="form-group"> </label>
<label class="control-label col-sm-2"> <div class="col-sm-10">
Roles <div class="input-group">
</label> <input type="text" ng-model="user.selectedRole" placeholder="Role Name"
<div class="col-sm-10"> typeahead="role.name for role in roleService.findRoleByName($viewValue)" typeahead-loading="loadingRoles"
<div class="input-group"> class="form-control input-md" typeahead-on-select="user.attachRole($item)" typeahead-min-wait="50"
<input type="text" ng-model="user.selectedRole" placeholder="Role Name" tooltip="Roles control which authorities a user can issue certificates from"
typeahead="role.name for role in roleService.findRoleByName($viewValue)" typeahead-loading="loadingRoles" tooltip-trigger="focus" tooltip-placement="top">
class="form-control input-md" typeahead-on-select="user.attachRole($item)" typeahead-min-wait="50"
tooltip="Roles control which authorities a user can issue certificates from"
tooltip-trigger="focus" tooltip-placement="top">
<span class="input-group-btn"> <span class="input-group-btn">
<button ng-model="roles.show" class="btn btn-md btn-default" btn-checkbox btn-checkbox-true="1" btn-checkbox-false="0"> <button ng-model="roles.show" class="btn btn-md btn-default" btn-checkbox btn-checkbox-true="1" btn-checkbox-false="0">
<span class="badge">{{ user.roles.total || 0 }}</span> <span class="badge">{{ user.roles.total || 0 }}</span>
</button> </button>
</span> </span>
</div> </div>
<table ng-show="user.roles" class="table"> <table ng-show="user.roles" class="table">
<tr ng-repeat="role in user.roles track by $index"> <tr ng-repeat="role in user.roles track by $index">
<td><a class="btn btn-sm btn-info" href="#/roles/{{ role.id }}/edit">{{ role.name }}</a></td> <td><a class="btn btn-sm btn-info" href="#/roles/{{ role.id }}/edit">{{ role.name }}</a></td>
<td><span class="text-muted">{{ role.description }}</span></td> <td><span class="text-muted">{{ role.description }}</span></td>
<td> <td>
<button type="button" ng-click="user.removeRole($index)" class="btn btn-danger btn-sm pull-right">Remove</button> <button type="button" ng-click="user.removeRole($index)" class="btn btn-danger btn-sm pull-right">Remove</button>
</td> </td>
</tr> </tr>
<tr> <tr>
<td></td> <td></td>
<td></td> <td></td>
<td><a class="pull-right" ng-click="loadMoreRoles()"><strong>More</strong></a></td> <td><a class="pull-right" ng-click="loadMoreRoles()"><strong>More</strong></a></td>
</tr> </tr>
</table> </table>
</div>
</div>
</form>
<div class="modal-footer">
<button ng-click="save(user)" type="submit" ng-disabled="createForm.$invalid" class="btn btn-primary">Save</button>
<button ng-click="cancel()" class="btn btn-danger">Cancel</button>
</div> </div>
</div> </div>
</form>
</div>
<div class="panel-footer">
<button ng-click="save(user)" class="btn btn-success pull-right">Save</button>
<div class="clearfix"></div>
</div>
</div> </div>

View File

@ -9,7 +9,7 @@ angular.module('lemur')
}); });
}) })
.controller('UsersViewController', function ($scope, UserApi, UserService, ngTableParams) { .controller('UsersViewController', function ($scope, $modal, UserApi, UserService, ngTableParams) {
$scope.filter = {}; $scope.filter = {};
$scope.usersTable = new ngTableParams({ $scope.usersTable = new ngTableParams({
page: 1, // show first page page: 1, // show first page
@ -36,6 +36,39 @@ angular.module('lemur')
}); });
}; };
$scope.edit = function (userId) {
var modalInstance = $modal.open({
animation: true,
templateUrl: '/angular/users/user/user.tpl.html',
controller: 'UsersEditController',
size: 'lg',
resolve: {
editId: function () {
return userId;
}
}
});
modalInstance.result.then(function () {
$scope.usersTable.reload();
});
};
$scope.create = function () {
var modalInstance = $modal.open({
animation: true,
controller: 'UsersCreateController',
templateUrl: '/angular/users/user/user.tpl.html',
size: 'lg'
});
modalInstance.result.then(function () {
$scope.usersTable.reload();
});
};
$scope.toggleFilter = function (params) { $scope.toggleFilter = function (params) {
params.settings().$scope.show_filter = !params.settings().$scope.show_filter; params.settings().$scope.show_filter = !params.settings().$scope.show_filter;
}; };

View File

@ -5,7 +5,7 @@
<div class="panel panel-default"> <div class="panel panel-default">
<div class="panel-heading"> <div class="panel-heading">
<div class="btn-group pull-right"> <div class="btn-group pull-right">
<a href="#/users/create" class="btn btn-primary">Create</a> <button ng-click="create()" class="btn btn-primary">Create</button>
</div> </div>
<div class="btn-group"> <div class="btn-group">
<button ng-click="toggleFilter(usersTable)" class="btn btn-default">Filter</button> <button ng-click="toggleFilter(usersTable)" class="btn btn-default">Filter</button>
@ -29,9 +29,9 @@
</td> </td>
<td data-title="''"> <td data-title="''">
<div class="btn-group-vertical pull-right"> <div class="btn-group-vertical pull-right">
<a tooltip="Edit User" href="#/users/{{ user.id }}/edit" class="btn btn-sm btn-info"> <button tooltip="Edit User" ng-click="edit(user.id)" class="btn btn-sm btn-info">
Edit Edit
</a> </button>
</div> </div>
</td> </td>
</tr> </tr>

View File

@ -1,23 +1,12 @@
<div> <div>
<div class="panel panel-default"> <div class="modal-body">
<div class="panel-heading">
<ul class="steps-indicator steps-{{steps.length}}" ng-if="!hideIndicators">
<li ng-class="{default: !step.completed && !step.selected, current: step.selected && !step.completed, done: step.completed && !step.selected, editing: step.selected && step.completed}" ng-repeat="step in steps">
<a ng-click="goTo(step)">{{step.title || step.wzTitle}}</a>
</li>
</ul>
<div class="clearfix"></div>
</div>
<div class="panel-body">
<div class="steps" ng-transclude></div> <div class="steps" ng-transclude></div>
</div> </div>
<div class="panel-footer"> <div class="modal-footer">
<input ng-hide="currentStepNumber() == 1" class="btn btn-default pull-left" type="submit" wz-previous value="Previous" /> <input ng-hide="currentStepNumber() == 1" class="btn btn-default pull-left" type="submit" wz-previous value="Previous" />
<input ng-show="currentStepNumber() != steps.length" class="btn btn-default pull-right" type="submit" wz-next value="Next" /> <input ng-show="currentStepNumber() != steps.length" class="btn btn-default pull-right" type="submit" wz-next value="Next" />
<button ng-show="currentStepNumber() == steps.length" class="btn btn-success pull-right" type="submit" wz-next> <input ng-show="!context.loading" class="btn btn-success pull-right" type="submit" wz-finish value="Create" />
Create <button ng-show="context.loading" class="btn btn-success pull-right disabled"><wave-spinner></wave-spinner></button>
</button>
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
</div>
</div> </div>

View File

@ -55,7 +55,7 @@
<li data-match-route="/domains"><a href="/#/domains">Domains</a></li> <li data-match-route="/domains"><a href="/#/domains">Domains</a></li>
<li><a href="/#/roles">Roles</a></li> <li><a href="/#/roles">Roles</a></li>
<li><a href="/#/users">Users</a></li> <li><a href="/#/users">Users</a></li>
<li><a href="/#/accounts">Accounts</a></li> <li><a href="/#/destinations">Destinations</a></li>
</ul> </ul>
<ul ng-show="!currentUser.username" class="nav navbar-nav navbar-right"> <ul ng-show="!currentUser.username" class="nav navbar-nav navbar-right">
<li><a href="/#/login">Login</a></li> <li><a href="/#/login">Login</a></li>

View File

@ -159,3 +159,13 @@ a {
margin-top: 10px; margin-top: 10px;
} }
.wave-spinner {
margin: 5px auto !important;
width: 40px !important;
height: 12px !important;
}
.wave-spinner>div {
background-color: #FFFFFF !important;
}