Merge pull request #23 from Joxit/riot-mui

Move from material-design lite to riot-mui
This commit is contained in:
Jones Magloire 2017-10-17 00:02:31 +02:00 committed by GitHub
commit b9effee691
15 changed files with 480 additions and 258 deletions

View file

@ -7,7 +7,7 @@ There is no default registry on this UI, you should add your own with the UI.
You can manage more than one registry server. You can manage more than one registry server.
All registry will be stored in the [local storage](https://en.wikipedia.org/wiki/Web_storage#Local_and_session_storage) of your browser. All registry will be stored in the [local storage](https://en.wikipedia.org/wiki/Web_storage#Local_and_session_storage) of your browser.
This web user interface use [Riot](https://github.com/Riot/riot) the react-like user interface micro-library and [Material Design Lite](https://github.com/google/material-design-lite) components. This web user interface use [Riot](https://github.com/Riot/riot) the react-like user interface micro-library and [riot-mui](https://github.com/kysonic/riot-mui) components.
## [GitHub Page](https://joxit.github.io/docker-registry-ui) and [Live Demo](https://joxit.github.io/docker-registry-ui/demo/) ## [GitHub Page](https://joxit.github.io/docker-registry-ui) and [Live Demo](https://joxit.github.io/docker-registry-ui/demo/)
@ -20,6 +20,7 @@ This web user interface use [Riot](https://github.com/Riot/riot) the react-like
- Sort the tag list - Sort the tag list
- One interface for many registry - One interface for many registry
- Use a secured docker registry - Use a secured docker registry
- Share your docker registry with query parameter `url` (e.g. `https://joxit.github.io/docker-registry-ui/demo?url=https://registry.example.com`)
## Getting Started ## Getting Started

View file

@ -88,6 +88,12 @@ gulp.task('scripts', ['html'], function() {
.pipe(gulp.dest('dist/scripts')); .pipe(gulp.dest('dist/scripts'));
}); });
gulp.task('vendor', ['html'], function() {
return gulp.src(['node_modules/riot/riot.min.js', 'node_modules/riotgear-router/dist/rg-router.min.js', 'node_modules/riot-mui/build/js/riot-mui-min.js'])
.pipe(concat('vendor.js'))
.pipe(gulp.dest('dist/scripts'));
});
gulp.task('styles', ['html'], function() { gulp.task('styles', ['html'], function() {
return gulp.src(['src/*.css']) return gulp.src(['src/*.css'])
.pipe(concat('style.css')) .pipe(concat('style.css'))
@ -109,7 +115,7 @@ gulp.task('fonts', function() {
.pipe(gulp.dest('dist/fonts')); .pipe(gulp.dest('dist/fonts'));
}); });
gulp.task('sources', ['riot-tag', 'riot-static-tag', 'scripts', 'scripts-static', 'styles'], function() { gulp.task('sources', ['riot-tag', 'riot-static-tag', 'scripts', 'vendor', 'scripts-static', 'styles'], function() {
gulp.start(); gulp.start();
}); });

View file

@ -9,13 +9,11 @@
"url": "https://github.com/Joxit/docker-registry-ui.git" "url": "https://github.com/Joxit/docker-registry-ui.git"
}, },
"author": "Jones Magloire (Joxit)", "author": "Jones Magloire (Joxit)",
"license": "AGPLv3", "license": "AGPL-3.0",
"description": "A web UI for private docker registry", "description": "A web UI for private docker registry",
"dependencies": { "dependencies": {},
},
"devDependencies": { "devDependencies": {
"del": "^3.0.0", "del": "^3.0.0",
"dialog-polyfill": "^0.4",
"gulp": "^3.9", "gulp": "^3.9",
"gulp-clean-css": "^3.7.0", "gulp-clean-css": "^3.7.0",
"gulp-concat": "^2.6.0", "gulp-concat": "^2.6.0",
@ -26,9 +24,9 @@
"gulp-riot": "^1.1.1", "gulp-riot": "^1.1.1",
"gulp-uglify": "^2.1.2", "gulp-uglify": "^2.1.2",
"gulp-useref": "^3.0.0", "gulp-useref": "^3.0.0",
"material-design-lite": "^1.1",
"pump": "^1.0.2", "pump": "^1.0.2",
"riot": "^3.7.0", "riot": "^3.7.0",
"riot-mui": "^0.1.1",
"riotgear-router": "^1.3.1", "riotgear-router": "^1.3.1",
"uglify-js": "^3.0.28", "uglify-js": "^3.0.28",
"uglify-js-harmony": "^2.7.7" "uglify-js-harmony": "^2.7.7"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Before After
Before After

View file

@ -20,8 +20,7 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<!-- build:css vendor.css --> <!-- build:css vendor.css -->
<LINK href="../node_modules/dialog-polyfill/dialog-polyfill.css" rel="stylesheet" type="text/css"> <LINK href="../node_modules/riot-mui/build/styles/riot-mui.min.css" rel="stylesheet" type="text/css">
<LINK href="../node_modules/material-design-lite/dist/material.min.css" rel="stylesheet" type="text/css">
<!-- endbuild --> <!-- endbuild -->
<!-- build:css style.css --> <!-- build:css style.css -->
<LINK href="style.css" rel="stylesheet" type="text/css"> <LINK href="style.css" rel="stylesheet" type="text/css">
@ -32,38 +31,11 @@
</head> </head>
<body> <body>
<!-- Always shows a header, even in smaller screens. -->
<div class="mdl-layout mdl-js-layout mdl-layout--fixed-header">
<header class="mdl-layout__header">
<div class="mdl-layout__header-row">
<!-- Title -->
<span class="mdl-layout-title">Docker Registry UI</span>
<menu></menu>
</div>
</header>
<main class="mdl-layout__content">
<div class="page-content">
<app></app> <app></app>
</div>
</main>
<change></change>
<add></add>
<remove></remove>
<footer class="mdl-mini-footer">
<div class="mdl-mini-footer__left-section">
<div class="mdl-logo"><a href="https://joxit.github.io/docker-registry-ui/">Docker Registry UI</a></div>
<ul class="mdl-mini-footer__link-list">
<li><a href="https://github.com/Joxit/docker-registry-ui">Contribute on GitHub</a></li>
<li><a href="https://github.com/Joxit/docker-registry-ui/blob/master/LICENSE">Privacy &amp; Terms</a></li>
</ul>
</div>
</footer>
</div>
<!-- build:js scripts/vendor.js --> <!-- build:js scripts/vendor.js -->
<script src="../node_modules/riot/riot+compiler.min.js"></script> <script src="../node_modules/riot/riot+compiler.min.js"></script>
<script src="../node_modules/riotgear-router/dist/rg-router.min.js"></script> <script src="../node_modules/riotgear-router/dist/rg-router.min.js"></script>
<script src="../node_modules/dialog-polyfill/dialog-polyfill.js"></script> <script src="../node_modules/riot-mui/build/js/riot-mui.js"></script>
<script src="../node_modules/material-design-lite/dist/material.min.js"></script>
<!-- endbuild --> <!-- endbuild -->
<!-- build:js scripts/tags.js --> <!-- build:js scripts/tags.js -->
<script src="tags/catalog.tag" type="riot/tag"></script> <script src="tags/catalog.tag" type="riot/tag"></script>

View file

@ -18,7 +18,7 @@ var registryUI = {}
registryUI.URL_QUERY_PARAM_REGEX = /[&?]url=/; registryUI.URL_QUERY_PARAM_REGEX = /[&?]url=/;
registryUI.URL_PARAM_REGEX = /^url=/; registryUI.URL_PARAM_REGEX = /^url=/;
registryUI.url = function() { registryUI.url = function(byPassQueryParam) {
if (!registryUI._url) { if (!registryUI._url) {
var url = registryUI.getUrlQueryParam(); var url = registryUI.getUrlQueryParam();
if (url) { if (url) {
@ -78,10 +78,14 @@ registryUI.removeServer = function(url) {
} }
registryServer.splice(index, 1); registryServer.splice(index, 1);
localStorage.setItem('registryServer', JSON.stringify(registryServer)); localStorage.setItem('registryServer', JSON.stringify(registryServer));
if (url == registryUI.url()) {
registryUI.updateHistory(registryUI.getRegistryServer(0));
rg.router.go('home');
}
} }
registryUI.updateHistory = function(url) { registryUI.updateHistory = function(url) {
history.pushState(null, '', '?url=' + registryUI.encodeURI(url) + window.location.hash); history.pushState(null, '', (url ? '?url=' + registryUI.encodeURI(url) : '?') + window.location.hash);
registryUI._url = url; registryUI._url = url;
} }

View file

@ -18,28 +18,19 @@
html > body { html > body {
font-family: 'Roboto', 'Helvetica', 'Arial', sans-serif !important; font-family: 'Roboto', 'Helvetica', 'Arial', sans-serif !important;
} }
html, body {
.mdl-mini-footer { margin: 0;
padding-top: 8px; height: 100%;
padding-bottom: 8px;
} }
.catalog, .taglist { main {
padding: 16px; margin-bottom: 100px;
} }
.section-centerd { .section-centerd {
margin: auto; margin: auto;
} }
.mdl-data-table th {
font-size: 18px;
}
.mdl-data-table td {
font-size: 16px;
}
.full-table { .full-table {
width: 100%; width: 100%;
border: none; border: none;
@ -50,8 +41,270 @@ html > body {
word-break: break-all; word-break: break-all;
} }
.mdl-logo a { .material-card-title-action a {
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
font-weight: inherit; font-weight: inherit;
} }
material-card {
min-height: 200px;
max-width: 75%;
margin: auto;
margin-top: 20px;
margin-bottom: 20px;
}
material-spinner {
align-self: center;
}
.spinner-wrapper {
margin-top: 50px;
display: flex;
flex-direction: column;
}
material-navbar {
height: 64px;
}
.logo {
padding: 0 16px 0 72px;
text-decoration: none;
font-size: 20px;
line-height: 1;
letter-spacing: .02em;
font-weight: 400;
}
h2 {
padding: 16px;
margin: auto;
font-size: 24px;
font-weight: 300;
line-height: normal;
overflow: hidden;
}
.list {
display: block;
padding: 8px 0;
list-style: none;
}
.list.highlight>li:hover {
background-color: #eee;
cursor: pointer;
}
.list>li {
box-sizing: border-box;
line-height: 1;
height: 48px;
padding: 0 16px;
overflow: hidden;
}
.list>li i.material-icons {
margin-right: 32px;
height: 24px;
width: 24px;
font-size: 24px;
box-sizing: border-box;
color: #757575;
}
.list>li>span {
height: 100%;
text-decoration: none;
box-sizing: border-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
}
.material-card-title-action {
-webkit-align-items: center;
-ms-flex-align: center;
align-items: center;
display: block;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
padding: 16px;
}
.material-card-title-action h2 {
margin: 0;
}
material-card table {
width: 100%;
border: none;
position: relative;
border: 1px solid rgba(0,0,0,.12);
border-collapse: collapse;
white-space: nowrap;
font-size: 13px;
background-color: #fff;
border: none;
}
material-card table th {
font-size: 18px;
vertical-align: bottom;
line-height: 24px;
height: 48px;
color: rgba(0,0,0,.54);
box-sizing: border-box;
padding: 0 18px 12px 18px;
text-align: right;
}
.material-card-th-left {
text-align: left;
}
material-card table tbody tr:hover {
background-color: #eee;
}
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 {
font-size: 16px;
position: relative;
height: 48px;
border-top: 1px solid rgba(0,0,0,.12);
border-bottom: 1px solid rgba(0,0,0,.12);
padding: 12px 18px;
box-sizing: border-box;
vertical-align: middle;
text-align: right;
}
material-card table th.material-card-th-sorted-ascending:hover,
material-card table th.material-card-th-sorted-descending:hover {
cursor: pointer;
}
material-card table th.material-card-th-sorted-ascending:hover:before,
material-card table th.material-card-th-sorted-descending:hover:before {
color: rgba(0,0,0,.26);
}
material-card table th.material-card-th-sorted-ascending:before,
material-card table th.material-card-th-sorted-descending:before {
font-family: 'Material Icons';
font-weight: 400;
font-style: normal;
line-height: 1;
font-size: 16px;
content: "\e5d8";
margin-right: 5px;
vertical-align: sub;
}
material-card table th.material-card-th-sorted-descending:before {
content: "\e5db";
}
.material-icons {
color: #777;
}
material-snackbar .toast {
height: auto;
}
menu {
position: absolute;
top: 0px;
right: 16px;
color: #000;
}
menu .overlay {
position: fixed;
height: 100%;
width: 100%;
top: 0;
right: 0;
z-index: 1;
}
#menu-control-button {
background: rgba(255,255,255,0);
float: right;
}
#menu-control-button i {
color: #fff;
font-size: 24px;
}
#menu-control-dropdown {
display: inline-block;
position: relative;
}
.dropdown {
min-width: 124px;
padding: 8px 0;
margin: 0;
}
dropdown-item, #menu-control-dropdown p {
padding: 0 16px;
margin: auto;
line-height: 48px;
height: 48px;
cursor: pointer;
}
#menu-control-dropdown p:hover {
background-color: #eee;
}
#menu-control-dropdown p:active, .material-button-active:active {
background-color: #e0e0e0;
}
material-popup material-button {
background-color: #fff;
color: #000;
}
material-popup material-button:hover material-waves {
background-color: hsla(0,0%,75%,.2);
}
material-popup .popup {
max-width: 450px;
}
footer {
width: 100%;
position: fixed;
bottom: 0;
}
.select-padding {
padding: 20px 0;
}
select {
position: relative;
outline: 0;
box-shadow: none;
padding: 0;
width: 100%;
background: 0 0;
border: none;
font-weight: 400;
line-height: 24px;
height: 24px;
border-bottom: 1px solid #2f6975;
appearance: none;
-moz-appearance: none;
-webkit-appearance: none;
}

View file

@ -15,51 +15,45 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<add> <add>
<dialog ref="add-server-dialog" class="mdl-dialog"> <material-popup>
<h4 class="mdl-dialog__title">Add your Server ?</h4> <div class="material-popup-title">Add your Server ?</div>
<div class="mdl-dialog__content"> <div class="material-popup-content">
<div class="mdl-textfield mdl-js-textfield"> <material-input onkeyup="{ registryUI.addTag.onkeyup }" placeholder="Server URL"></material-input>
<input class="mdl-textfield__input" type="text" ref="add-server-input"> <span>Write your URL without /v2</span>
<label class="mdl-textfield__label" for="add-server-input">Server url</label>
</div> </div>
<div class="material-popup-action">
<material-button class="dialog-button" waves-color="rgba(158,158,158,.4)" onClick="registryUI.addTag.add();">Add</material-button>
<material-button class="dialog-button" waves-color="rgba(158,158,158,.4)" onClick="registryUI.addTag.close();">Cancel</material-button>
</div> </div>
<div class="mdl-dialog__actions"> </material-popup>
<button type="button" class="mdl-button change" onClick="registryUI.addTag.add();">Add</button>
<button type="button" class="mdl-button close" onClick="registryUI.addTag.close();">Cancel</button>
</div>
</dialog>
<script type="text/javascript"> <script type="text/javascript">
registryUI.addTag = registryUI.addTag || {}; registryUI.addTag = registryUI.addTag || {};
registryUI.addTag.update = this.update; this.one('mount', function () {
this.on('updated', function () { registryUI.addTag.dialog = this.tags['material-popup'];
registryUI.addTag.dialog = this.refs['add-server-dialog']; registryUI.addTag.dialog.getAddServer = function() {
registryUI.addTag.addServer = this.refs['add-server-input']; return this.tags['material-input'] ? this.tags['material-input'].value : '';
componentHandler.upgradeElements(registryUI.addTag.dialog);
if (!registryUI.addTag.dialog.showModal) {
dialogPolyfill.registerDialog(registryUI.addTag.dialog);
} }
this.refs['add-server-input'].onkeyup = function (e) { });
registryUI.addTag.onkeyup = function (e) {
// if keyCode is Enter // if keyCode is Enter
if (e.keyCode == 13) { if (e.keyCode == 13) {
registryUI.addTag.add(); registryUI.addTag.add();
} }
}; };
});
registryUI.addTag.show = function () { registryUI.addTag.show = function () {
registryUI.addTag.dialog.showModal(); registryUI.addTag.dialog.open();
}; };
registryUI.addTag.add = function () { registryUI.addTag.add = function () {
if (registryUI.addTag.addServer.value && registryUI.addTag.addServer.value.length > 0) { if (registryUI.addTag.dialog.getAddServer().length > 0) {
registryUI.addServer(registryUI.addTag.addServer.value); registryUI.addServer(registryUI.addTag.dialog.getAddServer());
} }
registryUI.addTag.addServer.value = '';
rg.router.go('home'); rg.router.go('home');
registryUI.addTag.dialog.close(); registryUI.addTag.close();
}; };
registryUI.addTag.close = function () { registryUI.addTag.close = function () {
registryUI.addTag.addServer.value = ''; registryUI.addTag.dialog.tags['material-input'].value = '';
registryUI.addTag.dialog.close(); registryUI.addTag.dialog.close();
}; };
registryUI.addTag.update();
</script> </script>
</add> </add>

View file

@ -15,8 +15,34 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<app> <app>
<header>
<material-navbar>
<div class="logo">Docker Registry UI</div>
<menu></menu>
</material-navbar>
</header>
<main>
<catalog if="{!rg.router.current || rg.router.current.name == 'home'}"></catalog> <catalog if="{!rg.router.current || rg.router.current.name == 'home'}"></catalog>
<taglist if="{rg.router.current && rg.router.current.name == 'taglist'}"></taglist> <taglist if="{rg.router.current && rg.router.current.name == 'taglist'}"></taglist>
<change></change>
<add></add>
<remove></remove>
<material-snackbar></material-snackbar>
</main>
<footer>
<material-footer>
<a class="material-footer-logo" href="https://joxit.github.io/docker-registry-ui/">Docker Registry UI</a>
<ul class="material-footer-link-list">
<li>
<a href="https://github.com/Joxit/docker-registry-ui">Contribute on GitHub</a>
</li>
<li>
<a href="https://github.com/Joxit/docker-registry-ui/blob/master/LICENSE">Privacy &amp; Terms</a>
</li>
</ul>
</material-footer>
</footer>
<script> <script>
this.mixin('rg.router'); this.mixin('rg.router');
@ -37,7 +63,14 @@
} }
break; break;
} }
}) });
registryUI.appTag = this;
registryUI.snackbar = function (message, isError) {
registryUI.appTag.tags['material-snackbar'].addToast({'message': message, 'isError': isError});
};
registryUI.errorSnackbar = function (message) {
return registryUI.snackbar(message, true);
}
this.router.start(); this.router.start();
</script> </script>
</app> </app>

View file

@ -16,57 +16,42 @@
--> -->
<catalog> <catalog>
<!-- Begin of tag --> <!-- Begin of tag -->
<div ref="catalog-tag" class="catalog"> <material-card ref="catalog-tag" class="catalog">
<div class="section-centerd mdl-card mdl-shadow--2dp mdl-cell--6-col"> <div class="material-card-title-action">
<div class="mdl-card__title"> <h2>Repositories of { registryUI.url() }</h2>
<h2 class="mdl-card__title-text">Repositories of { registryUI.url() }</h2>
</div> </div>
<div ref="catalog-spinner" hide="{ registryUI.catalog.loadend }" class="mdl-spinner mdl-js-spinner is-active section-centerd"></div> <div hide="{ registryUI.catalog.loadend }" class="spinner-wrapper">
<ul class="mdl-list" show="{ registryUI.catalog.loadend }"> <material-spinner></material-spinner>
<li class="mdl-list__item mdl-menu__item" style="opacity: 1;" each="{ item in registryUI.catalog.repositories }" onclick="registryUI.catalog.go('{item}');"> </div>
<span class="mdl-list__item-primary-content"> <ul class="list highlight" show="{ registryUI.catalog.loadend }">
<i class="material-icons mdl-list__item-icon">send</i> <li each="{ item in registryUI.catalog.repositories }" onclick="registryUI.catalog.go('{item}');">
<span>
<i class="material-icons">send</i>
{ item } { item }
</span> </span>
</li> </li>
</ul> </ul>
</div> </material-card>
<div ref="error-snackbar" aria-live="assertive" aria-atomic="true" aria-relevant="text" class="mdl-js-snackbar mdl-snackbar">
<div class="mdl-snackbar__text"></div>
<button class="mdl-snackbar__action" type="button"></button>
</div>
</div>
<script> <script>
registryUI.catalog.instance = this; registryUI.catalog.instance = this;
this.mixin('rg.router'); this.mixin('rg.router');
registryUI.catalog.display = function () { registryUI.catalog.display = function () {
var oReq = new Http(); var oReq = new Http();
registryUI.catalog.createSnackbar = function (msg) {
var snackbar = registryUI.catalog.instance.refs['error-snackbar'];
registryUI.catalog.error = msg;
var data = {
message: registryUI.catalog.error,
timeout: 100000,
actionHandler: function () {
snackbar.classList.remove('mdl-snackbar--active');
},
actionText: 'Undo'
};
snackbar.MaterialSnackbar.showSnackbar(data);
};
oReq.addEventListener('load', function () { oReq.addEventListener('load', function () {
registryUI.catalog.repositories = [];
if (this.status == 200) { if (this.status == 200) {
registryUI.catalog.repositories = JSON.parse(this.responseText).repositories || []; registryUI.catalog.repositories = JSON.parse(this.responseText).repositories || [];
registryUI.catalog.repositories.sort(); registryUI.catalog.repositories.sort();
} else if (this.status == 404) { } else if (this.status == 404) {
registryUI.catalog.createSnackbar('Server not found'); registryUI.snackbar('Server not found', true);
} else { } else {
registryUI.catalog.createSnackbar(this.responseText); registryUI.snackbar(this.responseText);
} }
}); });
oReq.addEventListener('error', function () { oReq.addEventListener('error', function () {
registryUI.catalog.createSnackbar('An error occured'); registryUI.snackbar('An error occured', true);
registryUI.catalog.repositories = [];
}); });
oReq.addEventListener('loadend', function () { oReq.addEventListener('loadend', function () {
registryUI.catalog.loadend = true; registryUI.catalog.loadend = true;
@ -75,9 +60,6 @@
oReq.open('GET', registryUI.url() + '/v2/_catalog'); oReq.open('GET', registryUI.url() + '/v2/_catalog');
oReq.send(); oReq.send();
}; };
this.on('updated', function () {
componentHandler.upgradeElements(this.refs['catalog-tag']);
});
registryUI.catalog.go = function (image) { registryUI.catalog.go = function (image) {
rg.router.go('taglist', { rg.router.go('taglist', {
repository: image.split('/')[0], repository: image.split('/')[0],

View file

@ -15,47 +15,42 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<change> <change>
<dialog ref="change-server-dialog" class="mdl-dialog"> <material-popup>
<h4 class="mdl-dialog__title">Change your Server ?</h4> <div class="material-popup-title">Change your Server ?</div>
<div class="mdl-dialog__content"> <div class="material-popup-content">
<div class="mdl-textfield mdl-js-textfield"> <div class="select-padding">
<select class="mdl-textfield__input mdl-textfield__select" name="server-list" ref="server-list"> <select class="mdl-textfield__input mdl-textfield__select" name="server-list" ref="server-list">
<option each="{ url in registryUI.getRegistryServer() }" value={url}>{url}</option> <option each="{ url in registryUI.getRegistryServer() }" value={url}>{url}</option>
</select> </select>
</div> </div>
</div> </div>
<div class="mdl-dialog__actions"> <div class="material-popup-action">
<button type="button" class="mdl-button change" onClick="registryUI.changeTag.change();">Change</button> <material-button class="dialog-button" waves-color="rgba(158,158,158,.4)" onClick="registryUI.changeTag.change();">Change</material-button>
<button type="button" class="mdl-button close" onClick="registryUI.changeTag.close();">Cancel</button> <material-button class="dialog-button" waves-color="rgba(158,158,158,.4)" onClick="registryUI.changeTag.close();">Cancel</material-button>
</div> </div>
</dialog> </material-popup>
<script type="text/javascript"> <script type="text/javascript">
registryUI.changeTag = registryUI.changeTag || {}; registryUI.changeTag = registryUI.changeTag || {};
registryUI.changeTag.update = this.update; this.one('mount', function () {
this.on('updated', function () { registryUI.changeTag.dialog = this.tags['material-popup'];
componentHandler.upgradeElements(this.refs['change-server-dialog']); registryUI.changeTag.dialog.getServerUrl = function () {
registryUI.changeTag.dialog = registryUI.changeTag.dialog || this.refs['change-server-dialog']; return this.refs['server-list']
registryUI.changeTag.serverList = registryUI.changeTag.serverList || this.refs['server-list']; ? this.refs['server-list'].value
if (!registryUI.changeTag.dialog.showModal) { : '';
dialogPolyfill.registerDialog(registryUI.changeTag.dialog);
}
this.refs['server-list'].onkeyup = function (e) {
// if keyCode is Enter
if (e.keyCode == 13) {
registryUI.changeTag.change();
}
}; };
registryUI.changeTag.dialog.on('updated', function () {
if (this.refs['server-list']) {
this.refs['server-list'].value = registryUI.url();
}
});
}); });
registryUI.changeTag.show = function () { registryUI.changeTag.show = function () {
registryUI.changeTag.update(); registryUI.changeTag.dialog.open();
registryUI.changeTag.serverList.value = registryUI.url();;
registryUI.changeTag.dialog.showModal();
}; };
registryUI.changeTag.change = function () { registryUI.changeTag.change = function () {
if (registryUI.changeTag.serverList.value && registryUI.changeTag.serverList.value.length > 0) { if (registryUI.changeTag.dialog.getServerUrl().length > 0) {
registryUI.changeServer(registryUI.changeTag.serverList.value); registryUI.changeServer(registryUI.changeTag.dialog.getServerUrl());
} }
registryUI.changeTag.serverList.value = '';
rg.router.go('home'); rg.router.go('home');
registryUI.changeTag.dialog.close(); registryUI.changeTag.dialog.close();
}; };

View file

@ -15,23 +15,31 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<menu> <menu>
<div ref="card-menu" id="card-menu" class="mdl-card__menu"> <material-button id="menu-control-button" onclick="registryUI.menuTag.toggle();" waves-center="true" rounded="true" waves-opacity="0.6" waves-duration="600">
<button ref="registry-menu" name="registry-menu" class="mdl-button mdl-button--icon mdl-js-button mdl-js-ripple-effect">
<i class="material-icons">more_vert</i> <i class="material-icons">more_vert</i>
</button> </material-button>
<ul class="mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect" for="registry-menu"> <material-dropdown id="menu-control-dropdown">
<li class="mdl-menu__item" onclick="registryUI.addTag.show();">Add URL</li> <p onclick="registryUI.addTag.show(); registryUI.menuTag.close();">Add URL</p>
<li class="mdl-menu__item" onclick="registryUI.changeTag.show();">Change URL</li> <p onclick="registryUI.changeTag.show(); registryUI.menuTag.close();">Change URL</p>
<li class="mdl-menu__item" onclick="registryUI.removeTag.show();">Remove URL</li> <p onclick="registryUI.removeTag.show(); registryUI.menuTag.close();">Remove URL</p>
</ul> </material-dropdown>
</div> <div class="overlay" onclick="registryUI.menuTag.close();" show="{ registryUI.menuTag.isOpen && registryUI.menuTag.isOpen() }"></div>
<script type="text/javascript"> <script type="text/javascript">
registryUI.menuTag = registryUI.menuTag || {}; registryUI.menuTag = registryUI.menuTag || {};
registryUI.menuTag.update = this.update; registryUI.menuTag.update = this.update;
this.on('updated', function () { this.one('mount', function(args) {
componentHandler.upgradeElements(this.refs['card-menu']); var self = this;
registryUI.menuTag.close = function() {
self.tags['material-dropdown'].close();
self.update();
}
registryUI.menuTag.isOpen = function() {
return self.tags['material-dropdown'].opened;
}
registryUI.menuTag.toggle = function() {
self.tags['material-dropdown'].opened ? self.tags['material-dropdown'].close() : self.tags['material-dropdown'].open();
self.update();
};
}); });
registryUI.menuTag.update();
</script> </script>
</menu> </menu>

View file

@ -16,7 +16,7 @@
--> -->
<remove-image> <remove-image>
<a href="#" onclick="registryUI.removeImage.remove('{ opts.name }', '{ opts.tag }')"> <a href="#" onclick="registryUI.removeImage.remove('{ opts.name }', '{ opts.tag }')">
<i class="material-icons mdl-list__item-icon">delete</i> <i class="material-icons">delete</i>
</a> </a>
<script type="text/javascript"> <script type="text/javascript">
registryUI.removeImage = registryUI.removeImage || {} registryUI.removeImage = registryUI.removeImage || {}
@ -28,7 +28,7 @@
registryUI.taglist.refresh(); registryUI.taglist.refresh();
if (this.status == 200) { if (this.status == 200) {
if (!this.hasHeader('Docker-Content-Digest')) { if (!this.hasHeader('Docker-Content-Digest')) {
registryUI.taglist.createSnackbar('You need to add Access-Control-Expose-Headers: [\'Docker-Content-Digest\'] in your server configuration.'); registryUI.errorSnackbar('You need to add Access-Control-Expose-Headers: [\'Docker-Content-Digest\'] in your server configuration.');
return; return;
} }
var digest = this.getResponseHeader('Docker-Content-Digest'); var digest = this.getResponseHeader('Docker-Content-Digest');
@ -36,23 +36,23 @@
oReq.addEventListener('loadend', function () { oReq.addEventListener('loadend', function () {
if (this.status == 200 || this.status == 202) { if (this.status == 200 || this.status == 202) {
registryUI.taglist.refresh(); registryUI.taglist.refresh();
registryUI.taglist.createSnackbar('Deleting ' + name + ':' + tag + ' image. Run `registry garbage-collect config.yml` on your registry'); registryUI.snackbar('Deleting ' + name + ':' + tag + ' image. Run `registry garbage-collect config.yml` on your registry');
} else if (this.status == 404) { } else if (this.status == 404) {
registryUI.taglist.createSnackbar('Digest not found'); registryUI.errorSnackbar('Digest not found');
} else { } else {
registryUI.taglist.createSnackbar(this.responseText); registryUI.snackbar(this.responseText);
} }
}); });
oReq.open('DELETE', registryUI.url() + '/v2/' + name + '/manifests/' + digest); oReq.open('DELETE', registryUI.url() + '/v2/' + name + '/manifests/' + digest);
oReq.setRequestHeader('Accept', 'application/vnd.docker.distribution.manifest.v2+json'); oReq.setRequestHeader('Accept', 'application/vnd.docker.distribution.manifest.v2+json');
oReq.addEventListener('error', function () { oReq.addEventListener('error', function () {
registryUI.taglist.createSnackbar('An error occurred when deleting image. Check if your server accept DELETE methods Access-Control-Allow-Methods: [\'DELETE\'].'); registryUI.errorSnackbar('An error occurred when deleting image. Check if your server accept DELETE methods Access-Control-Allow-Methods: [\'DELETE\'].');
}); });
oReq.send(); oReq.send();
} else if (this.status == 404) { } else if (this.status == 404) {
registryUI.taglist.createSnackbar('Manifest for' + name + ':' + tag + 'not found'); registryUI.errorSnackbar('Manifest for ' + name + ':' + tag + ' not found');
} else { } else {
registryUI.taglist.createSnackbar(this.responseText); registryUI.snackbar(this.responseText);
} }
}); });
oReq.open('HEAD', registryUI.url() + '/v2/' + name + '/manifests/' + tag); oReq.open('HEAD', registryUI.url() + '/v2/' + name + '/manifests/' + tag);

View file

@ -15,33 +15,32 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
--> -->
<remove> <remove>
<dialog ref="remove-server-dialog" class="mdl-dialog">
<h4 class="mdl-dialog__title">Remove your Registry Server ?</h4> <material-popup>
<div class="mdl-dialog__content"> <div class="material-popup-title">Remove your Registry Server ?</div>
<div class="mdl-textfield mdl-js-textfield"> <div class="material-popup-content">
<ul class="mdl-list"> <ul class="list">
<li class="mdl-list__item" each="{ url in registryUI.getRegistryServer() }"> <li each="{ url in registryUI.getRegistryServer() }">
<span class="mdl-list__item-primary-content"> <span>
<a href="#" onClick="registryUI.removeTag.removeUrl('{url}');"> <a href="#" onClick="registryUI.removeTag.removeUrl('{url}');">
<i class="material-icons mdl-list__item-icon">delete</i> <i class="material-icons">delete</i>
</a> </a>
<span class="url">{ url }</span> <span class="url">{ url }</span>
</span> </span>
</li> </li>
</ul> </ul>
</div> </div>
<div class="material-popup-action">
<material-button class="dialog-button" waves-color="rgba(158,158,158,.4)" onClick="registryUI.removeTag.close();">Close</material-button>
</div> </div>
<div class="mdl-dialog__actions"> </material-popup>
<button type="button" class="mdl-button close" onClick="registryUI.removeTag.close();">Close</button>
</div>
</dialog>
<script type="text/javascript"> <script type="text/javascript">
registryUI.removeTag = registryUI.removeTag || {} registryUI.removeTag = registryUI.removeTag || {}
registryUI.removeTag.update = this.update; registryUI.removeTag.update = this.update;
registryUI.removeTag.removeUrl = function (url) { registryUI.removeTag.removeUrl = function (url) {
registryUI.removeServer(url); registryUI.removeServer(url);
registryUI.removeTag.update(); registryUI.removeTag.close();
}; };
registryUI.removeTag.close = function () { registryUI.removeTag.close = function () {
@ -50,15 +49,11 @@
}; };
registryUI.removeTag.show = function () { registryUI.removeTag.show = function () {
registryUI.removeTag.update(); registryUI.removeTag.dialog.open();
registryUI.removeTag.dialog.showModal();
}; };
this.on('updated', function () { this.one('mount', function () {
registryUI.removeTag.dialog = this.refs['remove-server-dialog']; registryUI.removeTag.dialog = this.tags['material-popup'];
if (!registryUI.removeTag.dialog.showModal) {
dialogPolyfill.registerDialog(registryUI.removeTag.dialog);
}
}); });
</script> </script>
</remove> </remove>

View file

@ -16,26 +16,27 @@
--> -->
<taglist> <taglist>
<!-- Begin of tag --> <!-- Begin of tag -->
<div ref="taglist-tag" class="taglist"> <material-card ref="taglist-tag" class="taglist">
<div class="section-centerd mdl-card mdl-shadow--2dp mdl-cell--6-col"> <div class="material-card-title-action">
<div class="mdl-card__title">
<a href="#" onclick="registryUI.taglist.back();"> <a href="#" onclick="registryUI.taglist.back();">
<i class="material-icons mdl-list__item-icon">arrow_back</i> <i class="material-icons">arrow_back</i>
</a> </a>
<h2 class="mdl-card__title-text">Tags of { registryUI.url() + '/' + registryUI.taglist.name }</h2> <h2>Tags of { registryUI.url() + '/' + registryUI.taglist.name }</h2>
</div> </div>
<div ref="taglist-spinner" hide="{ registryUI.taglist.loadend }" class="mdl-spinner mdl-js-spinner section-centerd is-active"></div> <div hide="{ registryUI.taglist.loadend }" class="spinner-wrapper">
<table class="mdl-data-table mdl-js-data-table full-table" show="{ registryUI.taglist.loadend }" style="border: none;"> <material-spinner></material-spinner>
</div>
<table show="{ registryUI.taglist.loadend }" style="border: none;">
<thead> <thead>
<tr> <tr>
<th class="mdl-data-table__cell--non-numeric">Repository</th> <th class="material-card-th-left">Repository</th>
<th class="{ registryUI.taglist.asc ? 'mdl-data-table__header--sorted-ascending' : 'mdl-data-table__header--sorted-descending' }" onclick="registryUI.taglist.reverse();">Tag</th> <th class="{ registryUI.taglist.asc ? 'material-card-th-sorted-ascending' : 'material-card-th-sorted-descending' }" onclick="registryUI.taglist.reverse();">Tag</th>
<th show="{ registryUI.isImageRemoveActivated }"></th> <th show="{ registryUI.isImageRemoveActivated }"></th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr each="{ item in registryUI.taglist.tags }"> <tr each="{ item in registryUI.taglist.tags }">
<td class="mdl-data-table__cell--non-numeric">{ registryUI.taglist.name }</td> <td class="material-card-th-left">{ registryUI.taglist.name }</td>
<td>{ item }</td> <td>{ item }</td>
<td show="{ registryUI.isImageRemoveActivated }"> <td show="{ registryUI.isImageRemoveActivated }">
<remove-image name={ registryUI.taglist.name } tag={ item }/> <remove-image name={ registryUI.taglist.name } tag={ item }/>
@ -43,13 +44,7 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </material-card>
<div ref="error-snackbar" aria-live="assertive" aria-atomic="true" aria-relevant="text" class="mdl-js-snackbar mdl-snackbar">
<div class="mdl-snackbar__text"></div>
<button class="mdl-snackbar__action" type="button"></button>
</div>
</div>
<script> <script>
registryUI.taglist.instance = this; registryUI.taglist.instance = this;
registryUI.taglist.display = function () { registryUI.taglist.display = function () {
@ -60,31 +55,20 @@
var oReq = new Http(); var oReq = new Http();
registryUI.taglist.name = name; registryUI.taglist.name = name;
registryUI.taglist.instance.update(); registryUI.taglist.instance.update();
registryUI.taglist.createSnackbar = function (msg) {
var snackbar = registryUI.taglist.instance['error-snackbar'];
registryUI.taglist.error = msg;
var data = {
message: registryUI.taglist.error,
timeout: 100000,
actionHandler: function () {
snackbar.classList.remove('mdl-snackbar--active');
},
actionText: 'Undo'
};
snackbar.MaterialSnackbar.showSnackbar(data);
};
oReq.addEventListener('load', function () { oReq.addEventListener('load', function () {
registryUI.taglist.tags = [];
if (this.status == 200) { if (this.status == 200) {
registryUI.taglist.tags = JSON.parse(this.responseText).tags || []; registryUI.taglist.tags = JSON.parse(this.responseText).tags || [];
registryUI.taglist.tags.sort(); registryUI.taglist.tags.sort();
} else if (this.status == 404) { } else if (this.status == 404) {
registryUI.taglist.createSnackbar('Server not found'); registryUI.snackbar('Server not found', true);
} else { } else {
registryUI.taglist.createSnackbar(this.responseText); registryUI.snackbar(this.responseText, true);
} }
}); });
oReq.addEventListener('error', function () { oReq.addEventListener('error', function () {
registryUI.taglist.createSnackbar('An error occured'); registryUI.snackbar('An error occured', true);
registryUI.taglist.tags = [];
}); });
oReq.addEventListener('loadend', function () { oReq.addEventListener('loadend', function () {
registryUI.taglist.loadend = true; registryUI.taglist.loadend = true;
@ -97,9 +81,6 @@
}; };
registryUI.taglist.display(); registryUI.taglist.display();
registryUI.taglist.instance.update(); registryUI.taglist.instance.update();
this.on('updated', function () {
componentHandler.upgradeElements(this.refs['taglist-tag']);
});
registryUI.taglist.reverse = function () { registryUI.taglist.reverse = function () {
if (registryUI.taglist.asc) { if (registryUI.taglist.asc) {