- 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;
|
padding: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media (max-width: 767px) {
|
||||||
|
.co-tab-content {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.co-tabs li {
|
.co-tabs li {
|
||||||
list-style: none;
|
list-style: none;
|
||||||
display: block;
|
display: block;
|
||||||
|
@ -206,15 +212,16 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-tab-element.open li {
|
.co-tab-element.open li {
|
||||||
display: block;
|
height: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-tab-element.closed li {
|
.co-tab-element.closed li {
|
||||||
display: none;
|
height: 0px;
|
||||||
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
.co-tab-element.closed li.active {
|
.co-tab-element.closed li.active {
|
||||||
display: block;
|
height: 60px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -960,6 +967,36 @@
|
||||||
padding-left: 28px;
|
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 {
|
.cor-checkable-menu {
|
||||||
display: inline-block;
|
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 {
|
.robots-manager-element .robot a {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -78,9 +82,3 @@
|
||||||
.robots-manager-element .member-perm-summary {
|
.robots-manager-element .member-perm-summary {
|
||||||
margin-right: 14px;
|
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;
|
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 class="cor-loader" ng-show="loading"></div>
|
||||||
|
|
||||||
<div ng-show="!loading">
|
<div ng-show="!loading">
|
||||||
<div class="manager-header">
|
<div class="manager-header" header-title="Robot Accounts">
|
||||||
<div class="side-controls">
|
<span class="popup-input-button" pattern="ROBOT_PATTERN"
|
||||||
<span class="popup-input-button" pattern="ROBOT_PATTERN"
|
placeholder="'Robot Account Name'"
|
||||||
placeholder="'Robot Account Name'"
|
submitted="createRobot(value)">
|
||||||
submitted="createRobot(value)">
|
<i class="fa fa-plus"></i> Create Robot Account
|
||||||
<i class="fa fa-plus"></i> Create Robot Account
|
</span>
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<h3>Robot Accounts</h3>
|
|
||||||
</div>
|
</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
|
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
|
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.
|
be shared, such as deployment systems.
|
||||||
</div>
|
</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...">
|
<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" ng-if="!robots.length">
|
||||||
<div class="empty-primary-msg">No robot accounts defined.</div>
|
<div class="empty-primary-msg">No robot accounts defined.</div>
|
||||||
|
@ -37,9 +34,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table class="co-table" ng-if="(robots | filter:robotFilter).length">
|
<table class="cor-table" ng-if="(robots | filter:robotFilter).length">
|
||||||
<thead>
|
<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>Robot Account Name</td>
|
||||||
<td ng-if="organization && Config.isNewLayout()">Teams</td>
|
<td ng-if="organization && Config.isNewLayout()">Teams</td>
|
||||||
<td ng-if="Config.isNewLayout()">Repository Permissions</td>
|
<td ng-if="Config.isNewLayout()">Repository Permissions</td>
|
||||||
|
@ -48,7 +45,7 @@
|
||||||
|
|
||||||
<tbody ng-repeat="robotInfo in robots | filter:robotFilter | orderBy:getShortenedRobotName">
|
<tbody ng-repeat="robotInfo in robots | filter:robotFilter | orderBy:getShortenedRobotName">
|
||||||
<tr ng-class="robotInfo.showing_permissions ? 'open' : 'closed'">
|
<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)">
|
<span ng-if="robotInfo.repositories.length > 0" ng-click="showPermissions(robotInfo)">
|
||||||
<i class="fa"
|
<i class="fa"
|
||||||
ng-class="robotInfo.showing_permissions ? 'fa-caret-down' : 'fa-caret-right'"
|
ng-class="robotInfo.showing_permissions ? 'fa-caret-down' : 'fa-caret-right'"
|
||||||
|
@ -56,7 +53,7 @@
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="robot">
|
<td class="robot">
|
||||||
<i class="fa fa-wrench"></i>
|
<i class="fa fa-wrench hidden-xs"></i>
|
||||||
<a ng-click="showRobot(robotInfo)">
|
<a ng-click="showRobot(robotInfo)">
|
||||||
<span class="prefix">{{ getPrefix(robotInfo.name) }}+</span>{{ getShortenedName(robotInfo.name) }}
|
<span class="prefix">{{ getPrefix(robotInfo.name) }}+</span>{{ getShortenedName(robotInfo.name) }}
|
||||||
</a>
|
</a>
|
||||||
|
@ -81,7 +78,12 @@
|
||||||
|
|
||||||
<span class="member-perm-summary" ng-if="robotInfo.repositories.length > 0">
|
<span class="member-perm-summary" ng-if="robotInfo.repositories.length > 0">
|
||||||
Permissions on
|
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">repository</span>
|
||||||
<span ng-if="robotInfo.repositories.length > 1">repositories</span>
|
<span ng-if="robotInfo.repositories.length > 1">repositories</span>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -715,4 +715,85 @@ angular.module("core-ui", [])
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return directiveDefinitionObject;
|
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