mirror of
https://github.com/Joxit/docker-registry-ui.git
synced 2025-04-27 15:39:54 +03:00
feat(riot-v5): upgrade remove-image and copy-to-clipboard
This commit is contained in:
parent
9c303d32c7
commit
669c3399d0
9 changed files with 186 additions and 147 deletions
|
@ -20,7 +20,7 @@ const plugins = [
|
||||||
nodeResolve(),
|
nodeResolve(),
|
||||||
commonjs(),
|
commonjs(),
|
||||||
scss({ output: `./${output}/docker-registry-ui.css`, outputStyle: 'compressed' }),
|
scss({ output: `./${output}/docker-registry-ui.css`, outputStyle: 'compressed' }),
|
||||||
babel({ babelHelpers: 'bundled', presets: [['@babel/env', { useBuiltIns: 'usage' }]] }),
|
babel({ babelHelpers: 'bundled', presets: [['@babel/env', { useBuiltIns: 'usage', corejs: { version: "2" } }]] }),
|
||||||
html({ template: () => htmlUseref('./src/index.html') }),
|
html({ template: () => htmlUseref('./src/index.html') }),
|
||||||
copy({
|
copy({
|
||||||
targets: [
|
targets: [
|
||||||
|
|
|
@ -27,7 +27,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
catalog-elements-limit="{ state.catalogElementsLimit }" />
|
catalog-elements-limit="{ state.catalogElementsLimit }" />
|
||||||
</route>
|
</route>
|
||||||
<route path="{baseRoute}taglist/(.*)">
|
<route path="{baseRoute}taglist/(.*)">
|
||||||
<tag-list registry-url="{ state.registryUrl }" registry-name="{ state.name }"
|
<tag-list registry-url="{ state.registryUrl }" registry-name="{ state.name }" pull-url="{ state.pullUrl }"
|
||||||
image="{ router.getTagListImage() }" show-content-digest="{props.showContentDigest}"
|
image="{ router.getTagListImage() }" show-content-digest="{props.showContentDigest}"
|
||||||
is-image-remove-activated="{props.isImageRemoveActivated}"></tag-list>
|
is-image-remove-activated="{props.isImageRemoveActivated}"></tag-list>
|
||||||
</route>
|
</route>
|
||||||
|
@ -73,6 +73,13 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
''));
|
''));
|
||||||
this.state.name = props.name || stripHttps(props.registryUrl);
|
this.state.name = props.name || stripHttps(props.registryUrl);
|
||||||
this.state.catalogElementsLimit = props.catalogElementsLimit || 100000;
|
this.state.catalogElementsLimit = props.catalogElementsLimit || 100000;
|
||||||
|
this.state.pullUrl = this.pullUrl(props);
|
||||||
|
},
|
||||||
|
pullUrl(props) {
|
||||||
|
const url = props.pullUrl ||
|
||||||
|
(props.registryUrl && props.registryUrl.length > 0 && props.registryUrl) ||
|
||||||
|
window.location.host;
|
||||||
|
return stripHttps(url);
|
||||||
},
|
},
|
||||||
baseRoute: '/(\\?[^#]*)?(#!)?(/?)',
|
baseRoute: '/(\\?[^#]*)?(#!)?(/?)',
|
||||||
router,
|
router,
|
||||||
|
|
55
src/components/tag-list/copy-to-clipboard.riot
Normal file
55
src/components/tag-list/copy-to-clipboard.riot
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
<!--
|
||||||
|
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/>.
|
||||||
|
-->
|
||||||
|
<copy-to-clipboard>
|
||||||
|
<div class="copy-to-clipboard">
|
||||||
|
<input style="display: none; width: 1px; height: 1px;" value="{ state.dockerCmd }">
|
||||||
|
<material-button waves-center="true" rounded="true" waves-color="#ddd" onClick="{ copy }"
|
||||||
|
title="Copy pull command.">
|
||||||
|
<i class="material-icons">content_copy</i>
|
||||||
|
</material-button>
|
||||||
|
</div>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
onBeforeMount(props, state) {
|
||||||
|
const prefix = 'docker pull ' + props.pullUrl + '/' + props.image.name;
|
||||||
|
if (props.target === 'tag') {
|
||||||
|
state.dockerCmd = prefix + ':' + props.image.tag;
|
||||||
|
} else {
|
||||||
|
props.image.one('content-digest', (digest) => {
|
||||||
|
this.update({
|
||||||
|
dockerCmd: prefix + '@' + digest
|
||||||
|
})
|
||||||
|
});
|
||||||
|
props.image.trigger('get-content-digest');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
copy() {
|
||||||
|
if (!this.state.dockerCmd) {
|
||||||
|
// registryUI.showErrorCanNotReadContentDigest();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const copyText = this.$('input');
|
||||||
|
copyText.style.display = 'block';
|
||||||
|
copyText.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
copyText.style.display = 'none';
|
||||||
|
|
||||||
|
// registryUI.snackbar('`' + this.state.dockerCmd + '` has been copied to clipboard.')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</copy-to-clipboard>
|
78
src/components/tag-list/remove-image.riot
Normal file
78
src/components/tag-list/remove-image.riot
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
<!--
|
||||||
|
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/>.
|
||||||
|
-->
|
||||||
|
<remove-image>
|
||||||
|
<material-button waves-center="true" rounded="true" waves-color="#ddd" title="This will delete the image."
|
||||||
|
if="{ !props.multiDelete }" disabled="{ !state.digest }" onClick="{ deleteImage }">
|
||||||
|
<i class="material-icons">delete</i>
|
||||||
|
</material-button>
|
||||||
|
<material-checkbox if="{ props.multiDelete }" title="Select this tag to delete it." disabled="{ !state.digest }"
|
||||||
|
onChange="{ handleCheckboxChange }">
|
||||||
|
</material-checkbox>
|
||||||
|
<script>
|
||||||
|
import {
|
||||||
|
Http
|
||||||
|
} from '../../scripts/http';
|
||||||
|
import router from '../../scripts/router'
|
||||||
|
export default {
|
||||||
|
onBeforeMount(props, state) {
|
||||||
|
props.image.one('content-digest', (digest) => {
|
||||||
|
this.update({
|
||||||
|
digest
|
||||||
|
});
|
||||||
|
});
|
||||||
|
props.image.trigger('get-content-digest');
|
||||||
|
},
|
||||||
|
deleteImage(ignoreError) {
|
||||||
|
// registryUI.taglist.go(name);
|
||||||
|
deleteImage(this.props.image, this.props.registryUrl, ignoreError)
|
||||||
|
},
|
||||||
|
handleCheckboxChange(checked) {
|
||||||
|
this.props.handleCheckboxChange(checked, this.props.image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteImage(image, registryUrl, ignoreError) {
|
||||||
|
if (!image.digest) {
|
||||||
|
// registryUI.snackbar('Information for ' + name + ':' + tag + ' are not yet loaded.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const name = image.name;
|
||||||
|
const tag = image.tag;
|
||||||
|
const oReq = new Http();
|
||||||
|
oReq.addEventListener('loadend', function () {
|
||||||
|
if (this.status == 200 || this.status == 202) {
|
||||||
|
router.taglist(name);
|
||||||
|
// registryUI.snackbar('Deleting ' + name + ':' + tag +
|
||||||
|
// ' image. Run `registry garbage-collect config.yml` on your registry');
|
||||||
|
} else if (this.status == 404) {
|
||||||
|
// ignoreError || registryUI.errorSnackbar('Digest not found for this image in your registry.');
|
||||||
|
} else {
|
||||||
|
// registryUI.snackbar(this.responseText);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
oReq.open('DELETE', registryUrl + '/v2/' + name + '/manifests/' + image.digest);
|
||||||
|
oReq.setRequestHeader('Accept',
|
||||||
|
'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json');
|
||||||
|
oReq.addEventListener('error', function () {
|
||||||
|
registryUI.errorSnackbar(
|
||||||
|
'An error occurred when deleting image. Check if your server accept DELETE methods Access-Control-Allow-Methods: [\'DELETE\'].'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
oReq.send();
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</remove-image>
|
|
@ -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
|
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
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
@ -17,7 +17,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
<tag-list>
|
<tag-list>
|
||||||
<material-card class="header">
|
<material-card class="header">
|
||||||
<div class="material-card-title-action ">
|
<div class="material-card-title-action ">
|
||||||
<material-button waves-center="true" rounded="true" waves-color="#ddd" onclick="registryUI.home();">
|
<material-button waves-center="true" rounded="true" waves-color="#ddd" onClick="{ router.home }">
|
||||||
<i class="material-icons">arrow_back</i>
|
<i class="material-icons">arrow_back</i>
|
||||||
</material-button>
|
</material-button>
|
||||||
<h2>
|
<h2>
|
||||||
|
@ -38,7 +38,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
<tag-table if="{ state.loadend }" tags="{state.tags}" asc="{state.asc}" page="{ state.page }"
|
<tag-table if="{ state.loadend }" tags="{state.tags}" asc="{state.asc}" page="{ state.page }"
|
||||||
show-content-digest="{props.showContentDigest}" is-image-remove-activated="{props.isImageRemoveActivated}"
|
show-content-digest="{props.showContentDigest}" is-image-remove-activated="{props.isImageRemoveActivated}"
|
||||||
onReverseOrder="{ onReverseOrder }"></tag-table>
|
onReverseOrder="{ onReverseOrder }" registry-url="{ props.registryUrl }" pull-url="{ props.pullUrl }"></tag-table>
|
||||||
|
|
||||||
<pagination pages="{ getPageLabels(state.page, getNumPages(state.tags)) }" onPageUpdate="{onPageUpdate}"></pagination>
|
<pagination pages="{ getPageLabels(state.page, getNumPages(state.tags)) }" onPageUpdate="{onPageUpdate}"></pagination>
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
} from '../../scripts/utils'
|
} from '../../scripts/utils'
|
||||||
import Pagination from './pagination.riot'
|
import Pagination from './pagination.riot'
|
||||||
import TagTable from './tag-table.riot'
|
import TagTable from './tag-table.riot'
|
||||||
|
import router from '../../scripts/router'
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Pagination,
|
Pagination,
|
||||||
|
@ -151,7 +152,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
this.update();
|
this.update();
|
||||||
},
|
},
|
||||||
getPageLabels,
|
getPageLabels,
|
||||||
getNumPages
|
getNumPages,
|
||||||
|
router
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</tag-list>
|
</tag-list>
|
|
@ -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
|
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
|
it under the terms of the GNU Affero General Public License as published by
|
||||||
|
@ -28,11 +28,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
onclick="{() => props.onReverseOrder() }">Tag
|
onclick="{() => props.onReverseOrder() }">Tag
|
||||||
</th>
|
</th>
|
||||||
<th class="show-tag-history">History</th>
|
<th class="show-tag-history">History</th>
|
||||||
<th class="remove-tag { state.toDelete > 0 ? 'delete' : '' }" if="{ props.isImageRemoveActivated }">
|
<th class="remove-tag { state.toDelete.size > 0 ? 'delete' : '' }" if="{ props.isImageRemoveActivated }">
|
||||||
<material-checkbox ref="remove-tag-checkbox" class="indeterminate" if="{ state.toDelete === 0}"
|
<material-checkbox ref="remove-tag-checkbox" class="indeterminate" if="{ state.toDelete.size === 0}"
|
||||||
title="Toggle multi-delete. Alt+Click to select all tags."></material-checkbox>
|
title="Toggle multi-delete. Alt+Click to select all tags." onChange="{ onRemoveImageHeaderChange }">
|
||||||
|
</material-checkbox>
|
||||||
<material-button waves-center="true" rounded="true" waves-color="#ddd"
|
<material-button waves-center="true" rounded="true" waves-color="#ddd"
|
||||||
title="This will delete selected images." onclick="{ bulkDelete }" if="{ state.toDelete > 0 }">
|
title="This will delete selected images." onClick="{ bulkDelete }" if="{ state.toDelete.size > 0 }">
|
||||||
<i class="material-icons">delete</i>
|
<i class="material-icons">delete</i>
|
||||||
</material-button>
|
</material-button>
|
||||||
</th>
|
</th>
|
||||||
|
@ -48,17 +49,18 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
</td>
|
</td>
|
||||||
<td if="{ props.showContentDigest }">
|
<td if="{ props.showContentDigest }">
|
||||||
<image-content-digest image="{ image }" />
|
<image-content-digest image="{ image }" />
|
||||||
<copy-to-clipboard target="digest" image="{ image }" />
|
<copy-to-clipboard target="digest" image="{ image }" pull-url="{ props.pullUrl }" />
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<image-tag image="{ image }" />
|
<image-tag image="{ image }" />
|
||||||
<copy-to-clipboard target="tag" image="{ image }" />
|
<copy-to-clipboard target="tag" image="{ image }" pull-url="{ props.pullUrl }" />
|
||||||
</td>
|
</td>
|
||||||
<td class="show-tag-history">
|
<td class="show-tag-history">
|
||||||
<tag-history-button image="{ image }" />
|
<tag-history-button image="{ image }" />
|
||||||
</td>
|
</td>
|
||||||
<td if="{ props.isImageRemoveActivated }">
|
<td if="{ props.isImageRemoveActivated }" class="remove-tag">
|
||||||
<remove-image multi-delete="{ state.multiDelete }" image="{ image }" />
|
<remove-image multi-delete="{ state.multiDelete }" image="{ image }" registry-url="{ props.registryUrl }"
|
||||||
|
handleCheckboxChange="{ onRemoveImageChange }" />
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
@ -75,21 +77,44 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
import ImageSize from './image-size.riot';
|
import ImageSize from './image-size.riot';
|
||||||
import ImageTag from './image-tag.riot';
|
import ImageTag from './image-tag.riot';
|
||||||
import ImageContentDigest from './image-content-digest.riot';
|
import ImageContentDigest from './image-content-digest.riot';
|
||||||
|
import CopyToClipboard from './copy-to-clipboard.riot';
|
||||||
|
import RemoveImage, {
|
||||||
|
deleteImage
|
||||||
|
} from './remove-image.riot';
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
ImageDate,
|
ImageDate,
|
||||||
ImageSize,
|
ImageSize,
|
||||||
ImageTag,
|
ImageTag,
|
||||||
ImageContentDigest,
|
ImageContentDigest,
|
||||||
|
CopyToClipboard,
|
||||||
|
RemoveImage,
|
||||||
},
|
},
|
||||||
onBeforeMount(props) {
|
onBeforeMount(props) {
|
||||||
this.state = {
|
this.state = {
|
||||||
toDelete: 0,
|
toDelete: new Set(),
|
||||||
multiDelete: false
|
multiDelete: false,
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onMounted(props, state) {},
|
onMounted(props, state) {},
|
||||||
bulkDelete() {},
|
bulkDelete() {
|
||||||
|
this.state.toDelete.forEach(image => deleteImage(image, this.props.registryUrl, true))
|
||||||
|
},
|
||||||
|
onRemoveImageHeaderChange(checked) {
|
||||||
|
this.update({
|
||||||
|
multiDelete: checked
|
||||||
|
})
|
||||||
|
},
|
||||||
|
onRemoveImageChange(checked, image) {
|
||||||
|
if (checked) {
|
||||||
|
this.state.toDelete.add(image)
|
||||||
|
} else {
|
||||||
|
this.state.toDelete.delete(image)
|
||||||
|
}
|
||||||
|
this.update({
|
||||||
|
toDelete: this.state.toDelete
|
||||||
|
})
|
||||||
|
},
|
||||||
getPage
|
getPage
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -6,7 +6,7 @@ function baseUrl() {
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
home() {
|
home() {
|
||||||
router.pus(baseUrl());
|
router.push(baseUrl());
|
||||||
},
|
},
|
||||||
taglist(image) {
|
taglist(image) {
|
||||||
router.push(`${baseUrl()}#!/taglist/${image}`);
|
router.push(`${baseUrl()}#!/taglist/${image}`);
|
||||||
|
|
|
@ -1,50 +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/>.
|
|
||||||
-->
|
|
||||||
<copy-to-clipboard>
|
|
||||||
<div class="copy-to-clipboard">
|
|
||||||
<input ref="input" style="display: none; width: 1px; height: 1px;" value="{ this.dockerCmd }">
|
|
||||||
<material-button waves-center="true" rounded="true" waves-color="#ddd" onclick="{ this.copy }" title="Copy pull command.">
|
|
||||||
<i class="material-icons">content_copy</i>
|
|
||||||
</material-button>
|
|
||||||
</div>
|
|
||||||
<script type="text/javascript">
|
|
||||||
this.prefix = 'docker pull ' + registryUI.cleanName() + '/' + opts.image.name;
|
|
||||||
const self = this;
|
|
||||||
if (opts.target === 'tag') {
|
|
||||||
self.dockerCmd = self.prefix + ':' + opts.image.tag;
|
|
||||||
} else {
|
|
||||||
opts.image.one('content-digest', function (digest) {
|
|
||||||
self.dockerCmd = self.prefix + '@' + digest;
|
|
||||||
});
|
|
||||||
opts.image.trigger('get-content-digest');
|
|
||||||
}
|
|
||||||
|
|
||||||
this.copy = function () {
|
|
||||||
if (!self.dockerCmd) {
|
|
||||||
registryUI.showErrorCanNotReadContentDigest();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const copyText = this.refs['input'];
|
|
||||||
copyText.style.display = 'block';
|
|
||||||
copyText.select();
|
|
||||||
document.execCommand('copy');
|
|
||||||
copyText.style.display = 'none';
|
|
||||||
|
|
||||||
registryUI.snackbar('`' + this.dockerCmd + '` has been copied to clipboard.')
|
|
||||||
};
|
|
||||||
</script>
|
|
||||||
</copy-to-clipboard>
|
|
|
@ -1,78 +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/>.
|
|
||||||
-->
|
|
||||||
<remove-image>
|
|
||||||
<material-button waves-center="true" rounded="true" waves-color="#ddd" title="This will delete the image." if="{ !opts.multiDelete }" disabled="{ !this.digest }">
|
|
||||||
<i class="material-icons">delete</i>
|
|
||||||
</material-button>
|
|
||||||
<material-checkbox if="{ opts.multiDelete }" title="Select this tag to delete it." disabled="{ !this.digest }"></material-checkbox>
|
|
||||||
<script type="text/javascript">
|
|
||||||
const self = this;
|
|
||||||
|
|
||||||
this.on('updated', function() {
|
|
||||||
if (self.multiDelete == self.opts.multiDelete) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (self.tags['material-button']) {
|
|
||||||
self.delete = function(ignoreError) {
|
|
||||||
const name = self.opts.image.name;
|
|
||||||
const tag = self.opts.image.tag;
|
|
||||||
registryUI.taglist.go(name);
|
|
||||||
if (!self.digest) {
|
|
||||||
registryUI.snackbar('Information for ' + name + ':' + tag + ' are not yet loaded.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const oReq = new Http();
|
|
||||||
oReq.addEventListener('loadend', function() {
|
|
||||||
if (this.status == 200 || this.status == 202) {
|
|
||||||
registryUI.taglist.display()
|
|
||||||
registryUI.snackbar('Deleting ' + name + ':' + tag + ' image. Run `registry garbage-collect config.yml` on your registry');
|
|
||||||
} else if (this.status == 404) {
|
|
||||||
ignoreError || registryUI.errorSnackbar('Digest not found for this image in your registry.');
|
|
||||||
} else {
|
|
||||||
registryUI.snackbar(this.responseText);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
oReq.open('DELETE', registryUI.url() + '/v2/' + name + '/manifests/' + self.digest);
|
|
||||||
oReq.setRequestHeader('Accept', 'application/vnd.docker.distribution.manifest.v2+json, application/vnd.oci.image.manifest.v1+json');
|
|
||||||
oReq.addEventListener('error', function() {
|
|
||||||
registryUI.errorSnackbar('An error occurred when deleting image. Check if your server accept DELETE methods Access-Control-Allow-Methods: [\'DELETE\'].');
|
|
||||||
});
|
|
||||||
oReq.send();
|
|
||||||
};
|
|
||||||
self.tags['material-button'].root.onclick = function() {
|
|
||||||
self.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self.tags['material-checkbox']) {
|
|
||||||
if (!self.opts.multiDelete && self.tags['material-checkbox'].checked) {
|
|
||||||
self.tags['material-checkbox'].toggle();
|
|
||||||
}
|
|
||||||
self.tags['material-checkbox'].on('toggle', function() {
|
|
||||||
registryUI.taglist.instance.trigger('toggle-remove-image', this.checked);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
self.multiDelete = self.opts.multiDelete;
|
|
||||||
});
|
|
||||||
|
|
||||||
opts.image.one('content-digest', function(digest) {
|
|
||||||
self.digest = digest;
|
|
||||||
self.update();
|
|
||||||
});
|
|
||||||
opts.image.trigger('get-content-digest');
|
|
||||||
</script>
|
|
||||||
</remove-image>
|
|
Loading…
Add table
Add a link
Reference in a new issue