Compare commits

...

26 Commits
0.2.2 ... 0.3.0

Author SHA1 Message Date
Joxit
89c532edbd Update version to 0.3.0: riot-mui (#17) 2017-10-19 09:56:47 +02:00
Jones Magloire
b9effee691 Merge pull request #23 from Joxit/riot-mui
Move from material-design lite to riot-mui
2017-10-17 00:02:31 +02:00
Joxit
05090d121d [riot-mui] Update gulpfile
Use riot.min.js instead of riot+compiler.min.js
2017-10-15 23:49:37 +02:00
Joxit
c8d98f68d1 [riot-mui] Update readme 2017-10-14 20:53:35 +02:00
Joxit
a8bede51db [riot-mui] Add css for select and code clean up (#17) 2017-10-13 00:27:14 +02:00
Joxit
cce858cbd9 [riot-mui] Remove links to material-design-lite 2017-10-12 23:45:40 +02:00
Joxit
215733c6e4 [riot-mui] Add new riot-mui footer (#17, kysonic/riot-mui#51, kysonic/riot-mui#52) 2017-10-11 00:01:45 +02:00
Joxit
93a8d4a188 [riot-mui] Fix when there is an error, resets the view 2017-09-30 19:08:58 +02:00
Joxit
ab0571eaa1 [riot-mui] Add riot-mui in remove taf (#17)
When we remove the current server, it will update the view.
2017-09-29 21:08:19 +02:00
Joxit
dc929951cf [riot-mui] Clean up and fix in add tag, again 2017-09-28 20:53:59 +02:00
Joxit
91497a06c3 [riot-mui] Add riot-mui in change tag (#17) 2017-09-27 20:52:52 +02:00
Joxit
4d1db1f884 [riot-mui] Fix in add tag dialog 2017-09-26 20:53:32 +02:00
Joxit
a59e759c9c [riot-mui] Minor clean up and fix in catalog and menu (#17) 2017-09-25 00:32:12 +02:00
Joxit
46b80e73f2 [riot-mui] Add riot-mui in add (#17) 2017-09-25 00:32:09 +02:00
Joxit
bdc0d34a87 [riot-mui] Add riot-mui in menu (#17) 2017-09-25 00:32:06 +02:00
Joxit
d4b99b2cb2 [riot-mui] Add riot-mui in remove-image (#17) 2017-09-25 00:32:02 +02:00
Joxit
c1f9d02afb [riot-mui] Add riot-mui in taglist (#17) 2017-09-25 00:31:58 +02:00
Joxit
d404ead587 [riot-mui] Add riot-mui in app and catalog (#17)
- Refactoring index.html/app.tag, now only <app></app> in index.html
- Add riot-mui in catalog.tag
2017-09-25 00:31:40 +02:00
Jones Magloire
5569f1f0bf Merge pull request #22 from Joxit/dependencies
Upgrade dependencies and use riot v3
2017-09-16 23:27:13 +02:00
Joxit
9d48643957 [dependencies] upgrade to riot v3 2017-09-10 20:14:16 +02:00
Joxit
961342d34c Update 0.2.4: query param 2017-09-09 00:07:23 +02:00
Jones Magloire
02c95fee44 Merge pull request #21 from Joxit/query-param
[query-param] Add url query param for sharing
2017-09-08 23:54:51 +02:00
Joxit
ca5fb09fc6 [query-param] Change decode/encodeURI to URIComponent 2017-09-06 23:32:10 +02:00
Joxit
83e2befd5d [dependencies] Upgrade packages dependencies 2017-09-05 23:09:19 +02:00
Joxit
06e4d62543 [query-param] Add url query param for sharing 2017-09-03 00:39:28 +02:00
Joxit
5cf136541f Update 0.2.3: Fix issue #19 again...
Add link to project page
2017-08-06 22:20:58 +02:00
25 changed files with 566 additions and 1111 deletions

View File

@@ -5,9 +5,9 @@
This project aims to provide a user interface for your private docker registry v2.
There is no default registry on this UI, you should add your own with the UI.
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 registries 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 uses [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/)
@@ -18,8 +18,9 @@ This web user interface use [Riot](https://github.com/Riot/riot) the react-like
- List all your repositories/images.
- List all tags for a repository/image
- Sort the tag list
- One interface for many registry
- One interface for many registries
- 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
@@ -48,7 +49,7 @@ The docker contains the source code and a node webserver in order to serve the d
You can get the image in three ways
From sources with this command :
From sources with this command:
```sh
git clone https://github.com/Joxit/docker-registry-ui.git
@@ -56,14 +57,14 @@ docker build -t joxit/docker-registry-ui docker-registry-ui
docker build -t joxit/docker-registry-ui -f docker-registry-ui/Dockerfile.static docker-registry-ui
```
Or build with the url :
Or build with the url:
```sh
docker build -t joxit/docker-registry-ui github.com/Joxit/docker-registry-ui
docker build -t joxit/docker-registry-ui -f Dockerfile.static github.com/Joxit/docker-registry-ui
```
Or pull the image from [docker hub](https://hub.docker.com/r/joxit/docker-registry-ui/) :
Or pull the image from [docker hub](https://hub.docker.com/r/joxit/docker-registry-ui/):
```sh
docker pull joxit/docker-registry-ui
@@ -72,7 +73,7 @@ docker pull joxit/docker-registry-ui:static
#### Run the docker
To run the docker and see the website on your 80 port, try this :
To run the docker and see the website on your 80 port, try this:
```sh
docker run -d -p 80:80 joxit/docker-registry-ui
@@ -93,11 +94,11 @@ docker run -d -p 80:80 -e URL=http://127.0.0.1:5000 -e DELETE_IMAGES=true joxit/
Your server should be configured to accept CORS.
If your docker registry does not need credentials, you will need to send this HEADER :
If your docker registry does not need credentials, you will need to send this HEADER:
Access-Control-Allow-Origin: '*'
If your docker registry need credentials, you will need to send these HEADERS :
If your docker registry need credentials, you will need to send these HEADERS:
```yml
http:
@@ -109,7 +110,7 @@ http:
## Using delete
For deleting images, you need to activate the delete feature in your registry :
For deleting images, you need to activate the delete feature in your registry:
```yml
storage:
@@ -117,7 +118,7 @@ storage:
enabled: true
```
And you need to add these HEADERS :
And you need to add these HEADERS:
```yml
http:

View File

@@ -26,32 +26,7 @@
</head>
<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>
</div>
</main>
<change></change>
<add></add>
<remove></remove>
<footer class="mdl-mini-footer">
<div class="mdl-mini-footer__left-section">
<div class="mdl-logo">Docker Registry UI</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>
<app></app>
<script src="../dist/scripts/vendor.js"></script>
<script src="../dist/scripts/tags.js"></script>
<script src="../dist/scripts/script.js"></script>

2
dist/index.html vendored
View File

@@ -13,4 +13,4 @@
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/>.
--><!DOCTYPE html><html><head><meta charset="UTF-8"><link rel="stylesheet" href="vendor.css"><link rel="stylesheet" href="style.css"><link href="https://fonts.googleapis.com/css?family=Roboto:regular,bold,italic,thin,light,bolditalic,black,medium&amp;lang=en" rel="stylesheet" type="text/css"><title>Docker Registry UI</title></head><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></div></main><change></change><add></add><remove></remove><footer class="mdl-mini-footer"><div class="mdl-mini-footer__left-section"><div class="mdl-logo">Docker Registry UI</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><script src="scripts/vendor.js"></script><script src="scripts/tags.js"></script><script src="scripts/script.js"></script></body></html>
--><!DOCTYPE html><html><head><meta charset="UTF-8"><link rel="stylesheet" href="vendor.css"><link rel="stylesheet" href="style.css"><link href="https://fonts.googleapis.com/css?family=Roboto:regular,bold,italic,thin,light,bolditalic,black,medium&amp;lang=en" rel="stylesheet" type="text/css"><title>Docker Registry UI</title></head><body><app></app><script src="scripts/vendor.js"></script><script src="scripts/tags.js"></script><script src="scripts/script.js"></script></body></html>

View File

@@ -15,4 +15,4 @@
* 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/>.
*/
function Http(){this.oReq=new XMLHttpRequest,this.oReq.hasHeader=Http.hasHeader,this._events={},this._headers={}}Http.prototype.addEventListener=function(e,t){this._events[e]=t;var s=this;switch(e){case"loadend":s.oReq.addEventListener("loadend",function(){if(401==this.status){var e=new XMLHttpRequest;e.open(s._method,s._url);for(key in s._events)e.addEventListener(key,s._events[key]);for(key in s._headers)e.setRequestHeader(key,s._headers[key]);e.withCredentials=!0,e.hasHeader=Http.hasHeader,e.send()}else t.bind(this)()});break;case"load":s.oReq.addEventListener("load",function(){401!==this.status&&t.bind(this)()});break;default:s.oReq.addEventListener(e,function(){t.bind(this)()})}},Http.prototype.setRequestHeader=function(e,t){this.oReq.setRequestHeader(e,t),this._headers[e]=t},Http.prototype.open=function(e,t){this._method=e,this._url=t,this.oReq.open(e,t)},Http.prototype.send=function(){this.oReq.send()},Http.hasHeader=function(e){return this.getAllResponseHeaders().split("\n").some(function(t){return t.match(new RegExp("^"+e+":"),"i")})};var registryUI={};registryUI.url=function(){return"${URL}"},registryUI.isImageRemoveActivated=!0,registryUI.catalog={},registryUI.taglist={},riot.mount("catalog"),riot.mount("taglist"),riot.mount("app");
function Http(){this.oReq=new XMLHttpRequest,this.oReq.hasHeader=Http.hasHeader,this._events={},this._headers={}}Http.prototype.addEventListener=function(e,t){this._events[e]=t;var s=this;switch(e){case"loadend":s.oReq.addEventListener("loadend",function(){if(401==this.status){var e=new XMLHttpRequest;e.open(s._method,s._url);for(key in s._events)e.addEventListener(key,s._events[key]);for(key in s._headers)e.setRequestHeader(key,s._headers[key]);e.withCredentials=!0,e.hasHeader=Http.hasHeader,e.send()}else t.bind(this)()});break;case"load":s.oReq.addEventListener("load",function(){401!==this.status&&t.bind(this)()});break;default:s.oReq.addEventListener(e,function(){t.bind(this)()})}},Http.prototype.setRequestHeader=function(e,t){this.oReq.setRequestHeader(e,t),this._headers[e]=t},Http.prototype.open=function(e,t){this._method=e,this._url=t,this.oReq.open(e,t)},Http.prototype.send=function(){this.oReq.send()},Http.hasHeader=function(e){return this.getAllResponseHeaders().split("\n").some(function(t){return new RegExp("^"+e+":","i").test(t)})};var registryUI={};registryUI.url=function(){return"${URL}"},registryUI.isImageRemoveActivated=!0,registryUI.catalog={},registryUI.taglist={},riot.mount("catalog"),riot.mount("taglist"),riot.mount("app");

View File

@@ -15,4 +15,4 @@
* 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/>.
*/
function Http(){this.oReq=new XMLHttpRequest,this.oReq.hasHeader=Http.hasHeader,this._events={},this._headers={}}Http.prototype.addEventListener=function(e,t){this._events[e]=t;var r=this;switch(e){case"loadend":r.oReq.addEventListener("loadend",function(){if(401==this.status){var e=new XMLHttpRequest;e.open(r._method,r._url);for(key in r._events)e.addEventListener(key,r._events[key]);for(key in r._headers)e.setRequestHeader(key,r._headers[key]);e.withCredentials=!0,e.hasHeader=Http.hasHeader,e.send()}else t.bind(this)()});break;case"load":r.oReq.addEventListener("load",function(){401!==this.status&&t.bind(this)()});break;default:r.oReq.addEventListener(e,function(){t.bind(this)()})}},Http.prototype.setRequestHeader=function(e,t){this.oReq.setRequestHeader(e,t),this._headers[e]=t},Http.prototype.open=function(e,t){this._method=e,this._url=t,this.oReq.open(e,t)},Http.prototype.send=function(){this.oReq.send()},Http.hasHeader=function(e){return this.getAllResponseHeaders().split("\n").some(function(t){return t.match(new RegExp("^"+e+":"),"i")})};var registryUI={};registryUI.url=function(){return registryUI.getRegistryServer(0)},registryUI.getRegistryServer=function(e){try{var t=JSON.parse(localStorage.getItem("registryServer"));if(t instanceof Array)return isNaN(e)?t.map(function(e){return e.trim().replace(/\/*$/,"")}):t[e]}catch(e){}return isNaN(e)?[]:""},registryUI.addServer=function(e){var t=registryUI.getRegistryServer();e=e.trim().replace(/\/*$/,"");var r=t.indexOf(e);r==-1&&(t.push(e),localStorage.setItem("registryServer",JSON.stringify(t)))},registryUI.changeServer=function(e){var t=registryUI.getRegistryServer();e=e.trim().replace(/\/*$/,"");var r=t.indexOf(e);r!=-1&&(t.splice(r,1),t=[e].concat(t),localStorage.setItem("registryServer",JSON.stringify(t)))},registryUI.removeServer=function(e){var t=registryUI.getRegistryServer();e=e.trim().replace(/\/*$/,"");var r=t.indexOf(e);r!=-1&&(t.splice(r,1),localStorage.setItem("registryServer",JSON.stringify(t)))},registryUI.isImageRemoveActivated=!0,registryUI.catalog={},registryUI.taglist={},riot.mount("add"),riot.mount("change"),riot.mount("remove"),riot.mount("menu"),riot.mount("app");
function Http(){this.oReq=new XMLHttpRequest,this.oReq.hasHeader=Http.hasHeader,this._events={},this._headers={}}Http.prototype.addEventListener=function(e,r){this._events[e]=r;var t=this;switch(e){case"loadend":t.oReq.addEventListener("loadend",function(){if(401==this.status){var e=new XMLHttpRequest;e.open(t._method,t._url);for(key in t._events)e.addEventListener(key,t._events[key]);for(key in t._headers)e.setRequestHeader(key,t._headers[key]);e.withCredentials=!0,e.hasHeader=Http.hasHeader,e.send()}else r.bind(this)()});break;case"load":t.oReq.addEventListener("load",function(){401!==this.status&&r.bind(this)()});break;default:t.oReq.addEventListener(e,function(){r.bind(this)()})}},Http.prototype.setRequestHeader=function(e,r){this.oReq.setRequestHeader(e,r),this._headers[e]=r},Http.prototype.open=function(e,r){this._method=e,this._url=r,this.oReq.open(e,r)},Http.prototype.send=function(){this.oReq.send()},Http.hasHeader=function(e){return this.getAllResponseHeaders().split("\n").some(function(r){return new RegExp("^"+e+":","i").test(r)})};var registryUI={};registryUI.URL_QUERY_PARAM_REGEX=/[&?]url=/,registryUI.URL_PARAM_REGEX=/^url=/,registryUI.url=function(e){if(!registryUI._url){var r=registryUI.getUrlQueryParam();if(r)try{return registryUI._url=registryUI.decodeURI(r),registryUI._url}catch(e){console.log(e)}registryUI._url=registryUI.getRegistryServer(0)}return registryUI._url},registryUI.getRegistryServer=function(e){try{var r=JSON.parse(localStorage.getItem("registryServer"));if(r instanceof Array)return isNaN(e)?r.map(function(e){return e.trim().replace(/\/*$/,"")}):r[e]}catch(e){}return isNaN(e)?[]:""},registryUI.addServer=function(e){var r=registryUI.getRegistryServer();e=e.trim().replace(/\/*$/,"");var t=r.indexOf(e);t==-1&&(r.push(e),registryUI._url||registryUI.updateHistory(e),localStorage.setItem("registryServer",JSON.stringify(r)))},registryUI.changeServer=function(e){var r=registryUI.getRegistryServer();e=e.trim().replace(/\/*$/,"");var t=r.indexOf(e);t!=-1&&(r.splice(t,1),r=[e].concat(r),registryUI.updateHistory(e),localStorage.setItem("registryServer",JSON.stringify(r)))},registryUI.removeServer=function(e){var r=registryUI.getRegistryServer();e=e.trim().replace(/\/*$/,"");var t=r.indexOf(e);t!=-1&&(r.splice(t,1),localStorage.setItem("registryServer",JSON.stringify(r)),e==registryUI.url()&&(registryUI.updateHistory(registryUI.getRegistryServer(0)),rg.router.go("home")))},registryUI.updateHistory=function(e){history.pushState(null,"",(e?"?url="+registryUI.encodeURI(e):"?")+window.location.hash),registryUI._url=e},registryUI.getUrlQueryParam=function(){var e=window.location.search;if(registryUI.URL_QUERY_PARAM_REGEX.test(e)){var r=e.split(/^\?|&/).find(function(e){return e&&registryUI.URL_PARAM_REGEX.test(e)});return r?r.replace(registryUI.URL_PARAM_REGEX,""):r}},registryUI.encodeURI=function(e){return e.indexOf("&")<0?window.encodeURIComponent(e):btoa(e)},registryUI.decodeURI=function(e){return e.startsWith("http")?window.decodeURIComponent(e):atob(e)},registryUI.isImageRemoveActivated=!0,registryUI.catalog={},registryUI.taglist={},riot.mount("*");

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

750
dist/scripts/vendor.js vendored

File diff suppressed because one or more lines are too long

2
dist/style.css vendored
View File

@@ -15,4 +15,4 @@
* 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/>.
*/
@font-face{font-family:'Material Icons';font-style:normal;font-weight:400;src:url(MaterialIcons-Regular.eot);src:local('fonts/Material Icons'),local('fonts/MaterialIcons-Regular'),url(fonts/MaterialIcons-Regular.woff2) format('woff2'),url(fonts/MaterialIcons-Regular.woff) format('woff'),url(fonts/MaterialIcons-Regular.ttf) format('truetype')}.material-icons{font-family:'Material Icons';font-weight:400;font-style:normal;font-size:24px;display:inline-block;width:1em;height:1em;line-height:1;text-transform:none;letter-spacing:normal;word-wrap:normal;white-space:nowrap;direction:ltr;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;font-feature-settings:'liga'}html>body{font-family:Roboto,Helvetica,Arial,sans-serif!important}.mdl-mini-footer{padding-top:8px;padding-bottom:8px}.catalog,.taglist{padding:16px}.section-centerd{margin:auto}.mdl-data-table th{font-size:18px}.mdl-data-table td{font-size:16px}.full-table{width:100%;border:none}.url{font-size:14px;word-break:break-all}
@font-face{font-family:'Material Icons';font-style:normal;font-weight:400;src:url(MaterialIcons-Regular.eot);src:local('fonts/Material Icons'),local('fonts/MaterialIcons-Regular'),url(fonts/MaterialIcons-Regular.woff2) format('woff2'),url(fonts/MaterialIcons-Regular.woff) format('woff'),url(fonts/MaterialIcons-Regular.ttf) format('truetype')}.material-icons{font-family:'Material Icons';font-weight:400;font-style:normal;font-size:24px;display:inline-block;width:1em;height:1em;line-height:1;text-transform:none;letter-spacing:normal;word-wrap:normal;white-space:nowrap;direction:ltr;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;-moz-osx-font-smoothing:grayscale;font-feature-settings:'liga'}html>body{font-family:Roboto,Helvetica,Arial,sans-serif!important}body,html{margin:0;height:100%}main{margin-bottom:100px}.section-centerd{margin:auto}.full-table{width:100%;border:none}.url{font-size:14px;word-break:break-all}.material-card-title-action a{color:inherit;text-decoration:none;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:0;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}#menu-control-dropdown p,dropdown-item{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}

47
dist/vendor.css vendored

File diff suppressed because one or more lines are too long

View File

@@ -14,7 +14,7 @@ var uglify = require('uglify-js-harmony');
var useref = require('gulp-useref');
gulp.task('html', function() {
var htmlFilter = filter('**/*.html');
var htmlFilter = filter('**/*.html', {restore: true});
return gulp.src(['src/index.html'])
.pipe(useref())
.pipe(gIf(['*.js', '!*.min.js'], minifier({}, uglify))) // FIXME
@@ -26,12 +26,12 @@ gulp.task('html', function() {
removeEmptyAttributes: true,
minifyJS: uglify
}))
.pipe(htmlFilter.restore())
.pipe(htmlFilter.restore)
.pipe(gulp.dest('dist'));
});
gulp.task('clean', function(done) {
del(['dist'], done);
return del(['dist']);
});
gulp.task('riot-tag', ['html'], function() {
@@ -88,6 +88,12 @@ gulp.task('scripts', ['html'], function() {
.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() {
return gulp.src(['src/*.css'])
.pipe(concat('style.css'))
@@ -109,7 +115,7 @@ gulp.task('fonts', function() {
.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();
});

View File

@@ -1,6 +1,6 @@
{
"name": "docker-registry-ui",
"version": "0.2.2",
"version": "0.3.0",
"scripts": {
"build": "./node_modules/gulp/bin/gulp.js build"
},
@@ -9,26 +9,26 @@
"url": "https://github.com/Joxit/docker-registry-ui.git"
},
"author": "Jones Magloire (Joxit)",
"license": "AGPLv3",
"license": "AGPL-3.0",
"description": "A web UI for private docker registry",
"dependencies": {
},
"dependencies": {},
"devDependencies": {
"del": "^0.1.3",
"dialog-polyfill": "^0.4",
"del": "^3.0.0",
"gulp": "^3.9",
"gulp-clean-css": "^3.7.0",
"gulp-concat": "^2.6.0",
"gulp-filter": "^1.0.0",
"gulp-htmlmin": "^2.0.0",
"gulp-filter": "^5.0.1",
"gulp-htmlmin": "^3.0.0",
"gulp-if": "^2.0.0",
"gulp-license": "^1.1.0",
"gulp-clean-css": "^2.0.11",
"gulp-riot": "^0.5.2",
"gulp-uglify": "^1.0.0",
"gulp-riot": "^1.1.1",
"gulp-uglify": "^2.1.2",
"gulp-useref": "^3.0.0",
"material-design-lite": "^1.1",
"riot": "^2.3",
"pump": "^1.0.2",
"riot": "^3.7.0",
"riot-mui": "^0.1.1",
"riotgear-router": "^1.3.1",
"uglify-js-harmony": "^2.6.2"
"uglify-js": "^3.0.28",
"uglify-js-harmony": "^2.7.7"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 38 KiB

View File

@@ -20,8 +20,7 @@
<head>
<meta charset="UTF-8">
<!-- build:css vendor.css -->
<LINK href="../node_modules/dialog-polyfill/dialog-polyfill.css" rel="stylesheet" type="text/css">
<LINK href="../node_modules/material-design-lite/dist/material.min.css" rel="stylesheet" type="text/css">
<LINK href="../node_modules/riot-mui/build/styles/riot-mui.min.css" rel="stylesheet" type="text/css">
<!-- endbuild -->
<!-- build:css style.css -->
<LINK href="style.css" rel="stylesheet" type="text/css">
@@ -32,38 +31,11 @@
</head>
<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>
</div>
</main>
<change></change>
<add></add>
<remove></remove>
<footer class="mdl-mini-footer">
<div class="mdl-mini-footer__left-section">
<div class="mdl-logo">Docker Registry UI</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>
<app></app>
<!-- build:js scripts/vendor.js -->
<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/dialog-polyfill/dialog-polyfill.js"></script>
<script src="../node_modules/material-design-lite/dist/material.min.js"></script>
<script src="../node_modules/riot-mui/build/js/riot-mui.js"></script>
<!-- endbuild -->
<!-- build:js scripts/tags.js -->
<script src="tags/catalog.tag" type="riot/tag"></script>

View File

@@ -82,6 +82,6 @@ Http.prototype.send = function() {
Http.hasHeader = function(header) {
return this.getAllResponseHeaders().split('\n').some(function(h) {
return h.match(new RegExp('^' + header + ':'), 'i');
return new RegExp('^' + header + ':', 'i').test(h);
});
};

View File

@@ -15,8 +15,23 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
var registryUI = {}
registryUI.url = function() {
return registryUI.getRegistryServer(0);
registryUI.URL_QUERY_PARAM_REGEX = /[&?]url=/;
registryUI.URL_PARAM_REGEX = /^url=/;
registryUI.url = function(byPassQueryParam) {
if (!registryUI._url) {
var url = registryUI.getUrlQueryParam();
if (url) {
try {
registryUI._url = registryUI.decodeURI(url);
return registryUI._url;
} catch (e) {
console.log(e);
}
}
registryUI._url = registryUI.getRegistryServer(0);
}
return registryUI._url;
}
registryUI.getRegistryServer = function(i) {
try {
@@ -37,6 +52,9 @@ registryUI.addServer = function(url) {
return;
}
registryServer.push(url);
if (!registryUI._url) {
registryUI.updateHistory(url);
}
localStorage.setItem('registryServer', JSON.stringify(registryServer));
}
registryUI.changeServer = function(url) {
@@ -48,6 +66,7 @@ registryUI.changeServer = function(url) {
}
registryServer.splice(index, 1);
registryServer = [url].concat(registryServer);
registryUI.updateHistory(url);
localStorage.setItem('registryServer', JSON.stringify(registryServer));
}
registryUI.removeServer = function(url) {
@@ -59,13 +78,37 @@ registryUI.removeServer = function(url) {
}
registryServer.splice(index, 1);
localStorage.setItem('registryServer', JSON.stringify(registryServer));
if (url == registryUI.url()) {
registryUI.updateHistory(registryUI.getRegistryServer(0));
rg.router.go('home');
}
}
registryUI.updateHistory = function(url) {
history.pushState(null, '', (url ? '?url=' + registryUI.encodeURI(url) : '?') + window.location.hash);
registryUI._url = url;
}
registryUI.getUrlQueryParam = function () {
var search = window.location.search;
if (registryUI.URL_QUERY_PARAM_REGEX.test(search)) {
var param = search.split(/^\?|&/).find(function(param) {
return param && registryUI.URL_PARAM_REGEX.test(param);
});
return param ? param.replace(registryUI.URL_PARAM_REGEX, '') : param;
}
};
registryUI.encodeURI = function(url) {
return url.indexOf('&') < 0 ? window.encodeURIComponent(url) : btoa(url);
};
registryUI.decodeURI = function(url) {
return url.startsWith('http') ? window.decodeURIComponent(url) : atob(url);
};
registryUI.isImageRemoveActivated = true;
registryUI.catalog = {};
registryUI.taglist = {};
riot.mount('add');
riot.mount('change');
riot.mount('remove');
riot.mount('menu');
riot.mount('app');
riot.mount('*');

View File

@@ -18,28 +18,19 @@
html > body {
font-family: 'Roboto', 'Helvetica', 'Arial', sans-serif !important;
}
.mdl-mini-footer {
padding-top: 8px;
padding-bottom: 8px;
html, body {
margin: 0;
height: 100%;
}
.catalog, .taglist {
padding: 16px;
main {
margin-bottom: 100px;
}
.section-centerd {
margin: auto;
}
.mdl-data-table th {
font-size: 18px;
}
.mdl-data-table td {
font-size: 16px;
}
.full-table {
width: 100%;
border: none;
@@ -48,4 +39,272 @@ html > body {
.url {
font-size: 14px;
word-break: break-all;
}
.material-card-title-action a {
color: inherit;
text-decoration: none;
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/>.
-->
<add>
<dialog id="add-server-dialog" class="mdl-dialog">
<h4 class="mdl-dialog__title">Add your Server ?</h4>
<div class="mdl-dialog__content">
<div class="mdl-textfield mdl-js-textfield">
<input class="mdl-textfield__input" type="text" id="add-server-input">
<label class="mdl-textfield__label" for="add-server-input">Server url</label>
</div>
</div>
<div class="mdl-dialog__actions">
<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>
<material-popup>
<div class="material-popup-title">Add your Server ?</div>
<div class="material-popup-content">
<material-input onkeyup="{ registryUI.addTag.onkeyup }" placeholder="Server URL"></material-input>
<span>Write your URL without /v2</span>
</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>
</material-popup>
<script type="text/javascript">
registryUI.addTag = registryUI.addTag || {};
registryUI.addTag.update = this.update;
this.on('updated', function () {
componentHandler.upgradeElements(this['add-server-dialog']);
registryUI.addTag.dialog = registryUI.addTag.dialog || document.querySelector('#add-server-dialog');
registryUI.addTag.addServer = registryUI.addTag.tileServerList || registryUI.addTag.dialog.querySelector('#add-server-input');
if (!registryUI.addTag.dialog.showModal) {
dialogPolyfill.registerDialog(registryUI.addTag.dialog);
this.one('mount', function () {
registryUI.addTag.dialog = this.tags['material-popup'];
registryUI.addTag.dialog.getAddServer = function() {
return this.tags['material-input'] ? this.tags['material-input'].value : '';
}
this['add-server-input'].onkeyup = function (e) {
// if keyCode is Enter
if (e.keyCode == 13) {
registryUI.addTag.add();
}
};
});
registryUI.addTag.onkeyup = function (e) {
// if keyCode is Enter
if (e.keyCode == 13) {
registryUI.addTag.add();
}
};
registryUI.addTag.show = function () {
registryUI.addTag.dialog.showModal();
registryUI.addTag.dialog.open();
};
registryUI.addTag.add = function () {
if (registryUI.addTag.addServer.value && registryUI.addTag.addServer.value.length > 0) {
registryUI.addServer(registryUI.addTag.addServer.value);
if (registryUI.addTag.dialog.getAddServer().length > 0) {
registryUI.addServer(registryUI.addTag.dialog.getAddServer());
}
registryUI.addTag.addServer.value = '';
rg.router.go('home');
registryUI.addTag.dialog.close();
registryUI.addTag.close();
};
registryUI.addTag.close = function () {
registryUI.addTag.addServer.value = '';
registryUI.addTag.dialog.tags['material-input'].value = '';
registryUI.addTag.dialog.close();
};
registryUI.addTag.update();
</script>
</add>

View File

@@ -15,8 +15,34 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<app>
<catalog if="{!rg.router.current || rg.router.current.name == 'home'}"></catalog>
<taglist if="{rg.router.current.name == 'taglist'}"></taglist>
<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>
<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>
this.mixin('rg.router');
@@ -37,7 +63,14 @@
}
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();
</script>
</app>
</app>

View File

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

View File

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

View File

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

View File

@@ -16,7 +16,7 @@
-->
<remove-image>
<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>
<script type="text/javascript">
registryUI.removeImage = registryUI.removeImage || {}
@@ -28,7 +28,7 @@
registryUI.taglist.refresh();
if (this.status == 200) {
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;
}
var digest = this.getResponseHeader('Docker-Content-Digest');
@@ -36,23 +36,23 @@
oReq.addEventListener('loadend', function () {
if (this.status == 200 || this.status == 202) {
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) {
registryUI.taglist.createSnackbar('Digest not found');
registryUI.errorSnackbar('Digest not found');
} else {
registryUI.taglist.createSnackbar(this.responseText);
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.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();
} else if (this.status == 404) {
registryUI.taglist.createSnackbar('Manifest for' + name + ':' + tag + 'not found');
registryUI.errorSnackbar('Manifest for ' + name + ':' + tag + ' not found');
} else {
registryUI.taglist.createSnackbar(this.responseText);
registryUI.snackbar(this.responseText);
}
});
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/>.
-->
<remove>
<dialog id="remove-server-dialog" class="mdl-dialog">
<h4 class="mdl-dialog__title">Remove your Registry Server ?</h4>
<div class="mdl-dialog__content">
<div class="mdl-textfield mdl-js-textfield">
<ul class="mdl-list">
<li class="mdl-list__item" each="{ url in registryUI.getRegistryServer() }">
<span class="mdl-list__item-primary-content">
<a href="#" onClick="registryUI.removeTag.removeUrl('{url}');">
<i class="material-icons mdl-list__item-icon">delete</i>
</a>
<span class="url">{url}</span>
</span>
</li>
</ul>
</div>
</div>
<div class="mdl-dialog__actions">
<button type="button" class="mdl-button close" onClick="registryUI.removeTag.close();">Close</button>
</div>
</dialog>
<material-popup>
<div class="material-popup-title">Remove your Registry Server ?</div>
<div class="material-popup-content">
<ul class="list">
<li each="{ url in registryUI.getRegistryServer() }">
<span>
<a href="#" onClick="registryUI.removeTag.removeUrl('{url}');">
<i class="material-icons">delete</i>
</a>
<span class="url">{ url }</span>
</span>
</li>
</ul>
</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>
</material-popup>
<script type="text/javascript">
registryUI.removeTag = registryUI.removeTag || {}
registryUI.removeTag.update = this.update;
registryUI.removeTag.removeUrl = function (url) {
registryUI.removeServer(url);
registryUI.removeTag.update();
registryUI.removeTag.close();
};
registryUI.removeTag.close = function () {
@@ -50,15 +49,11 @@
};
registryUI.removeTag.show = function () {
registryUI.removeTag.update();
registryUI.removeTag.dialog.showModal();
registryUI.removeTag.dialog.open();
};
this.on('updated', function () {
registryUI.removeTag.dialog = this['remove-server-dialog'];
if (!registryUI.removeTag.dialog.showModal) {
dialogPolyfill.registerDialog(registryUI.removeTag.dialog);
}
this.one('mount', function () {
registryUI.removeTag.dialog = this.tags['material-popup'];
});
</script>
</remove>

View File

@@ -16,40 +16,35 @@
-->
<taglist>
<!-- Begin of tag -->
<div id="taglist-tag" class="taglist">
<div class="section-centerd mdl-card mdl-shadow--2dp mdl-cell--6-col">
<div class="mdl-card__title">
<a href="#" onclick="registryUI.taglist.back();">
<i class="material-icons mdl-list__item-icon">arrow_back</i>
</a>
<h2 class="mdl-card__title-text">Tags of { registryUI.url() + '/' + registryUI.taglist.name }</h2>
</div>
<div id="taglist-spinner" hide="{ registryUI.taglist.loadend }" class="mdl-spinner mdl-js-spinner section-centerd is-active"></div>
<table class="mdl-data-table mdl-js-data-table full-table" show="{ registryUI.taglist.loadend }" style="border: none;">
<thead>
<tr>
<th class="mdl-data-table__cell--non-numeric">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 show="{ registryUI.isImageRemoveActivated }" ></th>
</tr>
</thead>
<tbody>
<tr each="{ item in registryUI.taglist.tags }">
<td class="mdl-data-table__cell--non-numeric">{ registryUI.taglist.name }</td>
<td>{ item }</td>
<td show="{ registryUI.isImageRemoveActivated }" >
<remove-image name={ registryUI.taglist.name } tag={ item } />
</td>
</tr>
</tbody>
</table>
<material-card ref="taglist-tag" class="taglist">
<div class="material-card-title-action">
<a href="#" onclick="registryUI.taglist.back();">
<i class="material-icons">arrow_back</i>
</a>
<h2>Tags of { registryUI.url() + '/' + registryUI.taglist.name }</h2>
</div>
<div id="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 hide="{ registryUI.taglist.loadend }" class="spinner-wrapper">
<material-spinner></material-spinner>
</div>
</div>
<table show="{ registryUI.taglist.loadend }" style="border: none;">
<thead>
<tr>
<th class="material-card-th-left">Repository</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>
</tr>
</thead>
<tbody>
<tr each="{ item in registryUI.taglist.tags }">
<td class="material-card-th-left">{ registryUI.taglist.name }</td>
<td>{ item }</td>
<td show="{ registryUI.isImageRemoveActivated }">
<remove-image name={ registryUI.taglist.name } tag={ item }/>
</td>
</tr>
</tbody>
</table>
</material-card>
<script>
registryUI.taglist.instance = this;
registryUI.taglist.display = function () {
@@ -60,31 +55,20 @@
var oReq = new Http();
registryUI.taglist.name = name;
registryUI.taglist.instance.update();
registryUI.taglist.createSnackbar = function (msg) {
var snackbar = document.querySelector('#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 () {
registryUI.taglist.tags = [];
if (this.status == 200) {
registryUI.taglist.tags = JSON.parse(this.responseText).tags || [];
registryUI.taglist.tags.sort();
} else if (this.status == 404) {
registryUI.taglist.createSnackbar('Server not found');
registryUI.snackbar('Server not found', true);
} else {
registryUI.taglist.createSnackbar(this.responseText);
registryUI.snackbar(this.responseText, true);
}
});
oReq.addEventListener('error', function () {
registryUI.taglist.createSnackbar('An error occured');
registryUI.snackbar('An error occured', true);
registryUI.taglist.tags = [];
});
oReq.addEventListener('loadend', function () {
registryUI.taglist.loadend = true;
@@ -97,9 +81,6 @@
};
registryUI.taglist.display();
registryUI.taglist.instance.update();
this.on('updated', function () {
componentHandler.upgradeElements(this['taglist-tag']);
});
registryUI.taglist.reverse = function () {
if (registryUI.taglist.asc) {