Skip to content

Commit 901baff

Browse files
committed
feat(catalog): show number of tags per image
1 parent 05cbb51 commit 901baff

File tree

10 files changed

+84
-39
lines changed

10 files changed

+84
-39
lines changed

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ WORKDIR /usr/share/nginx/html/
2020

2121
ENV NGINX_PROXY_HEADER_Host '$http_host'
2222
ENV NGINX_LISTEN_PORT '80'
23+
ENV SHOW_CATALOG_NB_TAGS 'false'
2324

2425
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
2526
COPY bin/entrypoint /docker-entrypoint.d/90-docker-registry-ui.sh

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ Some env options are available for use this interface for **only one server**.
9999
- `NGINX_LISTEN_PORT`: Listen on a port other than 80. (default: `80` when the user is root, `8080` otherwise).
100100
- `DEFAULT_REGISTRIES`: List of comma separated registry URLs (e.g `http://registry.example.com,http://registry:5000`), available only when `SINGLE_REGISTRY=false`. (default: ` `).
101101
- `READ_ONLY_REGISTRIES`: Desactivate dialog for remove and add new registries, available only when `SINGLE_REGISTRY=false`. (default: `false`).
102+
- `SHOW_CATALOG_NB_TAGS`: Show number of tags per images on catalog page. This will produce + nb images requests, not recommended on large registries. (default: `false`).
102103

103104
There are some examples with [docker-compose](https://docs.docker.com/compose/) and docker-registry-ui as proxy [here](https://github.com/Joxit/docker-registry-ui/tree/main/examples/ui-as-proxy/) or docker-registry-ui as standalone [here](https://github.com/Joxit/docker-registry-ui/tree/main/examples/ui-as-standalone/).
104105

arm32v7.dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ WORKDIR /usr/share/nginx/html/
2020

2121
ENV NGINX_PROXY_HEADER_Host '$http_host'
2222
ENV NGINX_LISTEN_PORT '80'
23+
ENV SHOW_CATALOG_NB_TAGS 'false'
2324

2425
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
2526
COPY bin/entrypoint /docker-entrypoint.d/90-docker-registry-ui.sh

arm64v8.dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ WORKDIR /usr/share/nginx/html/
2020

2121
ENV NGINX_PROXY_HEADER_Host '$http_host'
2222
ENV NGINX_LISTEN_PORT '80'
23+
ENV SHOW_CATALOG_NB_TAGS 'false'
2324

2425
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
2526
COPY bin/entrypoint /docker-entrypoint.d/90-docker-registry-ui.sh

bin/entrypoint

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ sed -i "s~\${CATALOG_ELEMENTS_LIMIT}~${CATALOG_ELEMENTS_LIMIT}~" index.html
88
sed -i "s~\${SHOW_CONTENT_DIGEST}~${SHOW_CONTENT_DIGEST}~" index.html
99
sed -i "s~\${DEFAULT_REGISTRIES}~${DEFAULT_REGISTRIES}~" index.html
1010
sed -i "s~\${READ_ONLY_REGISTRIES}~${READ_ONLY_REGISTRIES}~" index.html
11+
sed -i "s~\${SHOW_CATALOG_NB_TAGS}~${SHOW_CATALOG_NB_TAGS}~" index.html
1112

1213
if [ -z "${DELETE_IMAGES}" ] || [ "${DELETE_IMAGES}" = false ] ; then
1314
sed -i "s/\${DELETE_IMAGES}/false/" index.html

debian.dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ WORKDIR /usr/share/nginx/html/
2020

2121
ENV NGINX_PROXY_HEADER_Host '$http_host'
2222
ENV NGINX_LISTEN_PORT '80'
23+
ENV SHOW_CATALOG_NB_TAGS 'false'
2324

2425
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
2526
COPY bin/entrypoint /docker-entrypoint.d/90-docker-registry-ui.sh

src/components/catalog/catalog-element.riot

Lines changed: 51 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -16,29 +16,41 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
1616
-->
1717
<catalog-element>
1818
<!-- Begin of tag -->
19-
<div class="content"
20-
if="{!props.filterResults || state.nImages > 0 || matchSearch(props.filterResults, state.image)}">
19+
<div
20+
class="content"
21+
if="{!props.filterResults || state.nImages > 0 || matchSearch(props.filterResults, state.image)}"
22+
>
2123
<material-card class="list highlight" expanded="{state.expanded}" onclick="{ onClick }">
22-
<material-waves onmousedown="{this.triggerLaunch}" center="true" color="#ddd"
23-
setLaunchListener="{ setLaunchListener }" />
24+
<material-waves center="true" color="#ddd"></material-waves>
2425
<span>
2526
<i class="material-icons">send</i>
2627
{ state.image || state.repo }
2728
<div if="{state.images}" class="item-count right">
2829
{ state.nImages } images
2930
<i class="material-icons animated {state.expanded ? 'expanded' : ''}">expand_more</i>
3031
</div>
32+
<div if="{props.showCatalogNbTags && state.image}" class="item-count right">
33+
{ state.nbTags } tags
34+
<i class="material-icons animated"></i>
35+
</div>
3136
</span>
3237
</material-card>
33-
<catalog-element if="{ state.images }" filter-results="{ props.filterResults }"
38+
<catalog-element
39+
if="{ state.images }"
40+
filter-results="{ props.filterResults }"
41+
registry-url="{ props.registryUrl }"
42+
on-notify="{ props.onnNotify }"
43+
on-authentication="{ props.onAuthentication }"
44+
show-catalog-nb-tags="{ props.showCatalogNbTags }"
3445
class="animated {!state.expanded && !props.filterResults ? 'hide' : ''} {state.expanding ? 'expanding' : ''}"
35-
each="{item in state.images}" item="{ item }" />
46+
each="{item in state.images}"
47+
item="{ item }"
48+
></catalog-element>
3649
</div>
3750
<script>
3851
import router from '../../scripts/router';
39-
import {
40-
matchSearch
41-
} from '../search-bar.riot';
52+
import { Http } from '../../scripts/http';
53+
import { matchSearch } from '../search-bar.riot';
4254
4355
export default {
4456
onBeforeMount(props, state) {
@@ -51,10 +63,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
5163
state.repo = props.item.repo;
5264
state.nImages = props.item.images.length;
5365
}
66+
if (props.showCatalogNbTags && state.image) {
67+
this.getNbTags(props, state);
68+
}
5469
},
5570
onBeforeUpdate(props, state) {
5671
if (props.filterResults && state.images) {
57-
state.nImages = state.images.filter(image => matchSearch(props.filterResults, image)).length;
72+
state.nImages = state.images.filter((image) => matchSearch(props.filterResults, image)).length;
5873
} else {
5974
state.nImages = state.images && state.images.length;
6075
}
@@ -66,20 +81,38 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
6681
} else {
6782
this.update({
6883
expanded: !this.state.expanded,
69-
expanding: true
84+
expanding: true,
7085
});
7186
setTimeout(() => {
7287
this.update({
73-
expanding: false
88+
expanding: false,
7489
});
75-
}, 50)
90+
}, 50);
7691
}
7792
},
78-
setLaunchListener(cb) {
79-
this.triggerLaunch = cb;
93+
getNbTags(props, state) {
94+
const self = this;
95+
const oReq = new Http({
96+
onAuthentication: props.onAuthentication,
97+
});
98+
oReq.addEventListener('load', function () {
99+
if (this.status == 200) {
100+
const nbTags = (JSON.parse(this.responseText).tags || []).length;
101+
self.update({ nbTags });
102+
} else if (this.status == 404) {
103+
props.onNotify('Server not found', true);
104+
} else {
105+
props.onNotify(this.responseText, true);
106+
}
107+
});
108+
oReq.addEventListener('error', function () {
109+
props.onNotify(this.getErrorMessage(), true);
110+
});
111+
oReq.open('GET', props.registryUrl + '/v2/' + state.image + '/tags/list');
112+
oReq.send();
80113
},
81-
matchSearch
82-
}
114+
matchSearch,
115+
};
83116
</script>
84117
<!-- End of tag -->
85-
</catalog-element>
118+
</catalog-element>

src/components/catalog/catalog.riot

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -26,34 +26,38 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
2626
<div if="{ !state.loadend }" class="spinner-wrapper">
2727
<material-spinner></material-spinner>
2828
</div>
29-
<catalog-element each="{ item in state.repositories }" item="{ item }" filter-results="{ props.filterResults }" />
29+
<catalog-element
30+
each="{ item in state.repositories }"
31+
item="{ item }"
32+
filter-results="{ props.filterResults }"
33+
registry-url="{ props.registryUrl }"
34+
on-notify="{ props.onNotify }"
35+
on-authentication="{ props.onAuthentication }"
36+
show-catalog-nb-tags="{ props.showCatalogNbTags }"
37+
></catalog-element>
3038
<script>
31-
import CatalogElement from './catalog-element.riot'
32-
import {
33-
Http
34-
} from '../../scripts/http';
35-
import {
36-
getRegistryServers
37-
} from '../../scripts/utils';
39+
import CatalogElement from './catalog-element.riot';
40+
import { Http } from '../../scripts/http';
41+
import { getRegistryServers } from '../../scripts/utils';
3842
3943
export default {
4044
components: {
41-
CatalogElement
45+
CatalogElement,
4246
},
4347
state: {
4448
registryName: '',
4549
length: 0,
4650
loadend: false,
4751
repositories: [],
48-
registryUrl: ''
52+
registryUrl: '',
4953
},
5054
5155
onBeforeMount(props) {
5256
this.state.registryName = props.registryName;
5357
this.state.catalogElementsLimit = props.catalogElementsLimit;
5458
},
5559
onMounted(props, state) {
56-
this.display(props, state)
60+
this.display(props, state);
5761
},
5862
onUpdated(props, state) {
5963
this.display(props, state);
@@ -66,7 +70,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
6670
let repositories = [];
6771
const self = this;
6872
const oReq = new Http({
69-
onAuthentication: this.props.onAuthentication
73+
onAuthentication: this.props.onAuthentication,
7074
});
7175
oReq.addEventListener('load', function () {
7276
if (this.status == 200) {
@@ -79,7 +83,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
7983
if (acc.length == 0 || acc[acc.length - 1].repo != repoName) {
8084
acc.push({
8185
repo: repoName,
82-
images: []
86+
images: [],
8387
});
8488
}
8589
acc[acc.length - 1].images.push(e);
@@ -101,13 +105,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
101105
self.update({
102106
repositories,
103107
nRepositories: repositories.length,
104-
nImages: repositories.reduce((acc, e) => acc + (e.images && e.images.length || 1), 0),
105-
loadend: true
108+
nImages: repositories.reduce((acc, e) => acc + ((e.images && e.images.length) || 1), 0),
109+
loadend: true,
106110
});
107111
});
108112
oReq.open('GET', `${props.registryUrl}/v2/_catalog?n=${state.catalogElementsLimit}`);
109113
oReq.send();
110-
}
111-
}
114+
},
115+
};
112116
</script>
113-
</catalog>
117+
</catalog>

src/components/docker-registry-ui.riot

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
2929
<route path="{baseRoute}">
3030
<catalog registry-url="{ state.registryUrl }" registry-name="{ state.name }"
3131
catalog-elements-limit="{ state.catalogElementsLimit }" on-notify="{ notifySnackbar }"
32-
filter-results="{ state.filter }" on-authentication="{ onAuthentication }" />
32+
filter-results="{ state.filter }" on-authentication="{ onAuthentication }"
33+
show-catalog-nb-tags="{ truthy(props.showCatalogNbTags) }"/>
3334
</route>
3435
<route path="{baseRoute}taglist/(.*)">
3536
<tag-list registry-url="{ state.registryUrl }" registry-name="{ state.name }" pull-url="{ state.pullUrl }"

src/index.html

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,13 @@
3838
<docker-registry-ui registry-url="${REGISTRY_URL}" name="${REGISTRY_TITLE}" pull-url="${PULL_URL}"
3939
show-content-digest="${SHOW_CONTENT_DIGEST}" is-image-remove-activated="${DELETE_IMAGES}"
4040
catalog-elements-limit="${CATALOG_ELEMENTS_LIMIT}" single-registry="${SINGLE_REGISTRY}"
41-
default-registries="${DEFAULT_REGISTRIES}" read-only-registries="${READ_ONLY_REGISTRIES}">
41+
default-registries="${DEFAULT_REGISTRIES}" read-only-registries="${READ_ONLY_REGISTRIES}"
42+
show-catalog-nb-tags="${SHOW_CATALOG_NB_TAGS}">
4243
</docker-registry-ui>
4344
<!-- endbuild -->
4445
<!-- build:keep developement -->
4546
<docker-registry-ui registry-url="" name="Developement Registry" pull-url="" show-content-digest="true"
46-
is-image-remove-activated="true" catalog-elements-limit="1000" single-registry="false">
47+
is-image-remove-activated="true" catalog-elements-limit="1000" single-registry="false" show-catalog-nb-tags="true">
4748
</docker-registry-ui>
4849
<!-- endbuild -->
4950
<!-- build:js docker-registry-ui.js -->

0 commit comments

Comments
 (0)