- Make robots manager fully responsive
- Add a cor-table which automatically stacks and collapses on mobile views
This commit is contained in:
parent
d26927cb45
commit
32635cc641
8 changed files with 222 additions and 37 deletions
|
@ -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;
|
||||
}
|
||||
|
|
55
static/css/directives/ui/manager-header.css
Normal file
55
static/css/directives/ui/manager-header.css
Normal 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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
4
static/directives/manager-header.html
Normal file
4
static/directives/manager-header.html
Normal file
|
@ -0,0 +1,4 @@
|
|||
<div class="manager-header-element">
|
||||
<div class="manager-header-side-controls" ng-transclude></div>
|
||||
<h3>{{ headerTitle }}</h3>
|
||||
</div>
|
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
|
18
static/js/directives/ui/manager-header.js
Normal file
18
static/js/directives/ui/manager-header.js
Normal 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;
|
||||
});
|
Reference in a new issue