feat: allow sorting of tags by creation date and size (#125)

closes #125
This commit is contained in:
Joxit 2021-04-13 05:34:28 +02:00
parent 3bfe107e3c
commit e990c39a18
No known key found for this signature in database
GPG key ID: F526592B8E012263
5 changed files with 107 additions and 43 deletions

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>