docker-registry-ui/src/components/tag-list/tag-list.riot

182 lines
5.9 KiB
Plaintext

<!--
Copyright (C) 2016-2023 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/>.
-->
<tag-list>
<material-card class="header">
<div class="material-card-title-action">
<material-button
text-color="var(--neutral-text)"
color="inherit"
waves-color="var(--hover-background)"
waves-center="true"
href="{ router.home() }"
icon
>
<i class="material-icons">arrow_back</i>
</material-button>
<h2>
Tags of { props.image }
<div class="source-hint">Sourced from { state.registryName + '/' + props.image }</div>
<div class="item-count">{ state.tags.length } tags</div>
</h2>
</div>
</material-card>
<div if="{ !state.loadend }" class="spinner-wrapper">
<material-spinner></material-spinner>
</div>
<pagination pages="{ getPageLabels(state.page, getNumPages(state.tags)) }" onPageUpdate="{onPageUpdate}"></pagination>
<tag-table
if="{ state.loadend }"
tags="{state.tags}"
asc="{state.asc}"
page="{ state.page }"
show-content-digest="{props.showContentDigest}"
is-image-remove-activated="{props.isImageRemoveActivated}"
onReverseOrder="{ onReverseOrder }"
registry-url="{ props.registryUrl }"
pull-url="{ props.pullUrl }"
on-notify="{ props.onNotify }"
filter-results="{ props.filterResults }"
on-authentication="{ props.onAuthentication }"
>
</tag-table>
<pagination pages="{ getPageLabels(state.page, getNumPages(state.tags)) }" onPageUpdate="{onPageUpdate}"></pagination>
<script>
import { Http } from '../../scripts/http';
import { DockerImage, compare } from '../../scripts/docker-image';
import { getNumPages, getPageLabels } from '../../scripts/utils';
import Pagination from './pagination.riot';
import TagTable from './tag-table.riot';
import router from '../../scripts/router';
export default {
components: {
Pagination,
TagTable,
},
onBeforeMount(props) {
this.state = {
registryName: props.registryName,
tags: [],
loadend: false,
asc: true,
page: router.getPageQueryParam() || 1,
};
},
onMounted(props, state) {
this.display(props, state);
window.addEventListener('resize', this.onResize);
// this may be run before the final document size is available, so schedule
// a correction once everything is set up.
window.requestAnimationFrame(this.onResize);
},
display(props, state) {
state.tags = [];
const self = this;
const oReq = new Http({
onAuthentication: props.onAuthentication,
});
oReq.addEventListener('load', function () {
if (this.status === 200) {
const tags = (JSON.parse(this.responseText).tags || [])
.map(
(tag) =>
new DockerImage(props.image, tag, {
list: true,
registryUrl: props.registryUrl,
onNotify: props.onNotify,
onAuthentication: props.onAuthentication,
useControlCacheHeader: props.useControlCacheHeader,
})
)
.sort(compare);
window.requestAnimationFrame(self.onResize);
self.update({
page: Math.min(state.page, getNumPages(tags)),
tags,
});
} else if (this.status === 404) {
self.props.onNotify('Server not found', true);
} else {
self.props.onNotify(this.responseText, true);
}
});
oReq.addEventListener('error', function () {
self.props.onNotify(this.getErrorMessage(), true);
state.tags = [];
});
oReq.addEventListener('loadend', function () {
self.update({
loadend: true,
});
});
oReq.open('GET', props.registryUrl + '/v2/' + props.image + '/tags/list');
oReq.send();
state.asc = true;
},
onPageUpdate(idx) {
const labels = getPageLabels(this.state.page, getNumPages(this.state.tags));
const page = labels[idx].page;
this.update({
page: page,
});
router.updatePageQueryParam(page);
},
onResize() {
// window.innerWidth is a blocking access, cache its result.
const innerWidth = window.innerWidth;
let chars = 0;
const max = this.state.tags.reduce(function (acc, e) {
return e.tag.length > acc ? e.tag.length : acc;
}, 0);
if (innerWidth >= 1440) {
chars = 71;
} else if (innerWidth < 1024) {
chars = 0;
} else {
// SHA256:12345678 + scaled between 1024 and 1440px
chars = 15 + 56 * ((innerWidth - 1024) / 416);
}
if (max > 20) chars -= max - 20;
chars = Math.floor(chars);
this.state.tags.map(function (image) {
image.trigger('content-digest-chars', chars);
});
},
onReverseOrder() {
if (this.state.asc) {
this.state.tags.reverse();
this.state.asc = false;
} else {
this.state.tags.sort(compare);
this.state.asc = true;
}
this.update();
},
getPageLabels,
getNumPages,
router,
};
</script>
</tag-list>