diff options
Diffstat (limited to 'app/assets/javascripts/registry/explorer/components/details_page')
7 files changed, 166 insertions, 57 deletions
diff --git a/app/assets/javascripts/registry/explorer/components/details_page/delete_modal.vue b/app/assets/javascripts/registry/explorer/components/details_page/delete_modal.vue index 96f221bf71d..0432cf1123c 100644 --- a/app/assets/javascripts/registry/explorer/components/details_page/delete_modal.vue +++ b/app/assets/javascripts/registry/explorer/components/details_page/delete_modal.vue @@ -1,7 +1,12 @@ <script> import { GlModal, GlSprintf } from '@gitlab/ui'; import { n__ } from '~/locale'; -import { REMOVE_TAG_CONFIRMATION_TEXT, REMOVE_TAGS_CONFIRMATION_TEXT } from '../../constants/index'; +import { + REMOVE_TAG_CONFIRMATION_TEXT, + REMOVE_TAGS_CONFIRMATION_TEXT, + DELETE_IMAGE_CONFIRMATION_TITLE, + DELETE_IMAGE_CONFIRMATION_TEXT, +} from '../../constants'; export default { components: { @@ -14,9 +19,17 @@ export default { required: false, default: () => [], }, + deleteImage: { + type: Boolean, + default: false, + required: false, + }, }, computed: { - modalAction() { + modalTitle() { + if (this.deleteImage) { + return DELETE_IMAGE_CONFIRMATION_TITLE; + } return n__( 'ContainerRegistry|Remove tag', 'ContainerRegistry|Remove tags', @@ -24,14 +37,19 @@ export default { ); }, modalDescription() { + if (this.deleteImage) { + return { + message: DELETE_IMAGE_CONFIRMATION_TEXT, + }; + } if (this.itemsToBeDeleted.length > 1) { return { message: REMOVE_TAGS_CONFIRMATION_TEXT, item: this.itemsToBeDeleted.length, }; } - const [first] = this.itemsToBeDeleted; + const [first] = this.itemsToBeDeleted; return { message: REMOVE_TAG_CONFIRMATION_TEXT, item: first?.path, @@ -51,16 +69,17 @@ export default { ref="deleteModal" modal-id="delete-tag-modal" ok-variant="danger" - @ok="$emit('confirmDelete')" + :action-primary="{ text: __('Confirm'), attributes: { variant: 'danger' } }" + :action-cancel="{ text: __('Cancel') }" + @primary="$emit('confirmDelete')" @cancel="$emit('cancelDelete')" > - <template #modal-title>{{ modalAction }}</template> - <template #modal-ok>{{ modalAction }}</template> + <template #modal-title>{{ modalTitle }}</template> <p v-if="modalDescription" data-testid="description"> <gl-sprintf :message="modalDescription.message"> - <template #item - ><b>{{ modalDescription.item }}</b></template - > + <template #item> + <b>{{ modalDescription.item }}</b> + </template> </gl-sprintf> </p> </gl-modal> diff --git a/app/assets/javascripts/registry/explorer/components/details_page/details_header.vue b/app/assets/javascripts/registry/explorer/components/details_page/details_header.vue index ed02aa264ed..a4b4c08bc34 100644 --- a/app/assets/javascripts/registry/explorer/components/details_page/details_header.vue +++ b/app/assets/javascripts/registry/explorer/components/details_page/details_header.vue @@ -1,8 +1,8 @@ <script> -import { GlSprintf } from '@gitlab/ui'; +import { GlSprintf, GlButton } from '@gitlab/ui'; import { sprintf, n__ } from '~/locale'; -import TitleArea from '~/vue_shared/components/registry/title_area.vue'; import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue'; +import TitleArea from '~/vue_shared/components/registry/title_area.vue'; import timeagoMixin from '~/vue_shared/mixins/timeago'; import { DETAILS_PAGE_TITLE, @@ -24,7 +24,7 @@ import { export default { name: 'DetailsHeader', - components: { GlSprintf, TitleArea, MetadataItem }, + components: { GlSprintf, GlButton, TitleArea, MetadataItem }, mixins: [timeagoMixin], props: { image: { @@ -36,6 +36,11 @@ export default { required: false, default: false, }, + disabled: { + type: Boolean, + default: false, + required: false, + }, }, computed: { visibilityIcon() { @@ -65,6 +70,9 @@ export default { [UNFINISHED_STATUS]: { text: CLEANUP_UNFINISHED_TEXT, tooltip: CLEANUP_UNFINISHED_TOOLTIP }, }[this.image?.expirationPolicyCleanupStatus]; }, + deleteButtonDisabled() { + return this.disabled || !this.image.canDelete; + }, }, i18n: { DETAILS_PAGE_TITLE, @@ -75,11 +83,13 @@ export default { <template> <title-area :metadata-loading="metadataLoading"> <template #title> - <gl-sprintf :message="$options.i18n.DETAILS_PAGE_TITLE"> - <template #imageName> - {{ image.name }} - </template> - </gl-sprintf> + <span data-testid="title"> + <gl-sprintf :message="$options.i18n.DETAILS_PAGE_TITLE"> + <template #imageName> + {{ image.name }} + </template> + </gl-sprintf> + </span> </template> <template #metadata-tags-count> <metadata-item icon="tag" :text="tagCountText" data-testid="tags-count" /> @@ -103,5 +113,15 @@ export default { data-testid="updated-and-visibility" /> </template> + <template #right-actions> + <gl-button + v-if="!metadataLoading" + variant="danger" + :disabled="deleteButtonDisabled" + @click="$emit('delete')" + > + {{ __('Delete') }} + </gl-button> + </template> </title-area> </template> diff --git a/app/assets/javascripts/registry/explorer/components/details_page/empty_state.vue b/app/assets/javascripts/registry/explorer/components/details_page/empty_state.vue new file mode 100644 index 00000000000..a16d95a6b30 --- /dev/null +++ b/app/assets/javascripts/registry/explorer/components/details_page/empty_state.vue @@ -0,0 +1,44 @@ +<script> +import { GlEmptyState } from '@gitlab/ui'; +import { + NO_TAGS_TITLE, + NO_TAGS_MESSAGE, + MISSING_OR_DELETED_IMAGE_TITLE, + MISSING_OR_DELETED_IMAGE_MESSAGE, +} from '../../constants/index'; + +export default { + components: { + GlEmptyState, + }, + props: { + noContainersImage: { + type: String, + required: false, + default: '', + }, + isEmptyImage: { + type: Boolean, + default: false, + required: false, + }, + }, + computed: { + title() { + return this.isEmptyImage ? MISSING_OR_DELETED_IMAGE_TITLE : NO_TAGS_TITLE; + }, + description() { + return this.isEmptyImage ? MISSING_OR_DELETED_IMAGE_MESSAGE : NO_TAGS_MESSAGE; + }, + }, +}; +</script> + +<template> + <gl-empty-state + :title="title" + :svg-path="noContainersImage" + :description="description" + class="gl-mx-auto gl-my-0" + /> +</template> diff --git a/app/assets/javascripts/registry/explorer/components/details_page/empty_tags_state.vue b/app/assets/javascripts/registry/explorer/components/details_page/empty_tags_state.vue deleted file mode 100644 index 0c684d124d5..00000000000 --- a/app/assets/javascripts/registry/explorer/components/details_page/empty_tags_state.vue +++ /dev/null @@ -1,33 +0,0 @@ -<script> -import { GlEmptyState } from '@gitlab/ui'; -import { - EMPTY_IMAGE_REPOSITORY_TITLE, - EMPTY_IMAGE_REPOSITORY_MESSAGE, -} from '../../constants/index'; - -export default { - components: { - GlEmptyState, - }, - props: { - noContainersImage: { - type: String, - required: false, - default: '', - }, - }, - i18n: { - EMPTY_IMAGE_REPOSITORY_TITLE, - EMPTY_IMAGE_REPOSITORY_MESSAGE, - }, -}; -</script> - -<template> - <gl-empty-state - :title="$options.i18n.EMPTY_IMAGE_REPOSITORY_TITLE" - :svg-path="noContainersImage" - :description="$options.i18n.EMPTY_IMAGE_REPOSITORY_MESSAGE" - class="gl-mx-auto gl-my-0" - /> -</template> diff --git a/app/assets/javascripts/registry/explorer/components/details_page/status_alert.vue b/app/assets/javascripts/registry/explorer/components/details_page/status_alert.vue new file mode 100644 index 00000000000..fc1504f6c31 --- /dev/null +++ b/app/assets/javascripts/registry/explorer/components/details_page/status_alert.vue @@ -0,0 +1,50 @@ +<script> +import { GlAlert, GlLink, GlSprintf } from '@gitlab/ui'; +import { + IMAGE_STATUS_MESSAGES, + IMAGE_STATUS_TITLES, + IMAGE_STATUS_ALERT_TYPE, + PACKAGE_DELETE_HELP_PAGE_PATH, +} from '../../constants'; + +export default { + components: { + GlAlert, + GlSprintf, + GlLink, + }, + props: { + status: { + type: String, + required: true, + }, + }, + computed: { + message() { + return IMAGE_STATUS_MESSAGES[this.status]; + }, + title() { + return IMAGE_STATUS_TITLES[this.status]; + }, + variant() { + return IMAGE_STATUS_ALERT_TYPE[this.status]; + }, + }, + links: { + PACKAGE_DELETE_HELP_PAGE_PATH, + }, +}; +</script> +<template> + <gl-alert :title="title" :variant="variant"> + <span data-testid="message"> + <gl-sprintf :message="message"> + <template #link="{ content }"> + <gl-link :href="$options.links.PACKAGE_DELETE_HELP_PAGE_PATH" target="_blank">{{ + content + }}</gl-link> + </template> + </gl-sprintf> + </span> + </gl-alert> +</template> diff --git a/app/assets/javascripts/registry/explorer/components/details_page/tags_list.vue b/app/assets/javascripts/registry/explorer/components/details_page/tags_list.vue index 1e0736c4a53..bc10246614a 100644 --- a/app/assets/javascripts/registry/explorer/components/details_page/tags_list.vue +++ b/app/assets/javascripts/registry/explorer/components/details_page/tags_list.vue @@ -1,7 +1,7 @@ <script> import { GlButton } from '@gitlab/ui'; -import TagsListRow from './tags_list_row.vue'; import { REMOVE_TAGS_BUTTON_TITLE, TAGS_LIST_TITLE } from '../../constants/index'; +import TagsListRow from './tags_list_row.vue'; export default { name: 'TagsList', @@ -20,6 +20,11 @@ export default { default: true, required: false, }, + disabled: { + type: Boolean, + default: false, + required: false, + }, }, i18n: { REMOVE_TAGS_BUTTON_TITLE, @@ -37,6 +42,9 @@ export default { showMultiDeleteButton() { return this.tags.some((tag) => tag.canDelete) && !this.isMobile; }, + multiDeleteButtonIsDisabled() { + return !this.hasSelectedItems || this.disabled; + }, }, methods: { updateSelectedItems(name) { @@ -55,7 +63,7 @@ export default { <gl-button v-if="showMultiDeleteButton" - :disabled="!hasSelectedItems" + :disabled="multiDeleteButtonIsDisabled" category="secondary" variant="danger" @click="$emit('delete', selectedItems)" @@ -70,6 +78,7 @@ export default { :first="index === 0" :selected="selectedItems[tag.name]" :is-mobile="isMobile" + :disabled="disabled" @select="updateSelectedItems(tag.name)" @delete="$emit('delete', { [tag.name]: true })" /> diff --git a/app/assets/javascripts/registry/explorer/components/details_page/tags_list_row.vue b/app/assets/javascripts/registry/explorer/components/details_page/tags_list_row.vue index 2e4a489f2cb..c66f92bdd67 100644 --- a/app/assets/javascripts/registry/explorer/components/details_page/tags_list_row.vue +++ b/app/assets/javascripts/registry/explorer/components/details_page/tags_list_row.vue @@ -1,13 +1,12 @@ <script> import { GlFormCheckbox, GlTooltipDirective, GlSprintf, GlIcon } from '@gitlab/ui'; +import { formatDate } from '~/lib/utils/datetime_utility'; +import { numberToHumanSize } from '~/lib/utils/number_utils'; import { n__ } from '~/locale'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; -import { numberToHumanSize } from '~/lib/utils/number_utils'; -import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; -import { formatDate } from '~/lib/utils/datetime_utility'; -import ListItem from '~/vue_shared/components/registry/list_item.vue'; -import DeleteButton from '../delete_button.vue'; import DetailsRow from '~/vue_shared/components/registry/details_row.vue'; +import ListItem from '~/vue_shared/components/registry/list_item.vue'; +import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; import { REMOVE_TAG_BUTTON_TITLE, DIGEST_LABEL, @@ -20,6 +19,7 @@ import { NOT_AVAILABLE_TEXT, NOT_AVAILABLE_SIZE, } from '../../constants/index'; +import DeleteButton from '../delete_button.vue'; export default { components: { |