From e065298eedbecc6fb57318d079014e1c07a96264 Mon Sep 17 00:00:00 2001 From: Joxit Date: Sat, 24 Apr 2021 22:35:10 +0200 Subject: [PATCH 1/2] feat(confirm-delete): add dialog for confirmation of multiple image delete --- package.json | 2 +- .../dialogs/confirm-delete-image.riot | 108 ++++++++++++++++++ src/components/tag-list/remove-image.riot | 41 ------- src/components/tag-list/tag-table.riot | 21 ++-- 4 files changed, 123 insertions(+), 49 deletions(-) create mode 100644 src/components/dialogs/confirm-delete-image.riot diff --git a/package.json b/package.json index 2c658b7..3863a28 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "core-js": "^3.9.1", "js-beautify": "^1.13.0", "riot": "^5.3.1", - "riot-mui": "joxit/riot-5-mui#03c37c7", + "riot-mui": "joxit/riot-5-mui#ba273d7", "rollup": "^2.34.2", "rollup-plugin-app-utils": "^1.0.6", "rollup-plugin-commonjs": "^10.1.0", diff --git a/src/components/dialogs/confirm-delete-image.riot b/src/components/dialogs/confirm-delete-image.riot new file mode 100644 index 0000000..b3d902b --- /dev/null +++ b/src/components/dialogs/confirm-delete-image.riot @@ -0,0 +1,108 @@ + + + +
These images will be deleted
+
+
    +
  • { image.name }:{ image.tag }
  • +
+
+
+ + Delete + + + Cancel + +
+
+ + +
\ No newline at end of file diff --git a/src/components/tag-list/remove-image.riot b/src/components/tag-list/remove-image.riot index 899386c..49c1bea 100644 --- a/src/components/tag-list/remove-image.riot +++ b/src/components/tag-list/remove-image.riot @@ -52,46 +52,5 @@ along with this program. If not, see . this.props.handleCheckboxChange(checked, this.props.image); } } - - export function deleteImage(image, opts) { - const { - registryUrl, - ignoreError, - onNotify, - onAuthentication - } = opts; - if (!image.digest) { - onNotify(`Information for ${name}:${tag} are not yet loaded.`); - return; - } - const name = image.name; - const tag = image.tag; - const oReq = new Http({ - onAuthentication: onAuthentication - }); - oReq.addEventListener('loadend', function () { - if (this.status == 200 || this.status == 202) { - router.taglist(name); - onNotify(`Deleting ${name}:${tag} image. Run \`registry garbage-collect config.yml\` on your registry`); - } else if (this.status == 404) { - ignoreError || onNotify({ - message: 'Digest not found for this image in your registry.', - isError: true - }); - } else { - onNotify(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 () { - onNotify({ - message: 'An error occurred when deleting image. Check if your server accept DELETE methods Access-Control-Allow-Methods: [\'DELETE\'].', - isError: true - }); - }); - oReq.send(); - } \ No newline at end of file diff --git a/src/components/tag-list/tag-table.riot b/src/components/tag-list/tag-table.riot index d69fc8d..ef7bd6e 100644 --- a/src/components/tag-list/tag-table.riot +++ b/src/components/tag-list/tag-table.riot @@ -15,6 +15,9 @@ You should have received a copy of the GNU Affero General Public License along with this program. If not, see . --> + @@ -87,12 +90,11 @@ along with this program. If not, see . 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'; + import RemoveImage from './remove-image.riot'; import { matchSearch } from '../search-bar.riot'; + import ConfirmDeleteImage from '../dialogs/confirm-delete-image.riot'; export default { components: { ImageDate, @@ -102,6 +104,7 @@ along with this program. If not, see . CopyToClipboard, RemoveImage, TagHistoryButton, + ConfirmDeleteImage, }, onBeforeMount(props) { this.state = { @@ -117,10 +120,14 @@ along with this program. If not, see . state.page = props.page }, bulkDelete() { - this.state.toDelete.forEach(image => deleteImage(image, { - ...this.props, - ignoreError: true - })) + this.update({ + confirmDeleteImage: true + }) + }, + onConfirmDeleteImageClick() { + this.update({ + confirmDeleteImage: false + }) }, onRemoveImageHeaderChange(checked, event) { if (event.altKey === true) { From 29cd2b7a8f2347b2e8227b213ae9bbe7e9486865 Mon Sep 17 00:00:00 2001 From: Joxit Date: Mon, 26 Apr 2021 22:31:11 +0200 Subject: [PATCH 2/2] feat(confirm-delete): add dialog for single image delete --- src/components/tag-list/remove-image.riot | 15 ++++--- src/components/tag-list/tag-table.riot | 51 ++++++++++++++++++----- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/src/components/tag-list/remove-image.riot b/src/components/tag-list/remove-image.riot index 49c1bea..1e086d8 100644 --- a/src/components/tag-list/remove-image.riot +++ b/src/components/tag-list/remove-image.riot @@ -27,6 +27,11 @@ along with this program. If not, see . Http } from '../../scripts/http'; import router from '../../scripts/router' + import { + ACTION_CHECK_TO_DELETE, + ACTION_UNCHECK_TO_DELETE, + ACTION_DELETE_IMAGE + } from './tag-table.riot'; export default { onBeforeMount(props, state) { state.checked = props.checked; @@ -42,14 +47,12 @@ along with this program. If not, see . onBeforeUpdate(props, state) { state.checked = props.checked; }, - deleteImage(ignoreError) { - deleteImage(this.props.image, { - ...this.props, - ignoreError - }) + deleteImage() { + this.props.handleCheckboxChange(ACTION_DELETE_IMAGE, this.props.image); }, handleCheckboxChange(checked) { - this.props.handleCheckboxChange(checked, this.props.image); + const action = checked ? ACTION_CHECK_TO_DELETE : ACTION_UNCHECK_TO_DELETE; + this.props.handleCheckboxChange(action, this.props.image); } } diff --git a/src/components/tag-list/tag-table.riot b/src/components/tag-list/tag-table.riot index ef7bd6e..d0dff05 100644 --- a/src/components/tag-list/tag-table.riot +++ b/src/components/tag-list/tag-table.riot @@ -39,12 +39,15 @@ along with this program. If not, see . onclick="{ onReverseOrder }">Tag - @@ -95,6 +98,10 @@ along with this program. If not, see . matchSearch } from '../search-bar.riot'; import ConfirmDeleteImage from '../dialogs/confirm-delete-image.riot'; + const ACTION_CHECK_TO_DELETE = 'CHECK'; + const ACTION_UNCHECK_TO_DELETE = 'UNCHECK'; + const ACTION_DELETE_IMAGE = 'DELETE'; + export default { components: { ImageDate, @@ -119,13 +126,17 @@ along with this program. If not, see . } state.page = props.page }, - bulkDelete() { + deleteImages() { this.update({ confirmDeleteImage: true }) }, onConfirmDeleteImageClick() { + if (this.state.singleDeleteAction) { + this.state.toDelete.clear(); + } this.update({ + singleDeleteAction: false, confirmDeleteImage: false }) }, @@ -143,14 +154,29 @@ along with this program. If not, see . }) } }, - onRemoveImageChange(checked, image) { - if (checked) { - this.state.toDelete.add(image) - } else { - this.state.toDelete.delete(image) + onRemoveImageChange(action, image) { + let confirmDeleteImage = false; + let singleDeleteAction = false; + switch (action) { + case ACTION_CHECK_TO_DELETE: { + this.state.toDelete.add(image); + break; + } + case ACTION_UNCHECK_TO_DELETE: { + this.state.toDelete.delete(image); + break; + } + case ACTION_DELETE_IMAGE: { + this.state.toDelete.clear(); + this.state.toDelete.add(image); + confirmDeleteImage = true; + singleDeleteAction = true; + } } this.update({ - toDelete: this.state.toDelete + toDelete: this.state.toDelete, + confirmDeleteImage, + singleDeleteAction }) }, onReverseOrder() { @@ -181,5 +207,10 @@ along with this program. If not, see . }, matchSearch } + export { + ACTION_CHECK_TO_DELETE, + ACTION_UNCHECK_TO_DELETE, + ACTION_DELETE_IMAGE + } \ No newline at end of file
History - + + title="This will delete selected images." onClick="{ deleteImages }" + if="{ state.toDelete.size > 0 && !state.singleDeleteAction }"> delete