- Make robots manager fully responsive

- Add a cor-table which automatically stacks and collapses on mobile views
This commit is contained in:
Joseph Schorr 2015-04-17 16:43:53 -04:00
parent d26927cb45
commit 32635cc641
8 changed files with 222 additions and 37 deletions

View file

@ -100,6 +100,12 @@
padding: 30px;
}
@media (max-width: 767px) {
.co-tab-content {
padding: 20px;
}
}
.co-tabs li {
list-style: none;
display: block;
@ -206,15 +212,16 @@
}
.co-tab-element.open li {
display: block;
height: 60px;
}
.co-tab-element.closed li {
display: none;
height: 0px;
overflow: hidden;
}
.co-tab-element.closed li.active {
display: block;
height: 60px;
}
}
@ -960,6 +967,36 @@
padding-left: 28px;
}
.co-table .mobile-row {
border-bottom: 2px solid #eee;
padding-bottom: 10px;
margin-bottom: 10px;
position: relative;
}
.co-table .mobile-row:last-child {
border-bottom: 0px solid #eee;
padding-bottom: 0px;
margin-bottom: 0px;
}
.co-table .mobile-row .mobile-col-header {
font-weight: bold;
color: #444;
}
.co-table .mobile-row .mobile-col-value {
padding: 6px;
}
.co-table .mobile-row .options-col {
position: absolute;
top: -6px;
right: 0px;
}
.cor-checkable-menu {
display: inline-block;
}

View file

@ -0,0 +1,55 @@
.manager-header {
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
.manager-header h3 {
margin-bottom: 10px;
}
.manager-header .manager-header-side-controls {
float: right;
}
.manager-filter-box {
margin-bottom: 20px;
height: 30px;
}
.manager-filter-box input {
float: right;
min-width: 175px;
max-width: 300px;
}
@media (max-width: 767px) {
.manager-header {
position: relative;
padding-bottom: 36px;
}
.manager-header .manager-header-side-controls {
float: none;
display: block;
border-top: 1px solid #eee;
padding-top: 6px;
position: absolute;
top: 34px;
left: 0px;
right: 0px;
}
.manager-header .manager-header-side-controls .btn {
display: block;
width: 100%;
}
.manager-filter-box {
margin-bottom: 30px;
}
.manager-filter-box input {
max-width: none;
}
}

View file

@ -1,3 +1,7 @@
.robots-manager-element .robot {
white-space: nowrap;
}
.robots-manager-element .robot a {
font-size: 16px;
cursor: pointer;
@ -78,9 +82,3 @@
.robots-manager-element .member-perm-summary {
margin-right: 14px;
}
.robots-manager-element .co-filter-box {
float: right;
min-width: 175px;
margin-bottom: 10px;
}

View file

@ -4744,13 +4744,3 @@ i.rocket-icon {
text-align: center;
}
.manager-header {
margin-bottom: 10px;
padding-bottom: 10px;
border-bottom: 1px solid #eee;
}
.manager-header h3 {
margin-bottom: 10px;
}

View file

@ -0,0 +1,4 @@
<div class="manager-header-element">
<div class="manager-header-side-controls" ng-transclude></div>
<h3>{{ headerTitle }}</h3>
</div>

View file

@ -2,26 +2,23 @@
<div class="cor-loader" ng-show="loading"></div>
<div ng-show="!loading">
<div class="manager-header">
<div class="side-controls">
<span class="popup-input-button" pattern="ROBOT_PATTERN"
placeholder="'Robot Account Name'"
submitted="createRobot(value)">
<i class="fa fa-plus"></i> Create Robot Account
</span>
</div>
<h3>Robot Accounts</h3>
<div class="manager-header" header-title="Robot Accounts">
<span class="popup-input-button" pattern="ROBOT_PATTERN"
placeholder="'Robot Account Name'"
submitted="createRobot(value)">
<i class="fa fa-plus"></i> Create Robot Account
</span>
</div>
<div class="manager-header section-description-header">
<div class="section-description-header">
Robot Accounts are named tokens that can be granted permissions on multiple repositories
under this <span ng-if="organization">organization</span><span ng-if="!organization">user namespace</span>. They are typically used in environments where credentials will
be shared, such as deployment systems.
</div>
<span class="co-filter-box" ng-show="robots.length">
<div class="manager-filter-box" ng-show="robots.length">
<input class="form-control" type="text" ng-model="robotFilter" placeholder="Filter Robot Accounts...">
</span>
</div>
<div class="empty" ng-if="!robots.length">
<div class="empty-primary-msg">No robot accounts defined.</div>
@ -37,9 +34,9 @@
</div>
</div>
<table class="co-table" ng-if="(robots | filter:robotFilter).length">
<table class="cor-table" ng-if="(robots | filter:robotFilter).length">
<thead>
<td class="caret-col" ng-if="(user || organization.is_admin) && Config.isNewLayout()"></td>
<td class="caret-col hidden-xs" ng-if="(user || organization.is_admin) && Config.isNewLayout()"></td>
<td>Robot Account Name</td>
<td ng-if="organization && Config.isNewLayout()">Teams</td>
<td ng-if="Config.isNewLayout()">Repository Permissions</td>
@ -48,7 +45,7 @@
<tbody ng-repeat="robotInfo in robots | filter:robotFilter | orderBy:getShortenedRobotName">
<tr ng-class="robotInfo.showing_permissions ? 'open' : 'closed'">
<td class="caret-col" ng-if="(user || organization.is_admin) && Config.isNewLayout()">
<td class="caret-col hidden-xs" ng-if="(user || organization.is_admin) && Config.isNewLayout()">
<span ng-if="robotInfo.repositories.length > 0" ng-click="showPermissions(robotInfo)">
<i class="fa"
ng-class="robotInfo.showing_permissions ? 'fa-caret-down' : 'fa-caret-right'"
@ -56,7 +53,7 @@
</span>
</td>
<td class="robot">
<i class="fa fa-wrench"></i>
<i class="fa fa-wrench hidden-xs"></i>
<a ng-click="showRobot(robotInfo)">
<span class="prefix">{{ getPrefix(robotInfo.name) }}+</span>{{ getShortenedName(robotInfo.name) }}
</a>
@ -81,7 +78,12 @@
<span class="member-perm-summary" ng-if="robotInfo.repositories.length > 0">
Permissions on
<span class="anchor" href="javascript:void(0)" is-text-only="!organization.is_admin" ng-click="showPermissions(robotInfo)">{{ robotInfo.repositories.length }}
<span class="anchor hidden-xs" href="javascript:void(0)" is-text-only="!organization.is_admin"
ng-click="showPermissions(robotInfo)">{{ robotInfo.repositories.length }}
<span ng-if="robotInfo.repositories.length == 1">repository</span>
<span ng-if="robotInfo.repositories.length > 1">repositories</span>
</span>
<span class="visible-xs" href="javascript:void(0)">{{ robotInfo.repositories.length }}
<span ng-if="robotInfo.repositories.length == 1">repository</span>
<span ng-if="robotInfo.repositories.length > 1">repositories</span>
</span>

View file

@ -715,4 +715,85 @@ angular.module("core-ui", [])
}
};
return directiveDefinitionObject;
});
})
.directive('corTable', function() {
var directiveDefinitionObject = {
priority: 1,
replace: false,
transclude: false,
restrict: 'C',
scope: {},
compile: function(tElement, tAttrs, transclude) {
if (!window.matchMedia('(max-width: 767px)').matches) {
return;
}
var cloneWithAttr = function(e, kind, opt_fullclone) {
var clone = $(document.createElement(kind));
var attributes = $(e).prop("attributes");
$.each(attributes, function() {
clone.attr(this.name, this.value);
});
if (opt_fullclone) {
for (var i = 0; i < e.childNodes.length; ++i) {
clone.append($(e.childNodes[i]).clone(true));
}
}
return clone;
};
var appendRepeater = function(div, tr, headers) {
// Find all the tds directly under the tr and convert into a header + value span.
tr.children('td').each(function(idx, td) {
var displayer = cloneWithAttr(tr, 'div');
displayer.append(headers[idx].clone(true).addClass('mobile-col-header'));
displayer.append(cloneWithAttr(td, 'div', true).addClass('mobile-col-value'));
div.append(displayer);
});
};
// Find the thead's tds and turn them into header elements.
var headers = [];
tElement.find('thead td').each(function(idx, td) {
headers.push(cloneWithAttr(td, 'div', true));
});
// Find the element with the 'ng-repeat'.
var repeater = tElement.find('[ng-repeat]')[0];
// Convert the repeater into a <div> repeater.
var divRepeater = cloneWithAttr(repeater, 'div').addClass('mobile-row');
// If the repeater is a tbody, then we append each child tr. Otherwise, the repeater
// itself should be a tr.
if (repeater.nodeName.toLowerCase() == 'tbody') {
$(repeater).children().each(function(idx, tr) {
appendRepeater(divRepeater, $(tr), headers);
});
} else {
appendRepeater(divRepeater, $(repeater), headers);
}
var repeaterBody = $(document.createElement('tbody'));
var repeaterTr = $(document.createElement('tr'))
var repeaterTd = $(document.createElement('td'))
repeaterTd.append(divRepeater);
repeaterTr.append(repeaterTd);
repeaterBody.append(repeaterTr);
// Remove the tbody and thead.
tElement.find('thead').remove();
tElement.find('tbody').remove();
tElement.append(repeaterBody);
},
controller: function($rootScope, $scope, $element) {
$element.addClass('co-table');
}
};
return directiveDefinitionObject;
});

View file

@ -0,0 +1,18 @@
/**
* An element which displays the header bar for a manager UI component.
*/
angular.module('quay').directive('managerHeader', function () {
var directiveDefinitionObject = {
priority: 0,
templateUrl: '/static/directives/manager-header.html',
replace: false,
transclude: true,
restrict: 'C',
scope: {
'headerTitle': '@headerTitle'
},
controller: function($scope, $element) {
}
};
return directiveDefinitionObject;
});