mirror of
https://github.com/Joxit/docker-registry-ui.git
synced 2025-04-27 23:50:01 +03:00
Merge pull request #86 from Joxit/feat/36-pagination
[Feat #36] Pagination in taglist ## UI update  resolves #36 cc @madhukar93 @gionn
This commit is contained in:
commit
0f805daafa
11 changed files with 253 additions and 74 deletions
|
@ -58,6 +58,7 @@
|
|||
<script src="tags/dialogs/menu.tag" type="riot/tag"></script>
|
||||
<script src="tags/image-size.tag" type="riot/tag"></script>
|
||||
<script src="tags/image-date.tag" type="riot/tag"></script>
|
||||
<script src="tags/pagination.tag" type="riot/tag"></script>
|
||||
<script src="tags/app.tag" type="riot/tag"></script>
|
||||
<script src="scripts/http.js"></script>
|
||||
<script src="scripts/script.js"></script>
|
||||
|
|
|
@ -85,7 +85,7 @@ registryUI.removeServer = function(url) {
|
|||
}
|
||||
|
||||
registryUI.updateHistory = function(url) {
|
||||
history.pushState(null, '', (url ? '?url=' + registryUI.encodeURI(url) : '?') + window.location.hash);
|
||||
registryUI.updateQueryString({ url: registryUI.encodeURI(url) })
|
||||
registryUI._url = url;
|
||||
}
|
||||
|
||||
|
@ -100,10 +100,12 @@ registryUI.getUrlQueryParam = function () {
|
|||
};
|
||||
|
||||
registryUI.encodeURI = function(url) {
|
||||
if (!url) { return; }
|
||||
return url.indexOf('&') < 0 ? window.encodeURIComponent(url) : btoa(url);
|
||||
};
|
||||
|
||||
registryUI.decodeURI = function(url) {
|
||||
if (!url) { return; }
|
||||
return url.startsWith('http') ? window.decodeURIComponent(url) : atob(url);
|
||||
};
|
||||
|
||||
|
|
|
@ -65,4 +65,50 @@ registryUI.getHistoryIcon = function(attribute) {
|
|||
default:
|
||||
''
|
||||
}
|
||||
}
|
||||
|
||||
registryUI.getPage = function(elts, page, limit) {
|
||||
if (!limit) { limit = 100; }
|
||||
if (!elts) { return []; }
|
||||
return elts.slice((page - 1) * limit, limit * page);
|
||||
}
|
||||
|
||||
registryUI.getNumPages = function(elts, limit) {
|
||||
if (!limit) { limit = 100; }
|
||||
if (!elts) { return 0; }
|
||||
return Math.trunc(elts.length / limit) + 1;
|
||||
}
|
||||
|
||||
registryUI.getPageLabels = function(page, nPages) {
|
||||
var pageLabels = [];
|
||||
var maxItems = 10;
|
||||
if (nPages === 1) { return pageLabels; }
|
||||
if (page !== 1 && nPages >= maxItems) {
|
||||
pageLabels.push({'icon': 'first_page', page: 1});
|
||||
pageLabels.push({'icon': 'chevron_left', page: page - 1});
|
||||
}
|
||||
var start = Math.round(Math.max(1, Math.min(page - maxItems / 2, nPages - maxItems + 1)));
|
||||
for (var i = start; i < Math.min(nPages + 1, start + maxItems); i++) {
|
||||
pageLabels.push({
|
||||
page: i,
|
||||
current: i === page,
|
||||
'space-left': page === 1 && nPages > maxItems,
|
||||
'space-right': page === nPages && nPages > maxItems
|
||||
});
|
||||
}
|
||||
if (page !== nPages && nPages >= maxItems) {
|
||||
pageLabels.push({'icon': 'chevron_right', page: page + 1});
|
||||
pageLabels.push({'icon': 'last_page', page: nPages});
|
||||
}
|
||||
return pageLabels;
|
||||
}
|
||||
|
||||
registryUI.updateQueryString = function(qs) {
|
||||
var search = '';
|
||||
for (var key in qs) {
|
||||
if (qs[key] !== undefined) {
|
||||
search += (search.length > 0 ? '&' : '?') +key + '=' + qs[key];
|
||||
}
|
||||
}
|
||||
history.pushState(null, '', search + window.location.hash);
|
||||
}
|
|
@ -48,14 +48,24 @@ main {
|
|||
font-weight: inherit;
|
||||
}
|
||||
|
||||
material-card {
|
||||
min-height: 200px;
|
||||
material-card, pagination .conatianer {
|
||||
max-width: 75%;
|
||||
margin: auto;
|
||||
margin-top: 20px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
pagination .conatianer {
|
||||
display: flex;
|
||||
display: -moz-flex;
|
||||
display: -webkit-flex;
|
||||
display: -ms-flexbox;
|
||||
}
|
||||
|
||||
pagination .conatianer .pagination-centered {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 950px){
|
||||
material-card {
|
||||
width: 95%;
|
||||
|
@ -212,12 +222,14 @@ material-card table th {
|
|||
}
|
||||
|
||||
material-card material-button:hover,
|
||||
material-card table tbody tr:hover {
|
||||
material-card table tbody tr:hover,
|
||||
pagination material-button:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
material-card material-button,
|
||||
material-card table tbody tr {
|
||||
material-card table tbody tr,
|
||||
pagination material-button {
|
||||
transition-duration: .28s;
|
||||
transition-timing-function: cubic-bezier(.4, 0, .2, 1);
|
||||
transition-property: background-color;
|
||||
|
@ -326,7 +338,8 @@ dropdown-item, #menu-control-dropdown p {
|
|||
background-color: #e0e0e0;
|
||||
}
|
||||
|
||||
material-popup material-button {
|
||||
material-popup material-button,
|
||||
pagination material-button {
|
||||
background-color: #fff;
|
||||
color: #000;
|
||||
}
|
||||
|
@ -445,7 +458,8 @@ tag-history-button button {
|
|||
border: none;
|
||||
}
|
||||
|
||||
material-card material-button {
|
||||
material-card material-button,
|
||||
pagination material-button {
|
||||
max-height: 30px;
|
||||
max-width: 30px;
|
||||
}
|
||||
|
@ -454,7 +468,8 @@ material-button:hover material-waves {
|
|||
background: none;
|
||||
}
|
||||
|
||||
material-card material-button {
|
||||
material-card material-button,
|
||||
pagination material-button {
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
|
@ -506,4 +521,30 @@ material-checkbox .checkbox {
|
|||
|
||||
material-checkbox .checkbox.checked {
|
||||
background-color: #777;
|
||||
}
|
||||
|
||||
pagination material-button {
|
||||
padding: 0.2em 0.75em;
|
||||
}
|
||||
|
||||
pagination material-button .content {
|
||||
display: flex;
|
||||
align-content: center;
|
||||
line-height: 1.9em;
|
||||
}
|
||||
|
||||
pagination material-button.current {
|
||||
border: 1px solid rgba(0, 0, 0, .12);
|
||||
}
|
||||
|
||||
pagination material-button.current.space-left {
|
||||
margin-left: 85px;
|
||||
}
|
||||
|
||||
pagination material-button.current.space-right {
|
||||
margin-right: 85px;
|
||||
}
|
||||
|
||||
pagination material-button .content i.material-icons {
|
||||
color: #000;
|
||||
}
|
|
@ -130,8 +130,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
return this.fillInfo();
|
||||
});
|
||||
this.on('get-date', function() {
|
||||
if (this.date !== undefined) {
|
||||
return this.trigger('date', this.date);
|
||||
if (this.creationDate !== undefined) {
|
||||
return this.trigger('creation-date', this.creationDate);
|
||||
}
|
||||
return this.fillInfo();
|
||||
});
|
||||
|
@ -225,6 +225,30 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
route('taglist/' + image);
|
||||
};
|
||||
|
||||
registryUI.getPageQueryParam = function() {
|
||||
var qs = route.query();
|
||||
try {
|
||||
return qs.page !== undefined ? parseInt(qs.page.replace(/#.*/, '')) : 1;
|
||||
} catch(e) { return 1; }
|
||||
}
|
||||
|
||||
registryUI.getQueryParams = function(update) {
|
||||
var qs = route.query();
|
||||
update = update || {};
|
||||
for (var key in qs) {
|
||||
if (qs[key] !== undefined) {
|
||||
qs[key] = qs[key].replace(/#!.*/, '');
|
||||
} else {
|
||||
delete qs[key];
|
||||
}
|
||||
}
|
||||
for (var key in update) {
|
||||
if (update[key] !== undefined) {
|
||||
qs[key] = update[key];
|
||||
}
|
||||
}
|
||||
return qs;
|
||||
}
|
||||
route.start(true);
|
||||
</script>
|
||||
</app>
|
|
@ -16,17 +16,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
-->
|
||||
<catalog>
|
||||
<!-- Begin of tag -->
|
||||
<material-card ref="catalog-tag" class="catalog">
|
||||
<material-card ref="catalog-tag" class="catalog header">
|
||||
<div class="material-card-title-action">
|
||||
<h2>
|
||||
Repositories of { registryUI.name() }
|
||||
<div class="item-count">{ registryUI.catalog.length } images</div>
|
||||
</h2>
|
||||
</div>
|
||||
<div hide="{ registryUI.catalog.loadend }" class="spinner-wrapper">
|
||||
<material-spinner></material-spinner>
|
||||
</div>
|
||||
</material-card>
|
||||
<div hide="{ registryUI.catalog.loadend }" class="spinner-wrapper">
|
||||
<material-spinner></material-spinner>
|
||||
</div>
|
||||
<catalog-element each="{ item in registryUI.catalog.repositories }" />
|
||||
<script>
|
||||
registryUI.catalog.instance = this;
|
||||
|
|
|
@ -24,5 +24,7 @@
|
|||
self.localDate = date.toLocaleString()
|
||||
self.update();
|
||||
});
|
||||
|
||||
opts.image.trigger('get-date');
|
||||
</script>
|
||||
</image-date>
|
39
src/tags/pagination.tag
Normal file
39
src/tags/pagination.tag
Normal file
|
@ -0,0 +1,39 @@
|
|||
<!--
|
||||
Copyright (C) 2016-2019 Jones Magloire @Joxit
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<pagination>
|
||||
<!-- Begin of tag -->
|
||||
<div class="conatianer">
|
||||
<div class="pagination-centered">
|
||||
<material-button waves-color="rgba(158,158,158,.4)" each="{p in this.opts.pages}" class="{ current: p.current, space-left: p['space-left'], space-right: p['space-right']}">
|
||||
<i show="{ p.icon }" class="material-icons">{ p.icon }</i>
|
||||
<div hide="{ p.icon }">{ p.page }</div>
|
||||
</material-button>
|
||||
</div>
|
||||
<div>
|
||||
<script>
|
||||
this.on('updated', function() {
|
||||
if (!this.tags['material-button']) { return; }
|
||||
var buttons = Array.isArray(this.tags['material-button']) ? this.tags['material-button'] : [this.tags['material-button']];
|
||||
buttons.forEach(function(button) {
|
||||
button.root.onclick = function() {
|
||||
registryUI.taglist.instance.trigger('page-update', button.p.page)
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<!-- End of tag -->
|
||||
</pagination>
|
|
@ -15,63 +15,71 @@ You should have received a copy of the GNU Affero General Public License
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<remove-image>
|
||||
<material-button waves-center="true" rounded="true" waves-color="#ddd" title="This will delete the image." hide="{ opts.multiDelete }">
|
||||
<material-button waves-center="true" rounded="true" waves-color="#ddd" title="This will delete the image." if="{ !opts.multiDelete }">
|
||||
<i class="material-icons">delete</i>
|
||||
</material-button>
|
||||
<material-checkbox show="{ opts.multiDelete }" title="Select this tag to delete it."></material-checkbox>
|
||||
<material-checkbox if="{ opts.multiDelete }" title="Select this tag to delete it."></material-checkbox>
|
||||
<script type="text/javascript">
|
||||
const self = this;
|
||||
|
||||
this.on('update', function() {
|
||||
if (!this.opts.multiDelete && this.tags['material-checkbox'].checked) {
|
||||
this.tags['material-checkbox'].toggle();
|
||||
}
|
||||
this.on('updated', function() {
|
||||
});
|
||||
|
||||
this.on('mount', function() {
|
||||
this.delete = this.tags['material-button'].root.onclick = function(ignoreError) {
|
||||
const name = self.opts.image.name;
|
||||
const tag = self.opts.image.tag;
|
||||
const oReq = new Http();
|
||||
oReq.addEventListener('loadend', function() {
|
||||
registryUI.taglist.go(name);
|
||||
if (this.status == 200) {
|
||||
if (!this.hasHeader('Docker-Content-Digest')) {
|
||||
registryUI.errorSnackbar('You need to add Access-Control-Expose-Headers: [\'Docker-Content-Digest\'] in your server configuration.');
|
||||
return;
|
||||
}
|
||||
const digest = this.getResponseHeader('Docker-Content-Digest');
|
||||
const oReq = new Http();
|
||||
oReq.addEventListener('loadend', function() {
|
||||
if (this.status == 200 || this.status == 202) {
|
||||
registryUI.taglist.display()
|
||||
registryUI.snackbar('Deleting ' + name + ':' + tag + ' image. Run `registry garbage-collect config.yml` on your registry');
|
||||
} else if (this.status == 404) {
|
||||
ignoreError || registryUI.errorSnackbar('Digest not found');
|
||||
} else {
|
||||
registryUI.snackbar(this.responseText);
|
||||
this.on('updated', function() {
|
||||
if (self.multiDelete == self.opts.multiDelete) {
|
||||
return;
|
||||
}
|
||||
if (this.tags['material-button']) {
|
||||
this.delete = this.tags['material-button'].root.onclick = function(ignoreError) {
|
||||
const name = self.opts.image.name;
|
||||
const tag = self.opts.image.tag;
|
||||
const oReq = new Http();
|
||||
oReq.addEventListener('loadend', function() {
|
||||
registryUI.taglist.go(name);
|
||||
if (this.status == 200) {
|
||||
if (!this.hasHeader('Docker-Content-Digest')) {
|
||||
registryUI.errorSnackbar('You need to add Access-Control-Expose-Headers: [\'Docker-Content-Digest\'] in your server configuration.');
|
||||
return;
|
||||
}
|
||||
});
|
||||
oReq.open('DELETE', registryUI.url() + '/v2/' + name + '/manifests/' + digest);
|
||||
oReq.setRequestHeader('Accept', 'application/vnd.docker.distribution.manifest.v2+json');
|
||||
oReq.addEventListener('error', function() {
|
||||
registryUI.errorSnackbar('An error occurred when deleting image. Check if your server accept DELETE methods Access-Control-Allow-Methods: [\'DELETE\'].');
|
||||
});
|
||||
oReq.send();
|
||||
} else if (this.status == 404) {
|
||||
registryUI.errorSnackbar('Manifest for ' + name + ':' + tag + ' not found');
|
||||
} else {
|
||||
registryUI.snackbar(this.responseText);
|
||||
}
|
||||
});
|
||||
oReq.open('HEAD', registryUI.url() + '/v2/' + name + '/manifests/' + tag);
|
||||
oReq.setRequestHeader('Accept', 'application/vnd.docker.distribution.manifest.v2+json');
|
||||
oReq.send();
|
||||
};
|
||||
const digest = this.getResponseHeader('Docker-Content-Digest');
|
||||
const oReq = new Http();
|
||||
oReq.addEventListener('loadend', function() {
|
||||
if (this.status == 200 || this.status == 202) {
|
||||
registryUI.taglist.display()
|
||||
registryUI.snackbar('Deleting ' + name + ':' + tag + ' image. Run `registry garbage-collect config.yml` on your registry');
|
||||
} else if (this.status == 404) {
|
||||
ignoreError || registryUI.errorSnackbar('Digest not found');
|
||||
} else {
|
||||
registryUI.snackbar(this.responseText);
|
||||
}
|
||||
});
|
||||
oReq.open('DELETE', registryUI.url() + '/v2/' + name + '/manifests/' + digest);
|
||||
oReq.setRequestHeader('Accept', 'application/vnd.docker.distribution.manifest.v2+json');
|
||||
oReq.addEventListener('error', function() {
|
||||
registryUI.errorSnackbar('An error occurred when deleting image. Check if your server accept DELETE methods Access-Control-Allow-Methods: [\'DELETE\'].');
|
||||
});
|
||||
oReq.send();
|
||||
} else if (this.status == 404) {
|
||||
registryUI.errorSnackbar('Manifest for ' + name + ':' + tag + ' not found');
|
||||
} else {
|
||||
registryUI.snackbar(this.responseText);
|
||||
}
|
||||
});
|
||||
oReq.open('HEAD', registryUI.url() + '/v2/' + name + '/manifests/' + tag);
|
||||
oReq.setRequestHeader('Accept', 'application/vnd.docker.distribution.manifest.v2+json');
|
||||
oReq.send();
|
||||
};
|
||||
}
|
||||
|
||||
this.tags['material-checkbox'].on('toggle', function() {
|
||||
registryUI.taglist.instance.trigger('toggle-remove-image', this.checked);
|
||||
});
|
||||
if (this.tags['material-checkbox']) {
|
||||
if (!this.opts.multiDelete && this.tags['material-checkbox'].checked) {
|
||||
this.tags['material-checkbox'].toggle();
|
||||
}
|
||||
this.tags['material-checkbox'].on('toggle', function() {
|
||||
registryUI.taglist.instance.trigger('toggle-remove-image', this.checked);
|
||||
});
|
||||
}
|
||||
self.multiDelete = self.opts.multiDelete;
|
||||
});
|
||||
</script>
|
||||
</remove-image>
|
||||
|
|
|
@ -15,7 +15,7 @@ You should have received a copy of the GNU Affero General Public License
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<tag-history>
|
||||
<material-card ref="tag-history-tag" class="tag-history">
|
||||
<material-card ref="tag-history-tag" class="tag-history header">
|
||||
<div class="material-card-title-action">
|
||||
<material-button waves-center="true" rounded="true" waves-color="#ddd">
|
||||
<i class="material-icons">arrow_back</i>
|
||||
|
|
|
@ -16,8 +16,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
-->
|
||||
<taglist>
|
||||
<!-- Begin of tag -->
|
||||
<material-card ref="taglist-tag" class="taglist" multi-delete={ this.multiDelete }>
|
||||
<div class="material-card-title-action">
|
||||
<material-card class="header">
|
||||
<div class="material-card-title-action ">
|
||||
<material-button waves-center="true" rounded="true" waves-color="#ddd" onclick="registryUI.home();">
|
||||
<i class="material-icons">arrow_back</i>
|
||||
</material-button>
|
||||
|
@ -26,9 +26,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
<div class="item-count">{ registryUI.taglist.tags.length } tags</div>
|
||||
</h2>
|
||||
</div>
|
||||
<div hide="{ registryUI.taglist.loadend }" class="spinner-wrapper">
|
||||
<material-spinner></material-spinner>
|
||||
</div>
|
||||
</material-card>
|
||||
<div hide="{ registryUI.taglist.loadend }" class="spinner-wrapper">
|
||||
<material-spinner></material-spinner>
|
||||
</div>
|
||||
<pagination pages="{ registryUI.getPageLabels(this.page, registryUI.getNumPages(registryUI.taglist.tags)) }"></pagination>
|
||||
<material-card ref="taglist-tag" class="taglist"
|
||||
multi-delete={ this.multiDelete }
|
||||
tags={ registryUI.getPage(registryUI.taglist.tags, this.page) }
|
||||
show="{ registryUI.taglist.loadend }">
|
||||
<table show="{ registryUI.taglist.loadend }" style="border: none;">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -42,7 +48,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
onclick="registryUI.taglist.reverse();">Tag
|
||||
</th>
|
||||
<th class="show-tag-history">History</th>
|
||||
<th class={ 'remove-tag': true, delete: this.parent.toDelete > 0 } show="{ registryUI.isImageRemoveActivated }">
|
||||
<th class={ 'remove-tag': true, delete: this.parent.toDelete > 0 } if="{ registryUI.isImageRemoveActivated }">
|
||||
<material-checkbox ref="remove-tag-checkbox" class="indeterminate" show={ this.toDelete === 0} title="Toggle multi-delete. Alt+Click to select all tags."></material-checkbox>
|
||||
<material-button waves-center="true" rounded="true" waves-color="#ddd" title="This will delete selected images." onclick={ registryUI.taglist.bulkDelete } show={ this.toDelete > 0 }>
|
||||
<i class="material-icons">delete</i>
|
||||
|
@ -50,7 +56,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr each="{ image in registryUI.taglist.tags }">
|
||||
<tr each="{ image in this.opts.tags }">
|
||||
<td class="material-card-th-left">{ image.name }</td>
|
||||
<td class="copy-to-clipboard">
|
||||
<copy-to-clipboard image={ image }/>
|
||||
|
@ -67,15 +73,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
<td class="show-tag-history">
|
||||
<tag-history-button image={ image }/>
|
||||
</td>
|
||||
<td show="{ registryUI.isImageRemoveActivated }">
|
||||
<td if="{ registryUI.isImageRemoveActivated }">
|
||||
<remove-image multi-delete={ this.opts.multiDelete } image={ image }/>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</material-card>
|
||||
<pagination pages="{ registryUI.getPageLabels(this.page, registryUI.getNumPages(registryUI.taglist.tags)) }"></pagination>
|
||||
<script>
|
||||
var self = registryUI.taglist.instance = this;
|
||||
self.page = registryUI.getPageQueryParam();
|
||||
|
||||
this.multiDelete = false;
|
||||
this.toDelete = 0;
|
||||
|
@ -105,6 +113,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
}
|
||||
});
|
||||
|
||||
this.on('page-update', function(page) {
|
||||
self.page = page < 1 ? 1 : page;
|
||||
registryUI.updateQueryString(registryUI.getQueryParams({ page: self.page }) );
|
||||
this.toDelete = 0;
|
||||
this.update();
|
||||
});
|
||||
|
||||
this._getRemoveImageTags = function() {
|
||||
var images = self.refs['taglist-tag'].tags['remove-image'];
|
||||
if (!(images instanceof Array)) {
|
||||
|
@ -124,8 +139,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
};
|
||||
|
||||
this.on('mount', function() {
|
||||
var toggle = this.tags['material-card'].refs['remove-tag-checkbox'].toggle;
|
||||
this.tags['material-card'].refs['remove-tag-checkbox'].toggle = function(e) {
|
||||
var toggle = this.refs['taglist-tag'].refs['remove-tag-checkbox'].toggle;
|
||||
this.refs['taglist-tag'].refs['remove-tag-checkbox'].toggle = function(e) {
|
||||
if (e.altKey) {
|
||||
self._getRemoveImageTags()
|
||||
.filter(function(img) { return !img.tags['material-checkbox'].checked; })
|
||||
|
@ -135,7 +150,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
}
|
||||
};
|
||||
|
||||
this.tags['material-card'].refs['remove-tag-checkbox'].on('toggle', function() {
|
||||
this.refs['taglist-tag'].refs['remove-tag-checkbox'].on('toggle', function() {
|
||||
registryUI.taglist.instance.multiDelete = this.checked;
|
||||
registryUI.taglist.instance.update();
|
||||
});
|
||||
|
@ -153,6 +168,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
registryUI.taglist.tags = registryUI.taglist.tags.map(function(tag) {
|
||||
return new registryUI.DockerImage(registryUI.taglist.name, tag);
|
||||
}).sort(registryUI.DockerImage.compare);
|
||||
self.trigger('page-update', Math.min(self.page, registryUI.getNumPages(registryUI.taglist.tags)))
|
||||
} else if (this.status == 404) {
|
||||
registryUI.snackbar('Server not found', true);
|
||||
} else {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue