diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d9b0185a8d8bf3a09d874217e478f6dcc7c429b3..21dfd6563e25651eca5b09c685e09a80e2f85192 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -15,7 +15,7 @@ stages: # in cases where jobs require Docker-in-Docker, the job # definition must be extended with `.use-docker-in-docker` default: - image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.26-lfs-2.9-chrome-81.0-node-12.x-yarn-1.21-postgresql-9.6-graphicsmagick-1.3.34" + image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.26-lfs-2.9-chrome-73.0-node-12.x-yarn-1.21-postgresql-9.6-graphicsmagick-1.3.34" tags: - gitlab-org # All jobs are interruptible by default diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml index 2df24eedc1fd24eb02b5e231bec04b6144659818..5be4d4eaf1f63409d61480755830c3a8fc4f4762 100644 --- a/.gitlab/ci/frontend.gitlab-ci.yml +++ b/.gitlab/ci/frontend.gitlab-ci.yml @@ -15,7 +15,7 @@ - .default-retry - .default-before_script - .assets-compile-cache - image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-git-2.26-lfs-2.9-chrome-81.0-node-12.x-yarn-1.21-graphicsmagick-1.3.34-docker-19.03.1 + image: registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-git-2.26-lfs-2.9-chrome-73.0-node-12.x-yarn-1.21-graphicsmagick-1.3.34-docker-19.03.1 stage: prepare variables: NODE_ENV: "production" diff --git a/.gitlab/ci/global.gitlab-ci.yml b/.gitlab/ci/global.gitlab-ci.yml index 21d085c5ca5346625076010f0bfc9e386fa0d984..0c26273ef04dbbb9a4ad399710fb53eb24a2f53b 100644 --- a/.gitlab/ci/global.gitlab-ci.yml +++ b/.gitlab/ci/global.gitlab-ci.yml @@ -30,7 +30,7 @@ policy: pull .use-pg9: - image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.26-lfs-2.9-chrome-81.0-node-12.x-yarn-1.21-postgresql-9.6-graphicsmagick-1.3.34" + image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.26-lfs-2.9-chrome-73.0-node-12.x-yarn-1.21-postgresql-9.6-graphicsmagick-1.3.34" services: - name: postgres:9.6.17 command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] @@ -41,7 +41,7 @@ key: "debian-stretch-ruby-2.6.6-pg9-node-12.x" .use-pg10: - image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.26-lfs-2.9-chrome-81.0-node-12.x-yarn-1.21-postgresql-10-graphicsmagick-1.3.34" + image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.26-lfs-2.9-chrome-73.0-node-12.x-yarn-1.21-postgresql-10-graphicsmagick-1.3.34" services: - name: postgres:10.12 command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] @@ -52,7 +52,7 @@ key: "debian-stretch-ruby-2.6.6-pg10-node-12.x" .use-pg11: - image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.26-lfs-2.9-chrome-81.0-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34" + image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.26-lfs-2.9-chrome-73.0-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34" services: - name: postgres:11.6 command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] @@ -63,7 +63,7 @@ key: "debian-stretch-ruby-2.6.6-pg11-node-12.x" .use-pg9-ee: - image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.26-lfs-2.9-chrome-81.0-node-12.x-yarn-1.21-postgresql-9.6-graphicsmagick-1.3.34" + image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.26-lfs-2.9-chrome-73.0-node-12.x-yarn-1.21-postgresql-9.6-graphicsmagick-1.3.34" services: - name: postgres:9.6.17 command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] @@ -75,7 +75,7 @@ key: "debian-stretch-ruby-2.6.6-pg9-node-12.x" .use-pg10-ee: - image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.26-lfs-2.9-chrome-81.0-node-12.x-yarn-1.21-postgresql-10-graphicsmagick-1.3.34" + image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.26-lfs-2.9-chrome-73.0-node-12.x-yarn-1.21-postgresql-10-graphicsmagick-1.3.34" services: - name: postgres:10.12 command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] @@ -87,7 +87,7 @@ key: "debian-stretch-ruby-2.6.6-pg10-node-12.x" .use-pg11-ee: - image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.26-lfs-2.9-chrome-81.0-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34" + image: "registry.gitlab.com/gitlab-org/gitlab-build-images:ruby-2.6.6-golang-1.14-git-2.26-lfs-2.9-chrome-73.0-node-12.x-yarn-1.21-postgresql-11-graphicsmagick-1.3.34" services: - name: postgres:11.6 command: ["postgres", "-c", "fsync=off", "-c", "synchronous_commit=off", "-c", "full_page_writes=off"] diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml index f2de98cbfab99ff6c52d0affacb9c31a263ca71c..c63397dceea86dd51c4f1bdb1739cad04e7fe718 100644 --- a/.gitlab/ci/rails.gitlab-ci.yml +++ b/.gitlab/ci/rails.gitlab-ci.yml @@ -145,7 +145,6 @@ db:check-schema: - .db-job-base - .rails:rules:ee-mr-and-master-only script: - - scripts/regenerate-schema - source scripts/schema_changed.sh db:migrate-from-v11.11.0: diff --git a/app/assets/javascripts/registry/explorer/constants.js b/app/assets/javascripts/registry/explorer/constants.js index d4b9d25b212fa1eb52d27441d6153a00c95c4c84..4ca4c7088a646a91a288f11dfd2a211b360b265b 100644 --- a/app/assets/javascripts/registry/explorer/constants.js +++ b/app/assets/javascripts/registry/explorer/constants.js @@ -39,14 +39,20 @@ export const DELETE_IMAGE_SUCCESS_MESSAGE = s__( // Image details page +export const DETAILS_PAGE_TITLE = s__('ContainerRegistry|%{imageName} tags'); + export const DELETE_TAG_ERROR_MESSAGE = s__( - 'ContainerRegistry|Something went wrong while deleting the tag.', + 'ContainerRegistry|Something went wrong while marking the tag for deletion.', +); +export const DELETE_TAG_SUCCESS_MESSAGE = s__( + 'ContainerRegistry|Tag successfully marked for deletion.', ); -export const DELETE_TAG_SUCCESS_MESSAGE = s__('ContainerRegistry|Tag deleted successfully'); export const DELETE_TAGS_ERROR_MESSAGE = s__( - 'ContainerRegistry|Something went wrong while deleting the tags.', + 'ContainerRegistry|Something went wrong while marking the tags for deletion.', +); +export const DELETE_TAGS_SUCCESS_MESSAGE = s__( + 'ContainerRegistry|Tags successfully marked for deletion.', ); -export const DELETE_TAGS_SUCCESS_MESSAGE = s__('ContainerRegistry|Tags deleted successfully'); export const DEFAULT_PAGE = 1; export const DEFAULT_PAGE_SIZE = 10; @@ -65,6 +71,27 @@ export const LIST_LABEL_IMAGE_ID = s__('ContainerRegistry|Image ID'); export const LIST_LABEL_SIZE = s__('ContainerRegistry|Compressed Size'); export const LIST_LABEL_LAST_UPDATED = s__('ContainerRegistry|Last Updated'); +export const REMOVE_TAG_BUTTON_TITLE = s__('ContainerRegistry|Remove tag'); +export const REMOVE_TAGS_BUTTON_TITLE = s__('ContainerRegistry|Remove selected tags'); + +export const REMOVE_TAG_CONFIRMATION_TEXT = s__( + `ContainerRegistry|You are about to remove %{item}. Are you sure?`, +); +export const REMOVE_TAGS_CONFIRMATION_TEXT = s__( + `ContainerRegistry|You are about to remove %{item} tags. Are you sure?`, +); + +export const EMPTY_IMAGE_REPOSITORY_TITLE = s__('ContainerRegistry|This image has no active tags'); +export const EMPTY_IMAGE_REPOSITORY_MESSAGE = s__( + `ContainerRegistry|The last tag related to this image was recently removed. +This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. +If you have any questions, contact your administrator.`, +); + +export const ADMIN_GARBAGE_COLLECTION_TIP = s__( + 'ContainerRegistry|Remember to run %{docLinkStart}garbage collection%{docLinkEnd} to remove the stale data from storage.', +); + // Expiration policies export const EXPIRATION_POLICY_ALERT_TITLE = s__( diff --git a/app/assets/javascripts/registry/explorer/pages/details.vue b/app/assets/javascripts/registry/explorer/pages/details.vue index 6afd4d1107a96eb636ffc8be95e8738b6e66d5b8..1d4dcd9a7a2944aa8a22794585a6f12f517ee9d6 100644 --- a/app/assets/javascripts/registry/explorer/pages/details.vue +++ b/app/assets/javascripts/registry/explorer/pages/details.vue @@ -9,12 +9,14 @@ import { GlPagination, GlModal, GlSprintf, + GlAlert, + GlLink, GlEmptyState, GlResizeObserverDirective, GlSkeletonLoader, } from '@gitlab/ui'; import { GlBreakpointInstance } from '@gitlab/ui/dist/utils'; -import { n__, s__ } from '~/locale'; +import { n__ } from '~/locale'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import { numberToHumanSize } from '~/lib/utils/number_utils'; import timeagoMixin from '~/vue_shared/mixins/timeago'; @@ -35,6 +37,14 @@ import { DELETE_TAG_ERROR_MESSAGE, DELETE_TAGS_SUCCESS_MESSAGE, DELETE_TAGS_ERROR_MESSAGE, + REMOVE_TAG_CONFIRMATION_TEXT, + REMOVE_TAGS_CONFIRMATION_TEXT, + DETAILS_PAGE_TITLE, + REMOVE_TAGS_BUTTON_TITLE, + REMOVE_TAG_BUTTON_TITLE, + EMPTY_IMAGE_REPOSITORY_TITLE, + EMPTY_IMAGE_REPOSITORY_MESSAGE, + ADMIN_GARBAGE_COLLECTION_TIP, } from '../constants'; export default { @@ -49,6 +59,8 @@ export default { GlSkeletonLoader, GlSprintf, GlEmptyState, + GlAlert, + GlLink, }, directives: { GlTooltip: GlTooltipDirective, @@ -60,6 +72,19 @@ export default { width: 1000, height: 40, }, + i18n: { + DETAILS_PAGE_TITLE, + REMOVE_TAGS_BUTTON_TITLE, + REMOVE_TAG_BUTTON_TITLE, + EMPTY_IMAGE_REPOSITORY_TITLE, + EMPTY_IMAGE_REPOSITORY_MESSAGE, + }, + alertMessages: { + success_tag: DELETE_TAG_SUCCESS_MESSAGE, + danger_tag: DELETE_TAG_ERROR_MESSAGE, + success_tags: DELETE_TAGS_SUCCESS_MESSAGE, + danger_tags: DELETE_TAGS_ERROR_MESSAGE, + }, data() { return { selectedItems: [], @@ -67,6 +92,7 @@ export default { selectAllChecked: false, modalDescription: null, isDesktop: true, + deleteAlertType: false, }; }, computed: { @@ -110,20 +136,40 @@ export default { this.requestTagsList({ pagination: { page }, params: this.$route.params.id }); }, }, + deleteAlertConfig() { + const config = { + title: '', + message: '', + type: 'success', + }; + if (this.deleteAlertType) { + [config.type] = this.deleteAlertType.split('_'); + + const defaultMessage = this.$options.alertMessages[this.deleteAlertType]; + + if (this.config.isAdmin && config.type === 'success') { + config.title = defaultMessage; + config.message = ADMIN_GARBAGE_COLLECTION_TIP; + } else { + config.message = defaultMessage; + } + } + return config; + }, }, methods: { ...mapActions(['requestTagsList', 'requestDeleteTag', 'requestDeleteTags']), setModalDescription(itemIndex = -1) { if (itemIndex === -1) { this.modalDescription = { - message: s__(`ContainerRegistry|You are about to remove %{item} tags. Are you sure?`), + message: REMOVE_TAGS_CONFIRMATION_TEXT, item: this.itemsToBeDeleted.length, }; } else { const { path } = this.tags[itemIndex]; this.modalDescription = { - message: s__(`ContainerRegistry|You are about to remove %{item}. Are you sure?`), + message: REMOVE_TAG_CONFIRMATION_TEXT, item: path, }; } @@ -179,19 +225,17 @@ export default { this.track('click_button'); this.$refs.deleteModal.show(); }, - handleSingleDelete(itemToDelete) { + handleSingleDelete(index) { + const itemToDelete = this.tags[index]; this.itemsToBeDeleted = []; + this.selectedItems = this.selectedItems.filter(i => i !== index); return this.requestDeleteTag({ tag: itemToDelete, params: this.$route.params.id }) - .then(() => - this.$toast.show(DELETE_TAG_SUCCESS_MESSAGE, { - type: 'success', - }), - ) - .catch(() => - this.$toast.show(DELETE_TAG_ERROR_MESSAGE, { - type: 'error', - }), - ); + .then(() => { + this.deleteAlertType = 'success_tag'; + }) + .catch(() => { + this.deleteAlertType = 'danger_tag'; + }); }, handleMultipleDelete() { const { itemsToBeDeleted } = this; @@ -202,24 +246,19 @@ export default { ids: itemsToBeDeleted.map(x => this.tags[x].name), params: this.$route.params.id, }) - .then(() => - this.$toast.show(DELETE_TAGS_SUCCESS_MESSAGE, { - type: 'success', - }), - ) - .catch(() => - this.$toast.show(DELETE_TAGS_ERROR_MESSAGE, { - type: 'error', - }), - ); + .then(() => { + this.deleteAlertType = 'success_tags'; + }) + .catch(() => { + this.deleteAlertType = 'danger_tags'; + }); }, onDeletionConfirmed() { this.track('confirm_delete'); if (this.isMultiDelete) { this.handleMultipleDelete(); } else { - const index = this.itemsToBeDeleted[0]; - this.handleSingleDelete(this.tags[index]); + this.handleSingleDelete(this.itemsToBeDeleted[0]); } }, handleResize() { @@ -231,9 +270,24 @@ export default {