mirror of
https://github.com/Joxit/docker-registry-ui.git
synced 2025-04-27 23:50:01 +03:00
feat(riot-v5): upgrade all tag-history components
This commit is contained in:
parent
962592c54a
commit
a3276dcb79
10 changed files with 287 additions and 196 deletions
|
@ -31,6 +31,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
image="{ router.getTagListImage() }" show-content-digest="{props.showContentDigest}"
|
||||
is-image-remove-activated="{props.isImageRemoveActivated}"></tag-list>
|
||||
</route>
|
||||
<route path="{baseRoute}taghistory/(.*)">
|
||||
<tag-history registry-url="{ state.registryUrl }" registry-name="{ state.name }" pull-url="{ state.pullUrl }"
|
||||
image="{ router.getTagHistoryImage() }" tag="{ router.getTagHistoryTag() }"
|
||||
is-image-remove-activated="{props.isImageRemoveActivated}"></tag-history>
|
||||
</route>
|
||||
</router>
|
||||
</main>
|
||||
<footer>
|
||||
|
@ -55,7 +60,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
Route,
|
||||
} from '@riotjs/route'
|
||||
import Catalog from './catalog/catalog.riot';
|
||||
import TagList from './tag-list/tag-list.riot'
|
||||
import TagList from './tag-list/tag-list.riot';
|
||||
import TagHistory from './tag-history/tag-history.riot';
|
||||
import {
|
||||
stripHttps
|
||||
} from '../scripts/utils';
|
||||
|
@ -65,6 +71,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
components: {
|
||||
Catalog,
|
||||
TagList,
|
||||
TagHistory,
|
||||
Router,
|
||||
Route
|
||||
},
|
||||
|
|
40
src/components/tag-history/tag-history-element.riot
Normal file
40
src/components/tag-history/tag-history-element.riot
Normal file
|
@ -0,0 +1,40 @@
|
|||
<!--
|
||||
Copyright (C) 2016-2021 Jones Magloire @Joxit
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<tag-history-element class="{ state.key }">
|
||||
<div class="headline"><i class="material-icons">{ state.icon }</i>
|
||||
<p>{ state.name }</p>
|
||||
</div>
|
||||
<div class="value" if="{ state.value }"> { state.value }</div>
|
||||
<div class="value" each="{ value in state.values }" if="{ state.values }"> { value }</div>
|
||||
<script>
|
||||
import {
|
||||
getHistoryIcon
|
||||
} from '../../scripts/utils';
|
||||
export default {
|
||||
onBeforeMount(props, state) {
|
||||
state.key = props.entry.key;
|
||||
state.icon = getHistoryIcon(props.entry.key);
|
||||
state.name = props.entry.key.replace('_', ' ');
|
||||
if (props.value instanceof Array) {
|
||||
state.values = props.entry.value;
|
||||
} else {
|
||||
state.value = props.entry.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</tag-history-element>
|
184
src/components/tag-history/tag-history.riot
Normal file
184
src/components/tag-history/tag-history.riot
Normal file
|
@ -0,0 +1,184 @@
|
|||
<!--
|
||||
Copyright (C) 2016-2021 Jones Magloire @Joxit
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<tag-history>
|
||||
<material-card ref="tag-history-tag" class="tag-history header">
|
||||
<div class="material-card-title-action">
|
||||
<material-button waves-center="true" rounded="true" waves-color="#ddd" onClick="{ toTaglist }">
|
||||
<i class="material-icons">arrow_back</i>
|
||||
</material-button>
|
||||
<h2>
|
||||
History of { props.image }:{ props.tag } <i class="material-icons">history</i>
|
||||
</h2>
|
||||
</div>
|
||||
</material-card>
|
||||
<div if="{ !state.loadend }" class="spinner-wrapper">
|
||||
<material-spinner />
|
||||
</div>
|
||||
|
||||
<material-tabs if="{ state.archs }" useLine="true" tabs="{ state.archs }" tabchanged="{ onTabUpdate }" />
|
||||
|
||||
<material-card each="{ element in state.elements }" class="tag-history-element">
|
||||
<tag-history-element each="{ entry in element }" if="{ entry.value && entry.value.length > 0}" entry="{ entry }" />
|
||||
</material-card>
|
||||
<script>
|
||||
import {
|
||||
DockerImage
|
||||
} from '../../scripts/docker-image';
|
||||
import {
|
||||
bytesToSize
|
||||
} from '../../scripts/utils';
|
||||
import router from '../../scripts/router';
|
||||
import TagHistoryElement from './tag-history-element.riot'
|
||||
export default {
|
||||
components: {
|
||||
TagHistoryElement
|
||||
},
|
||||
onBeforeMount(props, state) {
|
||||
state.elements = [];
|
||||
state.image = new DockerImage(props.image, props.tag, true, props.registryUrl);
|
||||
state.image.fillInfo()
|
||||
state.image.on('blobs', this.processBlobs);
|
||||
state.image.on('list', this.multiArchList)
|
||||
},
|
||||
onTabUpdate() {
|
||||
const state = this.state;
|
||||
state.elements = []
|
||||
state.image.variants[idx] = state.image.variants[idx] ||
|
||||
new DockerImage(this.props.image, arch.digest);
|
||||
if (state.image.variants[idx].blobs) {
|
||||
return processBlobs(state.image.variants[idx].blobs);
|
||||
}
|
||||
state.image.variants[idx].fillInfo();
|
||||
state.image.variants[idx].on('blobs', processBlobs);
|
||||
},
|
||||
processBlobs(blobs) {
|
||||
const state = this.state;
|
||||
|
||||
function exec(elt) {
|
||||
const guiElements = [];
|
||||
for (var attribute in elt) {
|
||||
if (elt.hasOwnProperty(attribute) && attribute != 'empty_layer') {
|
||||
const value = elt[attribute];
|
||||
const guiElement = {
|
||||
"key": attribute,
|
||||
"value": modifySpecificAttributeTypes(attribute, value)
|
||||
};
|
||||
guiElements.push(guiElement);
|
||||
}
|
||||
}
|
||||
return guiElements.sort(eltSort);
|
||||
}
|
||||
const elements = new Array(blobs.history.length + 1);
|
||||
elements[0] = exec(getConfig(blobs));
|
||||
blobs.history.forEach(function (elt, i) {
|
||||
elements[blobs.history.length - i] = exec(elt)
|
||||
});
|
||||
this.update({
|
||||
elements,
|
||||
loadend: true
|
||||
});
|
||||
},
|
||||
multiArchList(manifests) {
|
||||
manifests = manifests.manifests || manifests;
|
||||
const archs = manifests.map(function (manifest) {
|
||||
return {
|
||||
title: manifest.platform.os + '/' + manifest.platform.architecture + (manifest.platform.variant ?
|
||||
manifest.platform.variant : ''),
|
||||
digest: manifest.digest
|
||||
}
|
||||
});
|
||||
this.update({
|
||||
archs
|
||||
});
|
||||
},
|
||||
toTaglist() {
|
||||
router.taglist(this.props.image);
|
||||
}
|
||||
}
|
||||
const eltIdx = function (e) {
|
||||
switch (e) {
|
||||
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) {
|
||||
return eltIdx(e1.key) - eltIdx(e2.key);
|
||||
};
|
||||
|
||||
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'
|
||||
case 'size':
|
||||
return bytesToSize(value);
|
||||
case 'Entrypoint':
|
||||
case 'Cmd':
|
||||
return (value || []).join(' ');
|
||||
case 'Labels':
|
||||
return Object.keys(value || {}).map(function (elt) {
|
||||
return value[elt] ? elt + '=' + value[elt] : '';
|
||||
});
|
||||
case 'Volumes':
|
||||
case 'ExposedPorts':
|
||||
return Object.keys(value);
|
||||
}
|
||||
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 && 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;
|
||||
delete res.Labels.maintainer;
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
</script>
|
||||
</tag-history>
|
|
@ -1,5 +1,5 @@
|
|||
<!--
|
||||
Copyright (C) 2016-2019 Jones Magloire @Joxit
|
||||
Copyright (C) 2016-2021 Jones Magloire @Joxit
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
|
@ -15,16 +15,16 @@ You should have received a copy of the GNU Affero General Public License
|
|||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<tag-history-button>
|
||||
<material-button ref="button" title="This will show the history of given tag" waves-center="true" rounded="true" waves-color="#ddd">
|
||||
<material-button title="This will show the history of given tag" waves-center="true" rounded="true" waves-color="#ddd"
|
||||
onClick="{ routeToHistory }">
|
||||
<i class="material-icons">history</i>
|
||||
</material-button>
|
||||
<script type="text/javascript">
|
||||
this.on('mount', function() {
|
||||
const self = this;
|
||||
this.refs.button.root.onclick = function() {
|
||||
registryUI.taghistory.go(self.opts.image.name, self.opts.image.tag);
|
||||
};
|
||||
});
|
||||
this.update()
|
||||
<script>
|
||||
import router from '../../scripts/router';
|
||||
export default {
|
||||
routeToHistory() {
|
||||
router.history(this.props.image.name, this.props.image.tag)
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</tag-history-button>
|
|
@ -78,6 +78,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
import ImageTag from './image-tag.riot';
|
||||
import ImageContentDigest from './image-content-digest.riot';
|
||||
import CopyToClipboard from './copy-to-clipboard.riot';
|
||||
import TagHistoryButton from './tag-history-button.riot';
|
||||
import RemoveImage, {
|
||||
deleteImage
|
||||
} from './remove-image.riot';
|
||||
|
@ -89,6 +90,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
ImageContentDigest,
|
||||
CopyToClipboard,
|
||||
RemoveImage,
|
||||
TagHistoryButton,
|
||||
},
|
||||
onBeforeMount(props) {
|
||||
this.state = {
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
* Copyright (C) 2016-2021 Jones Magloire @Joxit
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import { Http } from './http';
|
||||
import { isDigit, eventTransfer } from './utils';
|
||||
import observable from '@riotjs/observable';
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (C) 2016-2019 Jones Magloire @Joxit
|
||||
* Copyright (C) 2016-2021 Jones Magloire @Joxit
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
|
|
|
@ -1,3 +1,19 @@
|
|||
/*
|
||||
* Copyright (C) 2016-2021 Jones Magloire @Joxit
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import { router, getCurrentRoute } from '@riotjs/route';
|
||||
|
||||
function baseUrl() {
|
||||
|
@ -13,5 +29,14 @@ export default {
|
|||
},
|
||||
getTagListImage() {
|
||||
return getCurrentRoute().replace(/^.*(#!)?\/?taglist\//, '');
|
||||
}
|
||||
},
|
||||
history(image, tag) {
|
||||
router.push(`${baseUrl()}#!/taghistory/image/${image}/tag/${tag}`);
|
||||
},
|
||||
getTagHistoryImage() {
|
||||
return getCurrentRoute().replace(/^.*(#!)?\/?taghistory\/image\/(.*)\/tag\/(.*)\/?$/, '$2');
|
||||
},
|
||||
getTagHistoryTag() {
|
||||
return getCurrentRoute().replace(/^.*(#!)?\/?taghistory\/image\/(.*)\/tag\/(.*)\/?$/, '$3');
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
<!--
|
||||
Copyright (C) 2016-2019 Jones Magloire @Joxit
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<tag-history-element class="{entry.key}">
|
||||
<div class="headline"><i class="material-icons">{ registryUI.getHistoryIcon(entry.key) }</i>
|
||||
<p>{ entry.key.replace('_', ' ') }</p>
|
||||
</div>
|
||||
<div class="value" if={!(entry.value instanceof Array)}> { entry.value }</div>
|
||||
<div class="value" each={ e in entry.value } if={entry.value instanceof Array}> { e }</div>
|
||||
</tag-history-element>
|
|
@ -1,160 +0,0 @@
|
|||
<!--
|
||||
Copyright (C) 2016-2019 Jones Magloire @Joxit
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<tag-history>
|
||||
<material-card ref="tag-history-tag" class="tag-history header">
|
||||
<div class="material-card-title-action">
|
||||
<material-button waves-center="true" rounded="true" waves-color="#ddd">
|
||||
<i class="material-icons">arrow_back</i>
|
||||
</material-button>
|
||||
<h2>
|
||||
History of { registryUI.taghistory.image }:{ registryUI.taghistory.tag } <i class="material-icons">history</i>
|
||||
</h2>
|
||||
</div>
|
||||
</material-card>
|
||||
<div hide="{ registryUI.taghistory.loadend }" class="spinner-wrapper">
|
||||
<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}" />
|
||||
</material-card>
|
||||
<script type="text/javascript">
|
||||
const self = this;
|
||||
const eltIdx = function (e) {
|
||||
switch (e) {
|
||||
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) {
|
||||
return eltIdx(e1.key) - eltIdx(e2.key);
|
||||
};
|
||||
|
||||
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'
|
||||
case 'size':
|
||||
return registryUI.bytesToSize(value);
|
||||
case 'Entrypoint':
|
||||
case 'Cmd':
|
||||
return (value || []).join(' ');
|
||||
case 'Labels':
|
||||
return Object.keys(value || {}).map(function (elt) {
|
||||
return value[elt] ? elt + '=' + value[elt] : '';
|
||||
});
|
||||
case 'Volumes':
|
||||
case 'ExposedPorts':
|
||||
return Object.keys(value);
|
||||
}
|
||||
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 && 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;
|
||||
delete res.Labels.maintainer;
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
|
||||
const processBlobs = function (blobs) {
|
||||
function exec(elt) {
|
||||
const guiElements = [];
|
||||
for (var attribute in elt) {
|
||||
if (elt.hasOwnProperty(attribute) && attribute != 'empty_layer') {
|
||||
const value = elt[attribute];
|
||||
const guiElement = {
|
||||
"key": attribute,
|
||||
"value": modifySpecificAttributeTypes(attribute, value)
|
||||
};
|
||||
guiElements.push(guiElement);
|
||||
}
|
||||
}
|
||||
return guiElements.sort(eltSort);
|
||||
}
|
||||
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();
|
||||
};
|
||||
|
||||
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();
|
||||
};
|
||||
|
||||
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);
|
||||
};
|
||||
});
|
||||
|
||||
registryUI.taghistory.display();
|
||||
self.update();
|
||||
</script>
|
||||
</tag-history>
|
Loading…
Add table
Add a link
Reference in a new issue