Redo user admin page to match the style of the org admin page

This commit is contained in:
Joseph Schorr 2013-11-06 17:59:16 -05:00
parent dba806fd97
commit 10db2884ac
7 changed files with 91 additions and 176 deletions

View file

@ -1369,22 +1369,30 @@ p.editable:hover i {
font-size: 22px;
}
#repository-usage-chart path.warning-0 {
#repository-usage-chart.limit-at path.arc-0 {
fill: #c09853;
}
#repository-usage-chart path.error-0 {
#repository-usage-chart.limit-over path.arc-0 {
fill: #b94a48;
}
#repository-usage-chart path.warning-1 {
#repository-usage-chart.limit-near path.arc-0 {
fill: #468847;
}
#repository-usage-chart.limit-over path.arc-1 {
fill: #fcf8e3;
}
#repository-usage-chart path.error-1 {
#repository-usage-chart.limit-at path.arc-1 {
fill: #f2dede;
}
#repository-usage-chart.limit-near path.arc-1 {
fill: #dff0d8;
}
.plan-manager-element .usage-caption {
display: inline-block;
color: #aaa;
@ -1525,22 +1533,22 @@ p.editable:hover i {
padding: 6px;
}
.org-admin .plans-table thead td {
.plan-manager-element .plans-table thead td {
color: #aaa;
font-weight: bold;
}
.org-admin .plans-table td {
.plan-manager-element .plans-table td {
padding: 10px;
font-size: 16px;
vertical-align: middle;
}
.org-admin .plans-table td.controls {
.plan-manager-element .plans-table td.controls {
text-align: right;
}
.org-admin .plans-table .plan-price {
.plan-manager-element .plans-table .plan-price {
font-size: 16px;
margin-bottom: 0px;
}

View file

@ -3,19 +3,23 @@
<i class="fa fa-spinner fa-spin fa-3x" ng-show="planLoading"></i>
<!-- Alerts -->
<div class="alert alert-danger" ng-show="overLimit && !planLoading">
You are using more private repositories than your plan allows, please
upgrade your subscription to avoid disruptions in your organization's service.
<div class="alert alert-danger" ng-show="limit == 'over' && !planLoading">
You are using more private repositories than your plan allows. Please
upgrade your subscription to avoid disruptions in your <span ng-show="organization">organization's</span> service.
</div>
<div class="alert alert-warning" ng-show="nearLimit && !planLoading">
<div class="alert alert-warning" ng-show="limit == 'at' && !planLoading">
You are at your current plan's number of allowed private repositories. Please upgrade your subscription to avoid future disruptions in your <span ng-show="organization">organization's</span> service.
</div>
<div class="alert alert-success" ng-show="limit == 'near' && !planLoading">
You are nearing the number of allowed private repositories. It might be time to think about
upgrading your subscription to avoid future disruptions in your organization's service.
upgrading your subscription to avoid future disruptions in your <span ng-show="organization">organization's</span> service.
</div>
<!-- Chart -->
<div>
<div id="repository-usage-chart"></div>
<div id="repository-usage-chart" class="limit-{{limit}}"></div>
<span class="usage-caption" ng-show="chart">Repository Usage</span>
</div>

View file

@ -557,12 +557,13 @@ quayApp.directive('planManager', function () {
$scope.planUsagePercent = sub.usedPrivateRepos * 100 / $scope.subscribedPlan.privateRepos;
if (sub.usedPrivateRepos > $scope.subscribedPlan.privateRepos) {
$scope.overLimit = true;
$scope.limit = 'over';
} else if (sub.usedPrivateRepos == $scope.subscribedPlan.privateRepos) {
$scope.limit = 'at';
} else if (sub.usedPrivateRepos >= $scope.subscribedPlan.privateRepos * 0.7) {
$scope.nearLimit = true;
$scope.limit = 'near';
} else {
$scope.overLimit = false;
$scope.nearLimit = false;
$scope.limit = 'none';
}
if (!$scope.chart) {
@ -588,9 +589,7 @@ quayApp.directive('planManager', function () {
var update = function() {
$scope.planLoading = true;
if (!$scope.plans) { return; }
if (!$scope.user && !$scope.organization) { return; }
PlanService.getSubscription($scope.organization, subscribedToPlan, function() {
// User/Organization has no subscription.
@ -599,6 +598,7 @@ quayApp.directive('planManager', function () {
};
var loadPlans = function() {
if (!$scope.user && !$scope.organization) { return; }
PlanService.getPlans(function(plans) {
$scope.plans = plans[$scope.organization ? 'business' : 'user'];
update();
@ -606,15 +606,15 @@ quayApp.directive('planManager', function () {
};
// Start the initial download.
loadPlans();
update();
$scope.planLoading = true;
loadPlans();
$scope.$watch('organization', function() {
update();
loadPlans();
});
$scope.$watch('user', function() {
update();
loadPlans();
});
}
};

View file

@ -667,91 +667,24 @@ function RepoAdminCtrl($scope, Restangular, $routeParams, $rootScope) {
}
function UserAdminCtrl($scope, $timeout, Restangular, PlanService, UserService, KeyService, $routeParams) {
// Load the list of plans.
PlanService.getPlans(function(plans) {
$scope.plans = plans.user;
});
$scope.$watch(function () { return UserService.currentUser(); }, function (currentUser) {
$scope.askForPassword = currentUser.askForPassword;
if (!currentUser.anonymous) {
$scope.user = currentUser;
}
$scope.loading = false;
}, true);
var subscribedToPlan = function(sub) {
$scope.subscription = sub;
PlanService.getPlan(sub.plan, function(subscribedPlan) {
$scope.subscribedPlan = subscribedPlan;
$scope.planUsagePercent = sub.usedPrivateRepos * 100 / $scope.subscribedPlan.privateRepos;
if (sub.usedPrivateRepos > $scope.subscribedPlan.privateRepos) {
$scope.errorMessage = 'You are using more private repositories than your plan allows, please upgrade your subscription to avoid disruptions in your service.';
} else {
$scope.errorMessage = null;
}
$scope.planLoading = false;
$scope.planChanging = false;
mixpanel.people.set({
'plan': sub.plan
});
});
};
$scope.planLoading = true;
UserService.getCurrentSubscription(subscribedToPlan, function() {
// User has no subscription
$scope.planChanging = false;
});
$scope.planChanging = false;
$scope.subscribe = function(planId) {
PlanService.showSubscribeDialog($scope, planId, null, function() {
// Subscribing.
$scope.planChanging = true;
}, function(plan) {
// Subscribed.
UserService.resetCurrentSubscription();
subscribedToPlan(plan);
}, function() {
// Failure.
$scope.errorMessage = 'Unable to subscribe.';
$scope.planChanging = false;
});
};
$scope.changeSubscription = function(planId) {
$scope.planChanging = true;
$scope.errorMessage = undefined;
var subscriptionDetails = {
plan: planId,
};
UserService.resetCurrentSubscription();
var changeSubscriptionRequest = Restangular.one('user/plan');
changeSubscriptionRequest.customPUT(subscriptionDetails).then(subscribedToPlan, function() {
// Failure
$scope.errorMessage = 'Unable to change subscription.';
$scope.planChanging = false;
});
};
$scope.cancelSubscription = function() {
$scope.changeSubscription('free');
};
// Show the subscribe dialog if a plan was requested.
var requested = $routeParams['plan']
if (requested !== undefined && requested !== 'free') {
PlanService.getPlan(requested, function(found) {
if (found) {
$scope.subscribe(requested);
}
});
// TODO: this.
}
$scope.loading = true;
$scope.updatingUser = false;
$scope.changePasswordSuccess = false;
$('.form-change-pw').popover();
$scope.changePassword = function() {
@ -768,6 +701,7 @@ function UserAdminCtrl($scope, $timeout, Restangular, PlanService, UserService,
$scope.user.repeatPassword = '';
$scope.changePasswordForm.$setPristine();
// Reload the user.
UserService.load();
}, function(result) {
$scope.updatingUser = false;
@ -1176,6 +1110,7 @@ function OrgAdminCtrl($rootScope, $scope, Restangular, $routeParams, UserService
});
var orgname = $routeParams.orgname;
$scope.orgname = orgname;
var loadOrganization = function() {
var getOrganization = Restangular.one(getRestUrl('organization', orgname));

View file

@ -1175,18 +1175,6 @@ RepositoryUsageChart.prototype.drawInternal_ = function() {
var data = [count, Math.max(0, total - count)];
var getClass = function(i) {
if (total > 0 && (count / total) >= 0.7) {
return 'warning-' + i;
}
if (count >= total) {
return 'error-' + i;
}
return 'normal';
};
var arcTween = function(a) {
var i = d3.interpolate(this._current, a);
this._current = i(0);
@ -1208,7 +1196,7 @@ RepositoryUsageChart.prototype.drawInternal_ = function() {
.data(pie)
.enter().append("path")
.attr("fill", function(d, i) { return color(i); })
.attr("class", function(d, i) { return getClass(i); })
.attr("class", function(d, i) { return 'arc-' + i; })
.attr("d", arc)
.each(function(d) { this._current = d; }); // store the initial angles
@ -1217,9 +1205,7 @@ RepositoryUsageChart.prototype.drawInternal_ = function() {
} else {
pie.value(function(d, i) { return data[i]; }); // change the value function
this.path_ = this.path_.data(pie); // compute the new angles
this.path_.transition().duration(duration).attrTween("d", arcTween); // redraw the arcs
this.path_.attr("class", function(d, i) { return getClass(i); });
// Update the text.
this.text_.text(this.count_ + ' / ' + this.total_);

View file

@ -23,7 +23,7 @@
<div class="tab-content">
<!-- Plans tab -->
<div id="plan" class="tab-pane active">
<div class="plan-manager" organization="organization.name"></div>
<div class="plan-manager" organization="orgname"></div>
</div>
<!-- Members tab -->

View file

@ -1,80 +1,62 @@
<div class="container user-admin">
<div class="loading" ng-show="planLoading || planChanging">
<i class="fa fa-spinner fa-spin fa-3x"></i>
</div>
<div class="row" ng-show="errorMessage">
<div class="col-md-12">
<div class="alert alert-danger">{{ errorMessage }}</div>
<div class="loading" ng-show="loading">
<i class="fa fa-spinner fa-spin fa-3x"></i>
</div>
<div class="loading" ng-show="!loading && !user">
No matching user found
</div>
<div class="user-admin container" ng-show="!loading && user">
<div class="row">
<div class="organization-header-element">
<img src="//www.gravatar.com/avatar/{{ user.gravatar }}?s=24&amp;d=identicon">
<span class="organization-name">
{{ user.username }}
</span>
</div>
</div>
<div class="row" ng-show="askForPassword">
<div class="col-md-12">
<div class="alert alert-warning">Your account does not currently have a password. You will need to create a password before you will be able to <strong>push</strong> or <strong>pull</strong> repositories.</div>
</div>
</div>
<div class="row" ng-hide="planLoading">
<div class="col-md-3" ng-repeat='plan in plans'>
<div class="panel" ng-class="{'panel-success': subscription.plan == plan.stripeId, 'panel-default': subscription.plan != plan.stripeId}">
<div class="panel-heading">
{{ plan.title }}
<span class="pull-right" ng-show="subscription.plan == plan.stripeId">
<i class="fa fa-ok"></i>
Subscribed
</span>
</div>
<div class="panel-body panel-plan">
<div class="plan-price">${{ plan.price / 100 }}</div>
<div class="plan-description"><b>{{ plan.privateRepos }}</b> Private Repositories</div>
<div ng-switch='plan.stripeId'>
<div ng-switch-when='free'>
<button class="btn button-hidden">Hidden!</button>
</div>
<div ng-switch-default>
<button class="btn btn-primary" ng-show="subscription.plan === 'free'" ng-click="subscribe(plan.stripeId)">Subscribe</button>
<button class="btn btn-default" ng-hide="subscription.plan === 'free' || subscription.plan === plan.stripeId" ng-click="changeSubscription(plan.stripeId)">Change</button>
<button class="btn btn-danger" ng-show="subscription.plan === plan.stripeId" ng-click="cancelSubscription()">Cancel</button>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row" ng-show="subscription">
<div class="col-md-6">
<div class="panel panel-default">
<div class="panel-heading">
Plan Usage
</div>
<div class="panel-body">
<div class="used-description">
<b>{{ subscription.usedPrivateRepos }}</b> of <b>{{ subscribedPlan.privateRepos }}</b> private repositories used
</div>
<div class="progress">
<div ng-class="'progress-bar ' + (planUsagePercent > 90 ? 'progress-bar-danger' : '')" role="progressbar" aria-valuenow="{{ subscription.usedPrivateRepos }}" aria-valuemin="0" aria-valuemax="{{ subscribedPlan.privateRepos }}" style="width: {{ planUsagePercent }}%;">
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="loading" ng-show="updatingUser">
<i class="fa fa-spinner fa-spin fa-3x"></i>
<!-- Side tabs -->
<div class="col-md-2">
<ul class="nav nav-pills nav-stacked">
<li class="active"><a href="javascript:void(0)" data-toggle="tab" data-target="#plan">Plan and Usage</a></li>
<li><a href="javascript:void(0)" data-toggle="tab" data-target="#password">Set Password</a></li>
</ul>
</div>
<div class="col-md-3">
<div class="panel panel-default">
<div class="panel-heading">
Change Password
<!-- Content -->
<div class="col-md-10">
<div class="tab-content">
<!-- Plans tab -->
<div id="plan" class="tab-pane active">
<div class="plan-manager" user="user.username"></div>
</div>
<div class="panel-body">
<form class="form-change-pw" name="changePasswordForm" ng-submit="changePassword()" data-trigger="manual" data-content="{{ changePasswordError }}" data-placement="right" ng-show="!awaitingConfirmation && !registering">
<!-- Change password tab -->
<div id="password" class="tab-pane">
<div class="loading" ng-show="updatingUser">
<i class="fa fa-spinner fa-spin fa-3x"></i>
</div>
<form class="form-change-pw" name="changePasswordForm" ng-submit="changePassword()" data-trigger="manual"
data-content="{{ changePasswordError }}" data-placement="right" ng-show="!awaitingConfirmation && !registering">
<input type="password" class="form-control" placeholder="Your new password" ng-model="user.password" required>
<input type="password" class="form-control" placeholder="Verify your new password" ng-model="user.repeatPassword" match="user.password" required>
<button class="btn btn-danger" ng-disabled="changePasswordForm.$invalid" type="submit" analytics-on analytics-event="register">Change Password</button>
<input type="password" class="form-control" placeholder="Verify your new password" ng-model="user.repeatPassword"
match="user.password" required>
<button class="btn btn-danger" ng-disabled="changePasswordForm.$invalid" type="submit"
analytics-on analytics-event="register">Change Password</button>
<span class="help-block" ng-show="changePasswordSuccess">Password changed successfully</span>
</form>
</div>
</div>
</div>
</div>
</div>