mirror of
https://github.com/Joxit/docker-registry-ui.git
synced 2025-05-02 18:09:56 +03:00
feat: allow sorting of tags by creation date and size (#125)
closes #125
This commit is contained in:
parent
3bfe107e3c
commit
e990c39a18
5 changed files with 107 additions and 43 deletions
|
@ -16,7 +16,7 @@
|
|||
-->
|
||||
<copy-to-clipboard>
|
||||
<div class="copy-to-clipboard">
|
||||
<input style="display: none; width: 1px; height: 1px;" value="{ state.dockerCmd }">
|
||||
<input style="display: none; width: 1px; height: 1px;" value="{ getDockerCmd(props) }">
|
||||
<material-button waves-center="true" rounded="true" waves-color="#ddd" onClick="{ copy }"
|
||||
title="Copy pull command.">
|
||||
<i class="material-icons">content_copy</i>
|
||||
|
@ -27,33 +27,40 @@
|
|||
ERROR_CAN_NOT_READ_CONTENT_DIGEST
|
||||
} from '../../scripts/utils';
|
||||
export default {
|
||||
onBeforeMount(props, state) {
|
||||
onMounted(props, state) {
|
||||
this.load(props, state);
|
||||
},
|
||||
onUpdated(props, state) {
|
||||
this.load(props, state);
|
||||
},
|
||||
getDockerCmd(props) {
|
||||
if (props.target === 'tag') {
|
||||
state.dockerCmd = `docker pull ${props.pullUrl}/${props.image.name}:${props.image.tag}`;
|
||||
return `docker pull ${props.pullUrl}/${props.image.name}:${props.image.tag}`;
|
||||
} else {
|
||||
return `docker pull ${props.pullUrl}/${props.image.name}@${props.image.digest}`
|
||||
}
|
||||
},
|
||||
onMounted(props, state) {
|
||||
if (props.target !== 'tag') {
|
||||
load(props, state) {
|
||||
if (props.target !== 'tag' && !props.image.digest) {
|
||||
props.image.one('content-digest', (digest) => {
|
||||
this.update({
|
||||
dockerCmd: `docker pull ${props.pullUrl}/${props.image.name}@${digest}`
|
||||
})
|
||||
this.update()
|
||||
});
|
||||
props.image.trigger('get-content-digest');
|
||||
}
|
||||
},
|
||||
copy() {
|
||||
if (!this.state.dockerCmd) {
|
||||
const copyText = this.$('input');
|
||||
if (!copyText.value) {
|
||||
this.props.onNotify(ERROR_CAN_NOT_READ_CONTENT_DIGEST);
|
||||
return;
|
||||
}
|
||||
const copyText = this.$('input');
|
||||
|
||||
copyText.style.display = 'block';
|
||||
copyText.select();
|
||||
document.execCommand('copy');
|
||||
copyText.style.display = 'none';
|
||||
|
||||
this.props.onNotify('`' + this.state.dockerCmd + '` has been copied to clipboard.')
|
||||
this.props.onNotify('`' + copyText.value + '` has been copied to clipboard.')
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -15,11 +15,20 @@ Copyright (C) 2016-2021 Jones Magloire @Joxit
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<image-content-digest>
|
||||
<div title="{ state.title }">{ state.displayId }</div>
|
||||
<div title="{ getTitle(props.image, state.chars) }">{ getDigest(props.image, state.chars) }</div>
|
||||
<script>
|
||||
export default {
|
||||
onMounted(props) {
|
||||
this.chars = -1;
|
||||
onMounted(props, state) {
|
||||
this.load(props, state);
|
||||
},
|
||||
onUpdated(props, state) {
|
||||
this.load(props, state);
|
||||
},
|
||||
load(props, state) {
|
||||
if (props.image.digest) {
|
||||
return;
|
||||
}
|
||||
state.chars = -1;
|
||||
props.image.one('content-digest', (digest) => {
|
||||
this.digest = digest;
|
||||
props.image.on('content-digest-chars', this.onResize);
|
||||
|
@ -28,22 +37,23 @@ Copyright (C) 2016-2021 Jones Magloire @Joxit
|
|||
props.image.trigger('get-content-digest');
|
||||
},
|
||||
onResize(chars) {
|
||||
if (chars === this.chars) {
|
||||
return;
|
||||
}
|
||||
let displayId = this.digest;
|
||||
let title = '';
|
||||
this.chars = chars;
|
||||
if (chars >= 70) {
|
||||
displayId = this.digest;
|
||||
} else if (chars <= 0) {
|
||||
displayId = '';
|
||||
title = this.digest;
|
||||
} else {
|
||||
displayId = this.digest.slice(0, chars) + '...';
|
||||
title = this.digest;
|
||||
}
|
||||
this.update({title, displayId});
|
||||
if (chars !== this.state.chars) {
|
||||
this.update({
|
||||
chars
|
||||
});
|
||||
}
|
||||
},
|
||||
getTitle(image, chars) {
|
||||
return chars >= 70 ? '' : (image.digest || '');
|
||||
},
|
||||
getDigest(image, chars) {
|
||||
if (chars >= 70) {
|
||||
return image.digest || '';
|
||||
} else if (chars <= 0) {
|
||||
return '';
|
||||
} else {
|
||||
return image.digest && image.digest.slice(0, chars) + '...';
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
|
|
@ -15,17 +15,14 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<image-date>
|
||||
<div title="Creation date { state.localDate }">{ dateFormat(state.date) } ago</div>
|
||||
<div title="Creation date { getLocalDate(props.image) }">{ getDate(props.image) } ago</div>
|
||||
<script>
|
||||
import {
|
||||
dateFormat,
|
||||
} from '../../scripts/utils';
|
||||
export default {
|
||||
state: {
|
||||
localDate: 'unknown'
|
||||
},
|
||||
onMounted(props) {
|
||||
props.image.on('creation-date', (date) => {
|
||||
props.image.one('creation-date', (date) => {
|
||||
this.update({
|
||||
date: date,
|
||||
localDate: date.toLocaleString()
|
||||
|
@ -33,7 +30,12 @@
|
|||
});
|
||||
props.image.trigger('get-date');
|
||||
},
|
||||
dateFormat
|
||||
getDate(image) {
|
||||
return dateFormat(image.creationDate)
|
||||
},
|
||||
getLocalDate(image) {
|
||||
return (image.creationDate && image.creationDate.toLocaleString()) || 'unknown'
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</image-date>
|
|
@ -15,21 +15,33 @@
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<image-size>
|
||||
<div title="Compressed size of your image.">{ bytesToSize(state.size) }</div>
|
||||
<div title="Compressed size of your image.">{ getImageSize(props.image) }</div>
|
||||
<script>
|
||||
import {
|
||||
bytesToSize,
|
||||
} from '../../scripts/utils';
|
||||
export default {
|
||||
onMounted(props) {
|
||||
onMounted(props, state) {
|
||||
this.load(props, state);
|
||||
},
|
||||
onUpdated(props, state) {
|
||||
this.load(props, state);
|
||||
},
|
||||
load(props, state) {
|
||||
if (typeof props.image.size === 'number') {
|
||||
return;
|
||||
}
|
||||
props.image.on('size', (size) => {
|
||||
this.update({
|
||||
size
|
||||
});
|
||||
});
|
||||
props.image.trigger('get-size');
|
||||
|
||||
},
|
||||
bytesToSize
|
||||
getImageSize(image) {
|
||||
return bytesToSize(image.size)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</image-size>
|
|
@ -19,13 +19,21 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
<table style="border: none;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="creation-date">Creation date</th>
|
||||
<th class="image-size">Size</th>
|
||||
<th
|
||||
class="creation-date { (state.desc && state.orderType === 'date') ? 'material-card-th-sorted-descending' : 'material-card-th-sorted-ascending' }"
|
||||
onclick="{() => onPageReorder('date') }">
|
||||
Creation date
|
||||
</th>
|
||||
<th
|
||||
class="image-size { (state.desc && state.orderType === 'size') ? 'material-card-th-sorted-descending' : 'material-card-th-sorted-ascending' }"
|
||||
onclick="{() => onPageReorder('size') }">
|
||||
Size
|
||||
</th>
|
||||
<th id="image-content-digest-header" if="{ props.showContentDigest }">Content Digest</th>
|
||||
|
||||
<th id="image-tag-header"
|
||||
class="{ props.asc ? 'material-card-th-sorted-ascending' : 'material-card-th-sorted-descending' }"
|
||||
onclick="{() => props.onReverseOrder() }">Tag
|
||||
onclick="{ onReverseOrder }">Tag
|
||||
</th>
|
||||
<th class="show-tag-history">History</th>
|
||||
<th class="remove-tag { state.toDelete.size > 0 ? 'delete' : '' }" if="{ props.isImageRemoveActivated }">
|
||||
|
@ -138,7 +146,32 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
toDelete: this.state.toDelete
|
||||
})
|
||||
},
|
||||
getPage,
|
||||
onReverseOrder() {
|
||||
this.state.orderType = null;
|
||||
this.state.desc = false;
|
||||
this.props.onReverseOrder();
|
||||
},
|
||||
onPageReorder(type) {
|
||||
this.update({
|
||||
orderType: type,
|
||||
desc: (this.state.orderType && this.state.orderType !== type) || !this.state.desc
|
||||
})
|
||||
},
|
||||
getPage(tags, page) {
|
||||
const sortedTags = getPage(tags, page);
|
||||
if (this.state.orderType === 'date') {
|
||||
sortedTags.sort((e1, e2) =>
|
||||
!this.state.desc ?
|
||||
e2.creationDate.getTime() - e1.creationDate.getTime() :
|
||||
e1.creationDate.getTime() - e2.creationDate.getTime());
|
||||
} else if (this.state.orderType === 'size') {
|
||||
sortedTags.sort((e1, e2) =>
|
||||
!this.state.desc ?
|
||||
e2.size - e1.size :
|
||||
e1.size - e2.size);
|
||||
}
|
||||
return sortedTags;
|
||||
},
|
||||
matchSearch
|
||||
}
|
||||
</script>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue