mirror of
https://github.com/Joxit/docker-registry-ui.git
synced 2026-02-19 21:29:51 +00:00
Compare commits
19 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
476a441715 | ||
|
|
8055baa951 | ||
|
|
53557b2591 | ||
|
|
ea79fd621f | ||
|
|
2f014c1d8f | ||
|
|
e6d9f11b83 | ||
|
|
a36809408c | ||
|
|
7e2e4b6010 | ||
|
|
605e8a8d8e | ||
|
|
ac5a70c9df | ||
|
|
9b120bb6d5 | ||
|
|
7446452b77 | ||
|
|
d361068529 | ||
|
|
b03f00ebe8 | ||
|
|
d0b7e7ddeb | ||
|
|
7366e709a4 | ||
|
|
89e2782751 | ||
|
|
3911310d89 | ||
|
|
d599c1c202 |
@@ -1,4 +1,7 @@
|
||||
*
|
||||
!dist
|
||||
!bin
|
||||
!nginx
|
||||
!nginx
|
||||
!src
|
||||
!package.json
|
||||
!gulpfile.js
|
||||
14
Dockerfile
14
Dockerfile
@@ -12,10 +12,22 @@
|
||||
#
|
||||
# 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/>.
|
||||
FROM node:10-alpine AS builder
|
||||
|
||||
WORKDIR /usr/app
|
||||
|
||||
COPY package.json .
|
||||
|
||||
RUN yarn install
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN yarn build
|
||||
|
||||
FROM nginx:alpine
|
||||
|
||||
LABEL maintainer="Jones MAGLOIRE @Joxit"
|
||||
|
||||
WORKDIR /usr/share/nginx/html/
|
||||
|
||||
COPY dist/ /usr/share/nginx/html/
|
||||
COPY --from=builder /usr/app/dist/ /usr/share/nginx/html/
|
||||
@@ -11,7 +11,7 @@ This web user interface uses [Riot](https://github.com/Riot/riot) the react-like
|
||||
|
||||
## [GitHub Page](https://joxit.github.io/docker-registry-ui) and [Live Demo](https://joxit.github.io/docker-registry-ui/demo/)
|
||||
|
||||

|
||||

|
||||
|
||||
## Features
|
||||
|
||||
@@ -29,6 +29,8 @@ This web user interface uses [Riot](https://github.com/Riot/riot) the react-like
|
||||
- Show sha256 for specific tag (hover image tag)
|
||||
- Display image creation date (see #49)
|
||||
- Display image history (see #58)
|
||||
- Display image/tag count
|
||||
- Image aggregation (see #56)
|
||||
|
||||
## Getting Started
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ sed -i "s,\${URL},${URL}," scripts/docker-registry-ui.js
|
||||
sed -i "s,\${REGISTRY_TITLE},${REGISTRY_TITLE}," scripts/docker-registry-ui.js
|
||||
|
||||
if [ -z "${DELETE_IMAGES}" ] || [ "${DELETE_IMAGES}" = false ] ; then
|
||||
sed -i "s/registryUI.isImageRemoveActivated *= *[^,;]*/registryUI.isImageRemoveActivated=false/" scripts/docker-registry-ui.js
|
||||
sed -i -r "s/(isImageRemoveActivated[:=])[^,;]*/\1false/" scripts/docker-registry-ui.js
|
||||
fi
|
||||
|
||||
if [ -n "${REGISTRY_URL}" ] ; then
|
||||
|
||||
2
dist/index.html
vendored
2
dist/index.html
vendored
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright (C) 2016-2018 Jones Magloire @Joxit
|
||||
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
|
||||
|
||||
4
dist/scripts/docker-registry-ui-static.js
vendored
4
dist/scripts/docker-registry-ui-static.js
vendored
File diff suppressed because one or more lines are too long
4
dist/scripts/docker-registry-ui.js
vendored
4
dist/scripts/docker-registry-ui.js
vendored
File diff suppressed because one or more lines are too long
4
dist/style.css
vendored
4
dist/style.css
vendored
File diff suppressed because one or more lines are too long
BIN
docker-registry-ui.gif
Normal file
BIN
docker-registry-ui.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 764 KiB |
@@ -58,7 +58,7 @@ function appStatic() {
|
||||
.pipe(license('agpl3', {
|
||||
tiny: false,
|
||||
project: 'docker-registry-ui',
|
||||
year: '2016-2018',
|
||||
year: '2016-2019',
|
||||
organization: 'Jones Magloire @Joxit'
|
||||
}))
|
||||
.pipe(injectVersion())
|
||||
@@ -72,7 +72,7 @@ function app() {
|
||||
.pipe(license('agpl3', {
|
||||
tiny: false,
|
||||
project: 'docker-registry-ui',
|
||||
year: '2016-2018',
|
||||
year: '2016-2019',
|
||||
organization: 'Jones Magloire @Joxit'
|
||||
}))
|
||||
.pipe(injectVersion())
|
||||
@@ -94,7 +94,7 @@ function styles() {
|
||||
.pipe(license('agpl3', {
|
||||
tiny: false,
|
||||
project: 'docker-registry-ui',
|
||||
year: '2016-2018',
|
||||
year: '2016-2019',
|
||||
organization: 'Jones Magloire @Joxit'
|
||||
}))
|
||||
.pipe(gulp.dest('dist/'));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "docker-registry-ui",
|
||||
"version": "0.6.0",
|
||||
"version": "1.0.2",
|
||||
"scripts": {
|
||||
"build": "./node_modules/gulp/bin/gulp.js build"
|
||||
},
|
||||
|
||||
BIN
screenshot.png
BIN
screenshot.png
Binary file not shown.
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 36 KiB |
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright (C) 2016-2018 Jones Magloire @Joxit
|
||||
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
|
||||
@@ -39,6 +39,7 @@
|
||||
<!-- endbuild -->
|
||||
<!-- build:js scripts/docker-registry-ui.js -->
|
||||
<script src="tags/catalog.tag" type="riot/tag"></script>
|
||||
<script src="tags/catalog-element.tag" type="riot/tag"></script>
|
||||
<script src="tags/tag-history-button.tag" type="riot/tag"></script>
|
||||
<script src="tags/tag-history.tag" type="riot/tag"></script>
|
||||
<script src="tags/tag-history-element.tag" type="riot/tag"></script>
|
||||
|
||||
@@ -11,7 +11,9 @@
|
||||
url(fonts/MaterialIcons-Regular.ttf) format('truetype');
|
||||
}
|
||||
|
||||
.material-icons {
|
||||
material-button .content i.material-icons,
|
||||
material-button[rounded=true] .content i.material-icons,
|
||||
i.material-icons {
|
||||
font-family: 'Material Icons';
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
@@ -36,4 +38,9 @@
|
||||
|
||||
/* Support for IE. */
|
||||
font-feature-settings: 'liga';
|
||||
}
|
||||
}
|
||||
|
||||
material-button .content i.material-icons,
|
||||
material-button[rounded=true] .content i.material-icons {
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2018 Jones Magloire @Joxit
|
||||
* 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2018 Jones Magloire @Joxit
|
||||
* 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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2018 Jones Magloire @Joxit
|
||||
* 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
|
||||
|
||||
@@ -88,17 +88,23 @@ h2 {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.material-card-title-action h2 .item-count {
|
||||
font-size: 0.7em;
|
||||
margin-left: 1em;
|
||||
}
|
||||
|
||||
.list {
|
||||
display: block;
|
||||
padding: 8px 0;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.list.highlight > li:hover {
|
||||
.list.highlight:hover {
|
||||
background-color: #eee;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.list > span,
|
||||
.list > li {
|
||||
box-sizing: border-box;
|
||||
line-height: 1;
|
||||
@@ -107,6 +113,7 @@ h2 {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.list > span i.material-icons,
|
||||
.list > li i.material-icons {
|
||||
margin-right: 32px;
|
||||
height: 24px;
|
||||
@@ -116,6 +123,28 @@ h2 {
|
||||
color: #757575;
|
||||
}
|
||||
|
||||
.list > span .right i.material-icons.animated {
|
||||
transition: all 350ms cubic-bezier(.4,0,.2,1);
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.list > span .right {
|
||||
position: absolute;
|
||||
align-self: end;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.list > span i.material-icons.animated.expanded {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.list > span .item-count {
|
||||
font-size: 0.75em;
|
||||
}
|
||||
|
||||
.list > span,
|
||||
.list > li > span {
|
||||
height: 100%;
|
||||
text-decoration: none;
|
||||
@@ -128,6 +157,11 @@ h2 {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
material-card.list {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.material-card-title-action {
|
||||
-webkit-align-items: center;
|
||||
-ms-flex-align: center;
|
||||
@@ -170,16 +204,21 @@ material-card table th {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
material-card material-button:hover,
|
||||
material-card table tbody tr:hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
|
||||
material-card material-button,
|
||||
material-card table tbody tr {
|
||||
transition-duration: .28s;
|
||||
transition-timing-function: cubic-bezier(.4, 0, .2, 1);
|
||||
transition-property: background-color;
|
||||
}
|
||||
|
||||
material-card table tbody tr {
|
||||
position: relative;
|
||||
height: 48px;
|
||||
transition-duration: .28s;
|
||||
transition-timing-function: cubic-bezier(.4, 0, .2, 1);
|
||||
transition-property: background-color;
|
||||
}
|
||||
|
||||
material-card table td {
|
||||
@@ -218,6 +257,7 @@ material-card table th.material-card-th-sorted-descending:before {
|
||||
content: "\e5db";
|
||||
}
|
||||
|
||||
material-button .content i.material-icons,
|
||||
.material-icons {
|
||||
color: #777;
|
||||
}
|
||||
@@ -295,6 +335,7 @@ material-popup .popup {
|
||||
footer {
|
||||
width: 100%;
|
||||
position: fixed;
|
||||
z-index: 75;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
@@ -334,10 +375,7 @@ select {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.copy-to-clipboard a:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
catalog material-card,
|
||||
tag-history material-card {
|
||||
min-height: auto;
|
||||
}
|
||||
@@ -377,4 +415,34 @@ tag-history-element.id div.value {
|
||||
tag-history-button button {
|
||||
background: none;
|
||||
border: none;
|
||||
}
|
||||
|
||||
material-card material-button {
|
||||
max-height: 30px;
|
||||
max-width: 30px;
|
||||
}
|
||||
|
||||
material-button:hover material-waves {
|
||||
background: none;
|
||||
}
|
||||
|
||||
material-card material-button {
|
||||
background-color: inherit;
|
||||
}
|
||||
|
||||
catalog-element material-card {
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
catalog-element catalog-element material-card {
|
||||
transition: all 350ms cubic-bezier(.4,0,.2,1);
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
catalog-element catalog-element.showing material-card,
|
||||
catalog-element catalog-element.hide material-card {
|
||||
margin-top: -50px;
|
||||
opacity: 0;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright (C) 2016-2018 Jones Magloire @Joxit
|
||||
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
|
||||
@@ -231,6 +231,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
|
||||
return Math.ceil(bytes / Math.pow(1024, i)) + ' ' + sizes[i];
|
||||
};
|
||||
|
||||
registryUI.taglist.go = function(image) {
|
||||
route('taglist/' + image);
|
||||
};
|
||||
|
||||
route.start(true);
|
||||
</script>
|
||||
</app>
|
||||
59
src/tags/catalog-element.tag
Normal file
59
src/tags/catalog-element.tag
Normal file
@@ -0,0 +1,59 @@
|
||||
<!--
|
||||
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/>.
|
||||
-->
|
||||
<catalog-element>
|
||||
<!-- Begin of tag -->
|
||||
<material-card class="list highlight" item="{item}" expanded="{expanded}">
|
||||
<material-waves onmousedown="{launch}" center="true" color="#ddd" />
|
||||
<span>
|
||||
<i class="material-icons">send</i>
|
||||
{ typeof opts.item === "string" ? opts.item : opts.item.repo }
|
||||
<div hide="{typeof opts.item === "string"}" class="item-count right">
|
||||
{ opts.item.images && opts.item.images.length } images
|
||||
<i class="material-icons animated {expanded: opts.expanded}">expand_more</i>
|
||||
</div>
|
||||
</span>
|
||||
</material-card>
|
||||
<catalog-element hide="{typeof opts.item === "string"}" class="animated {hide: !expanded, expanding: expanding}" each="{item in item.images}" />
|
||||
<script>
|
||||
this.on('mount', function() {
|
||||
const self = this;
|
||||
const card = this.tags['material-card'];
|
||||
if (!card) {
|
||||
return;
|
||||
}
|
||||
// Launch waves
|
||||
card.launch = function(e) {
|
||||
card.tags['material-waves'].trigger('launch',e);
|
||||
}
|
||||
if (this.item.images && this.item.images.length === 1) {
|
||||
this.item = this.item.images[0];
|
||||
}
|
||||
card.root.onclick = function(e) {
|
||||
if (!self.item.repo) {
|
||||
registryUI.taglist.go(self.item);
|
||||
} else {
|
||||
self.expanded = !self.expanded;
|
||||
self.update({expanded: self.expanded, expanding: true});
|
||||
setTimeout(function() {
|
||||
self.update({expanded: self.expanded, expanding: false});
|
||||
}, 50)
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
<!-- End of tag -->
|
||||
</catalog-element>
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright (C) 2016-2018 Jones Magloire @Joxit
|
||||
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
|
||||
@@ -18,21 +18,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
<!-- Begin of tag -->
|
||||
<material-card ref="catalog-tag" class="catalog">
|
||||
<div class="material-card-title-action">
|
||||
<h2>Repositories of { registryUI.name() }</h2>
|
||||
<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>
|
||||
<ul class="list highlight" show="{ registryUI.catalog.loadend }">
|
||||
<li each="{ item in registryUI.catalog.repositories }" onclick="registryUI.catalog.go('{item}');">
|
||||
<span>
|
||||
<i class="material-icons">send</i>
|
||||
{ item }
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</material-card>
|
||||
|
||||
<catalog-element each="{ item in registryUI.catalog.repositories }" />
|
||||
<script>
|
||||
registryUI.catalog.instance = this;
|
||||
registryUI.catalog.display = function() {
|
||||
@@ -43,6 +38,19 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
if (this.status == 200) {
|
||||
registryUI.catalog.repositories = JSON.parse(this.responseText).repositories || [];
|
||||
registryUI.catalog.repositories.sort();
|
||||
registryUI.catalog.length = registryUI.catalog.repositories.length; registryUI.catalog.repositories = registryUI.catalog.repositories.reduce(function(acc, e) {
|
||||
const slash = e.indexOf('/');
|
||||
if (slash > 0) {
|
||||
const repoName = e.substring(0, slash) + '/';
|
||||
if (acc.length == 0 || acc[acc.length - 1].repo != repoName) {
|
||||
acc.push({repo: repoName, images: []});
|
||||
}
|
||||
acc[acc.length - 1].images.push(e);
|
||||
return acc;
|
||||
}
|
||||
acc.push(e);
|
||||
return acc;
|
||||
}, []);
|
||||
} else if (this.status == 404) {
|
||||
registryUI.snackbar('Server not found', true);
|
||||
} else {
|
||||
@@ -60,9 +68,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
oReq.open('GET', registryUI.url() + '/v2/_catalog?n=100000');
|
||||
oReq.send();
|
||||
};
|
||||
registryUI.catalog.go = function(image) {
|
||||
route('taglist/' + image);
|
||||
};
|
||||
registryUI.catalog.display();
|
||||
</script>
|
||||
<!-- End of tag -->
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright (C) 2016-2018 Jones Magloire @Joxit
|
||||
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
|
||||
@@ -16,9 +16,9 @@
|
||||
-->
|
||||
<copy-to-clipboard>
|
||||
<input ref="input" style="display: none; width: 1px; height: 1px;" value="{ this.dockerCmd }">
|
||||
<a onclick="{ this.copy }" title="Copy pull command.">
|
||||
<material-button waves-center="true" rounded="true" waves-color="#ddd" onclick="{ this.copy }" title="Copy pull command.">
|
||||
<i class="material-icons">content_copy</i>
|
||||
</a>
|
||||
</material-button>
|
||||
<script type="text/javascript">
|
||||
this.dockerCmd = 'docker pull ' + registryUI.cleanName() + '/' + opts.image.name + ':' + opts.image.tag;
|
||||
this.copy = function () {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright (C) 2016-2018 Jones Magloire @Joxit
|
||||
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright (C) 2016-2018 Jones Magloire @Joxit
|
||||
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright (C) 2016-2018 Jones Magloire @Joxit
|
||||
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright (C) 2016-2018 Jones Magloire @Joxit
|
||||
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright (C) 2018 Jones Magloire @Joxit
|
||||
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright (C) 2018 Jones Magloire @Joxit
|
||||
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright (C) 2016-2018 Jones Magloire @Joxit
|
||||
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright (C) 2016-2018 Jones Magloire @Joxit
|
||||
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
|
||||
@@ -15,49 +15,51 @@ 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>
|
||||
<a href="#" title="This will delete the image."
|
||||
onclick="registryUI.removeImage.remove('{ opts.image.name }', '{ opts.image.tag }')">
|
||||
<material-button waves-center="true" rounded="true" waves-color="#ddd" title="This will delete the image.">
|
||||
<i class="material-icons">delete</i>
|
||||
</a>
|
||||
</material-button>
|
||||
<script type="text/javascript">
|
||||
registryUI.removeImage = registryUI.removeImage || {};
|
||||
|
||||
registryUI.removeImage.remove = function(name, tag) {
|
||||
const oReq = new Http();
|
||||
oReq.addEventListener('loadend', function() {
|
||||
registryUI.taglist.refresh();
|
||||
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.refresh();
|
||||
registryUI.snackbar('Deleting ' + name + ':' + tag + ' image. Run `registry garbage-collect config.yml` on your registry');
|
||||
} else if (this.status == 404) {
|
||||
registryUI.errorSnackbar('Digest not found');
|
||||
} else {
|
||||
registryUI.snackbar(this.responseText);
|
||||
const self = this;
|
||||
this.on('mount', function() {
|
||||
this.tags['material-button'].root.onclick = function() {
|
||||
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) {
|
||||
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();
|
||||
};
|
||||
});
|
||||
</script>
|
||||
</remove-image>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright (C) 2016-2018 Jones Magloire @Joxit
|
||||
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
|
||||
@@ -15,13 +15,13 @@ 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-button>
|
||||
<button ref="button" title="This will show the history of given tag">
|
||||
<material-button ref="button" title="This will show the history of given tag" waves-center="true" rounded="true" waves-color="#ddd">
|
||||
<i class="material-icons">history</i>
|
||||
</button>
|
||||
</material-button>
|
||||
<script>
|
||||
this.on('mount', function() {
|
||||
const self = this;
|
||||
this.refs.button.onclick = function() {
|
||||
this.refs.button.root.onclick = function() {
|
||||
registryUI.taghistory._image = self.opts.image;
|
||||
registryUI.taghistory.go(self.opts.image.name, self.opts.image.tag);
|
||||
};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright (C) 2016-2018 Jones Magloire @Joxit
|
||||
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
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright (C) 2016-2018 Jones Magloire @Joxit
|
||||
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
|
||||
@@ -17,9 +17,9 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
<tag-history>
|
||||
<material-card ref="tag-history-tag" class="tag-history">
|
||||
<div class="material-card-title-action">
|
||||
<a href="#!taglist/{registryUI.taghistory.image}">
|
||||
<material-button waves-center="true" rounded="true" waves-color="#ddd">
|
||||
<i class="material-icons">arrow_back</i>
|
||||
</a>
|
||||
</material-button>
|
||||
<h2>
|
||||
History of { registryUI.taghistory.image }:{ registryUI.taghistory.tag } <i class="material-icons">history</i>
|
||||
</h2>
|
||||
@@ -118,13 +118,20 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
self.elements = []
|
||||
const blobs = registryUI.taghistory._image && registryUI.taghistory._image.blobs;
|
||||
if (blobs) {
|
||||
return processBlobs(blobs)
|
||||
window.scrollTo(0, 0);
|
||||
return processBlobs(blobs);
|
||||
}
|
||||
const image = new registryUI.DockerImage(registryUI.taghistory.image, registryUI.taghistory.tag);
|
||||
image.fillInfo()
|
||||
image.on('blobs', processBlobs);
|
||||
};
|
||||
|
||||
this.on('mount', function() {
|
||||
self.refs['tag-history-tag'].tags['material-button'].root.onclick = function() {
|
||||
registryUI.taglist.go(registryUI.taghistory.image);
|
||||
};
|
||||
});
|
||||
|
||||
registryUI.taghistory.display();
|
||||
self.update();
|
||||
</script>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--
|
||||
Copyright (C) 2016-2018 Jones Magloire @Joxit
|
||||
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
|
||||
@@ -18,10 +18,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
<!-- Begin of tag -->
|
||||
<material-card ref="taglist-tag" class="taglist">
|
||||
<div class="material-card-title-action">
|
||||
<a href="#!" onclick="registryUI.home();">
|
||||
<material-button waves-center="true" rounded="true" waves-color="#ddd" onclick="registryUI.home();">
|
||||
<i class="material-icons">arrow_back</i>
|
||||
</a>
|
||||
<h2>Tags of { registryUI.name() + '/' + registryUI.taglist.name }</h2>
|
||||
</material-button>
|
||||
<h2>
|
||||
Tags of { registryUI.name() + '/' + registryUI.taglist.name }
|
||||
<div class="item-count">{ registryUI.taglist.tags.length } tags</div>
|
||||
</h2>
|
||||
</div>
|
||||
<div hide="{ registryUI.taglist.loadend }" class="spinner-wrapper">
|
||||
<material-spinner></material-spinner>
|
||||
@@ -113,9 +116,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
}
|
||||
registryUI.taglist.instance.update();
|
||||
};
|
||||
registryUI.taglist.refresh = function() {
|
||||
route(registryUI.taglist.name);
|
||||
};
|
||||
</script>
|
||||
<!-- End of tag -->
|
||||
</taglist>
|
||||
@@ -12,6 +12,18 @@
|
||||
#
|
||||
# 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/>.
|
||||
FROM node:10-alpine AS builder
|
||||
|
||||
WORKDIR /usr/app
|
||||
|
||||
COPY package.json .
|
||||
|
||||
RUN yarn install
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN yarn build
|
||||
|
||||
FROM nginx:alpine
|
||||
|
||||
LABEL maintainer="Jones MAGLOIRE @Joxit"
|
||||
@@ -19,8 +31,8 @@ LABEL maintainer="Jones MAGLOIRE @Joxit"
|
||||
WORKDIR /usr/share/nginx/html/
|
||||
|
||||
COPY nginx/default.conf /etc/nginx/conf.d/default.conf
|
||||
COPY dist/ /usr/share/nginx/html/
|
||||
COPY dist/scripts/docker-registry-ui-static.js /usr/share/nginx/html/scripts/docker-registry-ui.js
|
||||
COPY --from=builder /usr/app/dist/ /usr/share/nginx/html/
|
||||
COPY --from=builder /usr/app/dist/scripts/docker-registry-ui-static.js /usr/share/nginx/html/scripts/docker-registry-ui.js
|
||||
COPY bin/entrypoint /bin
|
||||
|
||||
ENTRYPOINT entrypoint
|
||||
|
||||
Reference in New Issue
Block a user