Add a fetch tag dialog
This commit is contained in:
parent
c1d58bdd6c
commit
70aec00914
13 changed files with 258 additions and 2 deletions
|
@ -1,3 +1,14 @@
|
|||
.repo-panel-info-element .right-controls {
|
||||
margin-bottom: 20px;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.repo-panel-info-element .right-controls .copy-box {
|
||||
width: 400px;
|
||||
display: inline-block;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.repo-panel-info-element .stat-col {
|
||||
border-right: 2px solid #eee;
|
||||
}
|
||||
|
|
|
@ -63,4 +63,9 @@
|
|||
|
||||
.repo-panel-tags-element .options-col {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.repo-panel-tags-element .options-col .fa-download {
|
||||
color: #999;
|
||||
cursor: pointer;
|
||||
}
|
19
static/css/directives/ui/fetch-tag-dialog.css
Normal file
19
static/css/directives/ui/fetch-tag-dialog.css
Normal file
|
@ -0,0 +1,19 @@
|
|||
.fetch-tag-dialog .modal-table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.fetch-tag-dialog .modal-table .first-col {
|
||||
width: 140px;
|
||||
}
|
||||
|
||||
.fetch-tag-dialog .co-dialog .modal-body {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.fetch-tag-dialog .entity-search {
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.fetch-tag-dialog pre.command {
|
||||
margin-top: 10px;
|
||||
}
|
|
@ -4787,6 +4787,20 @@ i.slack-icon {
|
|||
height: 16px;
|
||||
}
|
||||
|
||||
i.docker-icon {
|
||||
background-image: url(/static/img/docker.png);
|
||||
background-size: 16px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
i.rocket-icon {
|
||||
background-image: url(/static/img/rocket.png);
|
||||
background-size: 16px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.external-notification-view-element {
|
||||
margin: 10px;
|
||||
padding: 6px;
|
||||
|
|
70
static/directives/fetch-tag-dialog.html
Normal file
70
static/directives/fetch-tag-dialog.html
Normal file
|
@ -0,0 +1,70 @@
|
|||
<div class="fetch-tag-dialog-element">
|
||||
<!-- Modal message dialog -->
|
||||
<div class="co-dialog modal fade" id="fetchTagDialog">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||
<h4 class="modal-title">
|
||||
Fetch Tag: <i class="fa fa-tag" style="margin-left: 6px; margin-right: 4px"></i> {{ currentTag.name }}
|
||||
</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<table class="modal-table">
|
||||
<tr>
|
||||
<td class="first-col">Image Format:</td>
|
||||
<td>
|
||||
<div class="dropdown-select"
|
||||
placeholder="'(Select Image Format)'"
|
||||
selected-item="currentFormat.title"
|
||||
handle-item-selected="handleFormatSelected(datum)"
|
||||
clear-value="clearCounter">
|
||||
|
||||
<!-- Icons -->
|
||||
<i class="dropdown-select-icon fa fa-lg" ng-class="currentFormat.icon"></i>
|
||||
|
||||
<!-- Dropdown menu -->
|
||||
<ul class="dropdown-select-menu pull-right" role="menu">
|
||||
<li ng-repeat="format in formats">
|
||||
<a href="javascript:void(0)" ng-click="setFormat(format)">
|
||||
<i class="fa fa-lg" ng-class="format.icon"></i> {{ format.title }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr ng-show="currentFormat.require_creds">
|
||||
<td class="first-col">Pull Credentials:</td>
|
||||
<td>
|
||||
<div class="entity-search" namespace="repository.namespace"
|
||||
placeholder="'Choose Pull Credentials'"
|
||||
allowed-entities="['robot']"
|
||||
clear-value="clearCounter"
|
||||
auto-clear="false"
|
||||
current-entity="currentEntity"></div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="cor-loader-inline" ng-if="currentEntity && !currentRobot"></div>
|
||||
<div ng-if="getCommand(currentFormat, currentRobot)">
|
||||
Command:
|
||||
<pre class="command">{{ getCommand(currentFormat, currentRobot) }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<div class="clipboard-copied-message" style="display: none">
|
||||
Copied
|
||||
</div>
|
||||
<input type="hidden" name="command-data" id="command-data"
|
||||
value="{{ getCommand(currentFormat, currentRobot) }}">
|
||||
<button id="copyClipboard" type="button" class="btn btn-primary"
|
||||
data-clipboard-target="command-data"
|
||||
ng-show="getCommand(currentFormat, currentRobot)">Copy Command</button>
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
|
||||
</div>
|
||||
</div><!-- /.modal-content -->
|
||||
</div><!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
</div>
|
|
@ -62,7 +62,14 @@
|
|||
|
||||
<!-- Repository Description -->
|
||||
<div class="description-container">
|
||||
|
||||
<!-- Pull Controls -->
|
||||
<div class="right-controls hidden-sm hidden-xs">
|
||||
Pull Image: <div class="copy-box" hovering-message="true" value="pullCommand"></div>
|
||||
</div>
|
||||
|
||||
<h4 style="font-size:20px;">Description</h4>
|
||||
|
||||
<div class="description markdown-input"
|
||||
content="repository.description"
|
||||
can-write="repository.can_write"
|
||||
|
|
|
@ -52,6 +52,7 @@
|
|||
<a href="javascript:void(0)" ng-click="orderBy('image_id')">Image</a>
|
||||
</td>
|
||||
<td class="options-col"></td>
|
||||
<td class="options-col"></td>
|
||||
</thead>
|
||||
|
||||
<tr class="co-checkable-row"
|
||||
|
@ -75,6 +76,11 @@
|
|||
<span class="image-track-line" ng-class="trackLineClass($parent.$index, it)"
|
||||
ng-style="{'borderColor': it.color}"></span>
|
||||
</td>
|
||||
<td class="options-col">
|
||||
<i class="fa fa-download" data-title="Fetch Tag" bs-tooltip
|
||||
ng-click="fetchTagActionHandler.askFetchTag(tag)">
|
||||
</i>
|
||||
</td>
|
||||
<td class="options-col">
|
||||
<span class="cor-options-menu" ng-if="repository.can_write">
|
||||
<span class="cor-option" option-click="askDeleteTag(tag.name)">
|
||||
|
@ -98,4 +104,7 @@
|
|||
</div>
|
||||
|
||||
<div class="tag-operations-dialog" repository="repository" images="images"
|
||||
action-handler="tagActionHandler"></div>
|
||||
action-handler="tagActionHandler"></div>
|
||||
|
||||
<div class="fetch-tag-dialog" repository="repository" action-handler="fetchTagActionHandler">
|
||||
</div>
|
BIN
static/img/docker.png
Normal file
BIN
static/img/docker.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
BIN
static/img/rocket.png
Normal file
BIN
static/img/rocket.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 618 B |
|
@ -12,7 +12,16 @@ angular.module('quay').directive('repoPanelInfo', function () {
|
|||
'repository': '=repository',
|
||||
'builds': '=builds'
|
||||
},
|
||||
controller: function($scope, $element, ApiService) {
|
||||
controller: function($scope, $element, ApiService, Config) {
|
||||
$scope.$watch('repository', function(repository) {
|
||||
if (!$scope.repository) { return; }
|
||||
|
||||
var namespace = $scope.repository.namespace;
|
||||
var name = $scope.repository.name;
|
||||
|
||||
$scope.pullCommand = 'docker pull ' + Config.getDomain() + '/' + namespace + '/' + name;
|
||||
});
|
||||
|
||||
$scope.updateDescription = function(content) {
|
||||
$scope.repository.description = content;
|
||||
$scope.repository.put();
|
||||
|
|
104
static/js/directives/ui/fetch-tag-dialog.js
Normal file
104
static/js/directives/ui/fetch-tag-dialog.js
Normal file
|
@ -0,0 +1,104 @@
|
|||
/**
|
||||
* An element which adds a of dialog for fetching a tag.
|
||||
*/
|
||||
angular.module('quay').directive('fetchTagDialog', function () {
|
||||
var directiveDefinitionObject = {
|
||||
priority: 0,
|
||||
templateUrl: '/static/directives/fetch-tag-dialog.html',
|
||||
replace: false,
|
||||
transclude: false,
|
||||
restrict: 'C',
|
||||
scope: {
|
||||
'repository': '=repository',
|
||||
'actionHandler': '=actionHandler'
|
||||
},
|
||||
controller: function($scope, $element, $timeout, ApiService, UserService, Config) {
|
||||
$scope.clearCounter = 0;
|
||||
$scope.currentFormat = null;
|
||||
$scope.currentEntity = null;
|
||||
$scope.currentRobot = null;
|
||||
|
||||
$scope.formats = [
|
||||
{
|
||||
'title': 'Squashed Docker Image',
|
||||
'icon': 'fa-file-archive-o',
|
||||
'command': 'curl -L -f {http}://{pull_user}:{pull_password}@{hostname}/c1/squash/{namespace}/{name}/{tag} | docker load',
|
||||
'require_creds': true
|
||||
},
|
||||
|
||||
{
|
||||
'title': 'Basic Docker Pull',
|
||||
'icon': 'docker-icon',
|
||||
'command': 'docker pull {hostname}/{namespace}/{name}:{tag}'
|
||||
}];
|
||||
|
||||
$scope.$watch('currentEntity', function(entity) {
|
||||
if (!entity) {
|
||||
$scope.currentRobot = null;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($scope.currentRobot && $scope.currentRobot.name == entity.name) {
|
||||
return;
|
||||
}
|
||||
|
||||
$scope.currentRobot = null;
|
||||
|
||||
var parts = entity.name.split('+');
|
||||
var namespace = parts[0];
|
||||
var shortname = parts[1];
|
||||
|
||||
var params = {
|
||||
'robot_shortname': shortname
|
||||
};
|
||||
|
||||
var orgname = UserService.isOrganization(namespace) ? namespace : '';
|
||||
ApiService.getRobot(orgname, null, params).then(function(resp) {
|
||||
$scope.currentRobot = resp;
|
||||
}, ApiService.errorDisplay('Cannot download robot token'));
|
||||
});
|
||||
|
||||
$scope.getCommand = function(format, robot) {
|
||||
if (!format || !format.command) { return ''; }
|
||||
if (format.require_creds && !robot) { return ''; }
|
||||
|
||||
var params = {
|
||||
'pull_user': robot ? robot.name : '',
|
||||
'pull_password': robot ? robot.token : '',
|
||||
'hostname': Config.getDomain(),
|
||||
'http': Config.getHttp(),
|
||||
'namespace': $scope.repository.namespace,
|
||||
'name': $scope.repository.name,
|
||||
'tag': $scope.currentTag.name
|
||||
};
|
||||
|
||||
var value = format.command;
|
||||
for (var param in params) {
|
||||
if (!params.hasOwnProperty(param)) { continue; }
|
||||
value = value.replace('{' + param + '}', params[param]);
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
$scope.setFormat = function(format) {
|
||||
$scope.currentFormat = format;
|
||||
};
|
||||
|
||||
$scope.actionHandler = {
|
||||
'askFetchTag': function(tag) {
|
||||
$scope.currentTag = tag;
|
||||
$scope.currentFormat = null;
|
||||
$scope.currentEntity = null;
|
||||
$scope.currentRobot = null;
|
||||
|
||||
$scope.clearCounter++;
|
||||
|
||||
$element.find('#copyClipboard').clipboardCopy();
|
||||
$element.find('#fetchTagDialog').modal({});
|
||||
}
|
||||
};
|
||||
}
|
||||
};
|
||||
return directiveDefinitionObject;
|
||||
});
|
|
@ -54,6 +54,10 @@ angular.module('quay').factory('Config', [function() {
|
|||
return config['PREFERRED_URL_SCHEME'] + '://' + auth + config['SERVER_HOSTNAME'];
|
||||
};
|
||||
|
||||
config.getHttp = function() {
|
||||
return config['PREFERRED_URL_SCHEME'];
|
||||
};
|
||||
|
||||
config.getUrl = function(opt_path) {
|
||||
var path = opt_path || '';
|
||||
return config['PREFERRED_URL_SCHEME'] + '://' + config['SERVER_HOSTNAME'] + path;
|
||||
|
|
|
@ -83,6 +83,10 @@ function(ApiService, CookieService, $rootScope, Config) {
|
|||
});
|
||||
};
|
||||
|
||||
userService.isOrganization = function(name) {
|
||||
return !!userService.getOrganization(name);
|
||||
};
|
||||
|
||||
userService.getOrganization = function(name) {
|
||||
if (!userResponse || !userResponse.organizations) { return null; }
|
||||
for (var i = 0; i < userResponse.organizations.length; ++i) {
|
||||
|
|
Reference in a new issue