mirror of
https://github.com/Joxit/docker-registry-ui.git
synced 2026-02-19 21:29:51 +00:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be813e6617 | ||
|
|
b4e6369a71 | ||
|
|
c9ede6fe61 | ||
|
|
656914f0d7 | ||
|
|
f8c5010fd1 | ||
|
|
42f19fcef7 |
@@ -12,6 +12,7 @@
|
||||
- Vladimir Kozyrev [@fieryvova](https://github.com/fieryvova)
|
||||
- Haibo Jia [@bluethon](https://github.com/bluethon)
|
||||
- Manuel Leitold [@agrippa1994](https://github.com/agrippa1994)
|
||||
- Murad [@muradheydarov](https://github.com/muradheydarov)
|
||||
|
||||
## Because committers are not the only contributors
|
||||
|
||||
@@ -29,4 +30,5 @@
|
||||
- Jernej K. [@Cvetk0](https://github.com/Cvetk0)
|
||||
- Cristian Posoiu [@cr1st1p](https://github.com/cr1st1p)
|
||||
- Sepp Zuther [@Herr-Sepp](https://github.com/Herr-Sepp)
|
||||
- Tomas Hulata [@tombokombo](https://github.com/tombokombo)
|
||||
- Tomas Hulata [@tombokombo](https://github.com/tombokombo)
|
||||
- Ben Jackson [@bjj](https://github.com/bjj)
|
||||
@@ -48,6 +48,7 @@ This web user interface uses [Riot](https://github.com/Riot/riot) the react-like
|
||||
- Add custom header via environment variable and file via `NGINX_PROXY_HEADER_*` (see [#89](https://github.com/Joxit/docker-registry-ui/pull/89)) **static interface**
|
||||
- Show/Hide content digest in taglist via `SHOW_CONTENT_DIGEST` (values are: [`true`, `false`], default: `true`) (see [#126](https://github.com/Joxit/docker-registry-ui/issues/126)).
|
||||
- Limit the number of elements in the image list via `CATALOG_ELEMENTS_LIMIT` (see [#127](https://github.com/Joxit/docker-registry-ui/pull/127)).
|
||||
- Multi arch support in history page (see [#130](https://github.com/Joxit/docker-registry-ui/issues/130) and [#134](https://github.com/Joxit/docker-registry-ui/pull/134))
|
||||
|
||||
## FAQ
|
||||
|
||||
@@ -185,6 +186,7 @@ http:
|
||||
headers:
|
||||
Access-Control-Allow-Origin: ['<your docker-registry-ui url>']
|
||||
Access-Control-Allow-Credentials: [true]
|
||||
Access-Control-Allow-Headers: ['Authorization', 'Accept']
|
||||
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS'] # Optional
|
||||
```
|
||||
|
||||
@@ -231,7 +233,7 @@ http:
|
||||
X-Content-Type-Options: [nosniff]
|
||||
Access-Control-Allow-Origin: ['http://127.0.0.1:8001']
|
||||
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
|
||||
Access-Control-Allow-Headers: ['Authorization']
|
||||
Access-Control-Allow-Headers: ['Authorization', 'Accept']
|
||||
Access-Control-Max-Age: [1728000]
|
||||
Access-Control-Allow-Credentials: [true]
|
||||
Access-Control-Expose-Headers: ['Docker-Content-Digest']
|
||||
|
||||
2
dist/scripts/docker-registry-ui-static.js
vendored
2
dist/scripts/docker-registry-ui-static.js
vendored
File diff suppressed because one or more lines are too long
2
dist/scripts/docker-registry-ui.js
vendored
2
dist/scripts/docker-registry-ui.js
vendored
File diff suppressed because one or more lines are too long
2
dist/style.css
vendored
2
dist/style.css
vendored
File diff suppressed because one or more lines are too long
@@ -63,7 +63,7 @@ registry:
|
||||
image:
|
||||
registry: docker.io
|
||||
repository: registry
|
||||
tag: 2.6.2
|
||||
tag: 2.7.1
|
||||
pullPolicy: Always
|
||||
probe:
|
||||
liveness: true
|
||||
|
||||
@@ -2,7 +2,7 @@ version: '2'
|
||||
|
||||
services:
|
||||
registry-srv:
|
||||
image: registry:2.7.1
|
||||
image: registry:2.7
|
||||
restart: always
|
||||
volumes:
|
||||
- storage:/var/lib/registry
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
version: '2.0'
|
||||
services:
|
||||
registry:
|
||||
image: registry:2.6.2
|
||||
image: registry:2.7
|
||||
volumes:
|
||||
- ./registry-data:/var/lib/registry
|
||||
networks:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
version: '2.0'
|
||||
services:
|
||||
registry:
|
||||
image: registry:2.6.2
|
||||
image: registry:2.7
|
||||
volumes:
|
||||
- ./registry-data:/var/lib/registry
|
||||
networks:
|
||||
|
||||
@@ -28,7 +28,7 @@ http:
|
||||
X-Content-Type-Options: [nosniff]
|
||||
Access-Control-Allow-Origin: ['http://127.0.0.1']
|
||||
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
|
||||
Access-Control-Allow-Headers: ['Authorization']
|
||||
Access-Control-Allow-Headers: ['Authorization', 'Accept']
|
||||
Access-Control-Max-Age: [1728000]
|
||||
Access-Control-Allow-Credentials: [true]
|
||||
Access-Control-Expose-Headers: ['Docker-Content-Digest']
|
||||
|
||||
@@ -15,6 +15,7 @@ http:
|
||||
X-Content-Type-Options: [nosniff]
|
||||
Access-Control-Allow-Origin: ['*']
|
||||
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
|
||||
Access-Control-Allow-Headers: ['Accept']
|
||||
Access-Control-Expose-Headers: ['Docker-Content-Digest']
|
||||
health:
|
||||
storagedriver:
|
||||
|
||||
@@ -2,7 +2,7 @@ version: '2'
|
||||
|
||||
services:
|
||||
registry-srv:
|
||||
image: registry:latest
|
||||
image: registry:2.7
|
||||
restart: always
|
||||
volumes:
|
||||
- storage:/var/lib/registry
|
||||
|
||||
@@ -25,7 +25,7 @@ data:
|
||||
X-Content-Type-Options: [nosniff]
|
||||
Access-Control-Allow-Origin: ['*']
|
||||
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
|
||||
Access-Control-Allow-Headers: ['Authorization']
|
||||
Access-Control-Allow-Headers: ['Authorization', 'Accept']
|
||||
Access-Control-Max-Age: [1728000]
|
||||
Access-Control-Allow-Credentials: [true]
|
||||
Access-Control-Expose-Headers: ['Docker-Content-Digest']
|
||||
|
||||
@@ -28,7 +28,7 @@ spec:
|
||||
claimName: docker-registry
|
||||
containers:
|
||||
- name: registry
|
||||
image: "docker.io/registry:2.6.2"
|
||||
image: "docker.io/registry:2.7"
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- name: registry
|
||||
|
||||
@@ -15,7 +15,7 @@ http:
|
||||
X-Content-Type-Options: [nosniff]
|
||||
Access-Control-Allow-Origin: ['http://localhost']
|
||||
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
|
||||
Access-Control-Allow-Headers: ['Authorization']
|
||||
Access-Control-Allow-Headers: ['Authorization', 'Accept']
|
||||
Access-Control-Max-Age: [1728000]
|
||||
Access-Control-Allow-Credentials: [true]
|
||||
Access-Control-Expose-Headers: ['Docker-Content-Digest']
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
version: '3.1'
|
||||
services:
|
||||
registry:
|
||||
image: registry:2.6.2
|
||||
image: registry:2.7
|
||||
volumes:
|
||||
- /opt/docker-registry:/var/lib/registry
|
||||
environment:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
version: '2.0'
|
||||
services:
|
||||
registry:
|
||||
image: registry:2.6.2
|
||||
image: registry:2.7
|
||||
volumes:
|
||||
- ./registry-data:/var/lib/registry
|
||||
- ./registry-config/credentials.yml:/etc/docker/registry/config.yml
|
||||
|
||||
@@ -15,7 +15,7 @@ http:
|
||||
X-Content-Type-Options: [nosniff]
|
||||
Access-Control-Allow-Origin: ['http://localhost']
|
||||
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
|
||||
Access-Control-Allow-Headers: ['Authorization']
|
||||
Access-Control-Allow-Headers: ['Authorization', 'Accept']
|
||||
Access-Control-Max-Age: [1728000]
|
||||
Access-Control-Allow-Credentials: [true]
|
||||
Access-Control-Expose-Headers: ['Docker-Content-Digest']
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
version: '2.0'
|
||||
services:
|
||||
registry:
|
||||
image: registry:2.6.2
|
||||
image: registry:2.7
|
||||
volumes:
|
||||
- ./registry-data:/var/lib/registry
|
||||
networks:
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
version: '2.0'
|
||||
services:
|
||||
registry:
|
||||
image: registry:2.6.2
|
||||
image: registry:2.7
|
||||
ports:
|
||||
- 5000:5000
|
||||
volumes:
|
||||
|
||||
@@ -15,7 +15,7 @@ http:
|
||||
X-Content-Type-Options: [nosniff]
|
||||
Access-Control-Allow-Origin: ['http://localhost']
|
||||
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
|
||||
Access-Control-Allow-Headers: ['Authorization']
|
||||
Access-Control-Allow-Headers: ['Authorization', 'Accept']
|
||||
Access-Control-Max-Age: [1728000]
|
||||
Access-Control-Allow-Credentials: [true]
|
||||
Access-Control-Expose-Headers: ['Docker-Content-Digest']
|
||||
|
||||
@@ -15,7 +15,7 @@ http:
|
||||
X-Content-Type-Options: [nosniff]
|
||||
Access-Control-Allow-Origin: ['http://localhost']
|
||||
Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE']
|
||||
Access-Control-Allow-Headers: ['Authorization']
|
||||
Access-Control-Allow-Headers: ['Authorization', 'Accept']
|
||||
Access-Control-Max-Age: [1728000]
|
||||
Access-Control-Allow-Credentials: [true]
|
||||
Access-Control-Expose-Headers: ['Docker-Content-Digest']
|
||||
@@ -1,7 +1,7 @@
|
||||
version: '2.0'
|
||||
services:
|
||||
registry:
|
||||
image: registry:2.6.2
|
||||
image: registry:2.7
|
||||
ports:
|
||||
- 5000:5000
|
||||
volumes:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "docker-registry-ui",
|
||||
"version": "1.4.9",
|
||||
"version": "1.5.0",
|
||||
"scripts": {
|
||||
"build": "./node_modules/gulp/bin/gulp.js build",
|
||||
"build:electron": "npm run build && cd examples/electron && npm install && npm run dist"
|
||||
|
||||
@@ -119,3 +119,9 @@ registryUI.stripHttps = function (url) {
|
||||
}
|
||||
return url.replace(/^https?:\/\//, '');
|
||||
};
|
||||
|
||||
registryUI.eventTransfer = function(from, to) {
|
||||
from.on('*', function(event, param) {
|
||||
to.trigger(event, param);
|
||||
})
|
||||
}
|
||||
@@ -48,7 +48,7 @@ main {
|
||||
font-weight: inherit;
|
||||
}
|
||||
|
||||
material-card, pagination .conatianer {
|
||||
material-card, material-tabs, pagination .conatianer {
|
||||
max-width: 95%;
|
||||
margin: auto;
|
||||
margin-top: 20px;
|
||||
@@ -68,11 +68,34 @@ pagination .conatianer .pagination-centered {
|
||||
|
||||
/* 1515px * 0.95 = 1440px */
|
||||
@media screen and (min-width: 1515px){
|
||||
material-card, pagination .conatianer {
|
||||
material-card, material-tabs, pagination .conatianer {
|
||||
max-width: 1440px;
|
||||
}
|
||||
}
|
||||
|
||||
material-tabs {
|
||||
display: block;
|
||||
-webkit-box-shadow: 0 2px 5px 0 rgba(0,0,0,.16), 0 2px 10px 0 rgba(0,0,0,.12);
|
||||
-ms-box-shadow: 0 2px 5px 0 rgba(0,0,0,.16),0 2px 10px 0 rgba(0,0,0,.12);
|
||||
-moz-box-shadow: 0 2px 5px 0 rgba(0,0,0,.16),0 2px 10px 0 rgba(0,0,0,.12);
|
||||
-o-box-shadow: 0 2px 5px 0 rgba(0,0,0,.16),0 2px 10px 0 rgba(0,0,0,.12);
|
||||
box-shadow: 0 2px 5px 0 rgba(0,0,0,.16), 0 2px 10px 0 rgba(0,0,0,.12);
|
||||
}
|
||||
|
||||
material-tabs material-button,
|
||||
material-tabs material-button .content .text {
|
||||
background-color: #fff;
|
||||
color: #aaa;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
material-tabs .line-wrapper .line {
|
||||
background-color: #25313b;
|
||||
}
|
||||
material-tabs material-button.selected .content .text {
|
||||
color: #25313b;
|
||||
}
|
||||
|
||||
material-spinner {
|
||||
align-self: center;
|
||||
}
|
||||
@@ -474,6 +497,7 @@ tag-history-element {
|
||||
display: block;
|
||||
padding: 20px;
|
||||
min-width: 100px;
|
||||
min-height: 3em;
|
||||
width: 420px;
|
||||
float: left;
|
||||
overflow-x: auto;
|
||||
|
||||
@@ -118,9 +118,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
return char >= '0' && char <= '9';
|
||||
};
|
||||
|
||||
registryUI.DockerImage = function(name, tag) {
|
||||
registryUI.DockerImage = function(name, tag, list) {
|
||||
this.name = name;
|
||||
this.tag = tag;
|
||||
this.list = list;
|
||||
this.chars = 0;
|
||||
riot.observable(this);
|
||||
this.on('get-size', function() {
|
||||
@@ -192,6 +193,15 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
oReq.addEventListener('loadend', function() {
|
||||
if (this.status == 200 || this.status == 202) {
|
||||
const response = JSON.parse(this.responseText);
|
||||
if (response.mediaType === 'application/vnd.docker.distribution.manifest.list.v2+json') {
|
||||
self.trigger('list', response);
|
||||
const manifest = response.manifests[0];
|
||||
const image = new registryUI.DockerImage(self.name, manifest.digest)
|
||||
registryUI.eventTransfer(image, self)
|
||||
image.fillInfo()
|
||||
self.variants = [image];
|
||||
return;
|
||||
}
|
||||
self.size = response.layers.reduce(function(acc, e) {
|
||||
return acc + e.size;
|
||||
}, 0);
|
||||
@@ -214,7 +224,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
}
|
||||
});
|
||||
oReq.open('GET', registryUI.url() + '/v2/' + self.name + '/manifests/' + self.tag);
|
||||
oReq.setRequestHeader('Accept', 'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json');
|
||||
oReq.setRequestHeader('Accept', 'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json'
|
||||
+ (self.list ? ', application/vnd.docker.distribution.manifest.list.v2+json' : ''));
|
||||
oReq.send();
|
||||
};
|
||||
|
||||
|
||||
@@ -22,7 +22,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
this.on('mount', function() {
|
||||
const self = this;
|
||||
this.refs.button.root.onclick = function() {
|
||||
registryUI.taghistory._image = self.opts.image;
|
||||
registryUI.taghistory.go(self.opts.image.name, self.opts.image.tag);
|
||||
};
|
||||
});
|
||||
|
||||
@@ -26,46 +26,48 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
</div>
|
||||
</material-card>
|
||||
<div hide="{ registryUI.taghistory.loadend }" class="spinner-wrapper">
|
||||
<material-spinner/>
|
||||
<material-spinner />
|
||||
</div>
|
||||
|
||||
<material-tabs if="{ this.archs }" useLine="true" tabs="{ this.archs }" tabchanged="{ this.tabchanged }" />
|
||||
|
||||
<material-card each="{ guiElement in this.elements }" class="tag-history-element">
|
||||
<tag-history-element each="{ entry in guiElement }" if="{ entry.value && entry.value.length > 0}"/>
|
||||
<tag-history-element each="{ entry in guiElement }" if="{ entry.value && entry.value.length > 0}" />
|
||||
</material-card>
|
||||
<script type="text/javascript">
|
||||
const self = this;
|
||||
const eltIdx = function(e) {
|
||||
const eltIdx = function (e) {
|
||||
switch (e) {
|
||||
case 'id': return 1;
|
||||
case 'created': return 2;
|
||||
case 'created_by': return 3;
|
||||
case 'size': return 4;
|
||||
case 'os': return 5;
|
||||
case 'architecture': return 6;
|
||||
case 'created': return 1;
|
||||
case 'created_by': return 2;
|
||||
case 'size': return 3;
|
||||
case 'os': return 4;
|
||||
case 'architecture': return 5;
|
||||
case 'id': return 6;
|
||||
case 'linux': return 7;
|
||||
case 'docker_version': return 8;
|
||||
default: return 10;
|
||||
}
|
||||
};
|
||||
|
||||
const eltSort = function(e1, e2) {
|
||||
const eltSort = function (e1, e2) {
|
||||
return eltIdx(e1.key) - eltIdx(e2.key);
|
||||
};
|
||||
|
||||
const modifySpecificAttributeTypes = function(attribute, value) {
|
||||
const modifySpecificAttributeTypes = function (attribute, value) {
|
||||
switch (attribute) {
|
||||
case 'created':
|
||||
return new Date(value).toLocaleString();
|
||||
case 'created_by':
|
||||
const cmd = value.match(/\/bin\/sh *-c *#\(nop\) *([A-Z]+)/);
|
||||
return (cmd && cmd [1]) || 'RUN'
|
||||
return (cmd && cmd[1]) || 'RUN'
|
||||
case 'size':
|
||||
return registryUI.bytesToSize(value);
|
||||
case 'Entrypoint':
|
||||
case 'Cmd':
|
||||
return (value || []).join(' ');
|
||||
case 'Labels':
|
||||
return Object.keys(value || {}).map(function(elt) {
|
||||
return Object.keys(value || {}).map(function (elt) {
|
||||
return value[elt] ? elt + '=' + value[elt] : '';
|
||||
});
|
||||
case 'Volumes':
|
||||
@@ -75,14 +77,17 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
return value || '';
|
||||
};
|
||||
|
||||
const getConfig = function(blobs) {
|
||||
const res = ['architecture', 'User', 'created', 'docker_version', 'os', 'Cmd', 'Entrypoint', 'Env', 'Labels', 'User', 'Volumes', 'WorkingDir', 'author', 'id', 'ExposedPorts'].reduce(function(acc, e) {
|
||||
const value = blobs[e] || blobs.config[e];
|
||||
if (value) {
|
||||
acc[e] = value;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
const getConfig = function (blobs) {
|
||||
const res = ['architecture', 'User', 'created', 'docker_version', 'os', 'Cmd', 'Entrypoint', 'Env', 'Labels', 'User', 'Volumes', 'WorkingDir', 'author', 'id', 'ExposedPorts']
|
||||
.reduce(function (acc, e) {
|
||||
const value = blobs[e] || blobs.config[e];
|
||||
if (value && e === 'architecture' && blobs.variant) {
|
||||
acc[e] = value + blobs.variant;
|
||||
} else if (value) {
|
||||
acc[e] = value;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
if (!res.author && (res.Labels && res.Labels.maintainer)) {
|
||||
res.author = blobs.config.Labels.maintainer;
|
||||
@@ -92,7 +97,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
return res;
|
||||
};
|
||||
|
||||
const processBlobs = function(blobs) {
|
||||
const processBlobs = function (blobs) {
|
||||
function exec(elt) {
|
||||
const guiElements = [];
|
||||
for (var attribute in elt) {
|
||||
@@ -107,27 +112,44 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
}
|
||||
return guiElements.sort(eltSort);
|
||||
}
|
||||
|
||||
self.elements.push(exec(getConfig(blobs)));
|
||||
blobs.history.reverse().forEach(function(elt) { self.elements.push(exec(elt)) });
|
||||
self.elements = new Array(blobs.history.length + 1);
|
||||
self.elements[0] = exec(getConfig(blobs));
|
||||
blobs.history.forEach(function (elt, i) { self.elements[blobs.history.length - i] = exec(elt) });
|
||||
registryUI.taghistory.loadend = true;
|
||||
self.update();
|
||||
};
|
||||
|
||||
registryUI.taghistory.display = function() {
|
||||
self.elements = []
|
||||
const blobs = registryUI.taghistory._image && registryUI.taghistory._image.blobs;
|
||||
if (blobs) {
|
||||
window.scrollTo(0, 0);
|
||||
return processBlobs(blobs);
|
||||
}
|
||||
const image = new registryUI.DockerImage(registryUI.taghistory.image, registryUI.taghistory.tag);
|
||||
image.fillInfo()
|
||||
image.on('blobs', processBlobs);
|
||||
const multiArchList = function (manifests) {
|
||||
manifests = manifests.manifests || manifests;
|
||||
self.archs = manifests.map(function (manifest) {
|
||||
return {
|
||||
title: manifest.platform.os + '/' + manifest.platform.architecture + (manifest.platform.variant ? manifest.platform.variant : ''),
|
||||
digest: manifest.digest
|
||||
}
|
||||
})
|
||||
self.update();
|
||||
};
|
||||
|
||||
this.on('mount', function() {
|
||||
self.refs['tag-history-tag'].tags['material-button'].root.onclick = function() {
|
||||
self.tabchanged = function (arch, idx) {
|
||||
self.elements = []
|
||||
self.image.variants[idx] = self.image.variants[idx] || new registryUI.DockerImage(registryUI.taghistory.image, arch.digest);
|
||||
if (self.image.variants[idx].blobs) {
|
||||
return processBlobs(self.image.variants[idx].blobs);
|
||||
}
|
||||
self.image.variants[idx].fillInfo();
|
||||
self.image.variants[idx].on('blobs', processBlobs);
|
||||
};
|
||||
|
||||
registryUI.taghistory.display = function () {
|
||||
self.elements = []
|
||||
self.image = new registryUI.DockerImage(registryUI.taghistory.image, registryUI.taghistory.tag, true);
|
||||
self.image.fillInfo()
|
||||
self.image.on('blobs', processBlobs);
|
||||
self.image.on('list', multiArchList)
|
||||
};
|
||||
|
||||
this.on('mount', function () {
|
||||
self.refs['tag-history-tag'].tags['material-button'].root.onclick = function () {
|
||||
registryUI.taglist.go(registryUI.taghistory.image);
|
||||
};
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user