summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/registry/explorer/pages/details.vue
diff options
context:
space:
mode:
Diffstat (limited to 'app/assets/javascripts/registry/explorer/pages/details.vue')
-rw-r--r--app/assets/javascripts/registry/explorer/pages/details.vue168
1 files changed, 116 insertions, 52 deletions
diff --git a/app/assets/javascripts/registry/explorer/pages/details.vue b/app/assets/javascripts/registry/explorer/pages/details.vue
index 6afd4d1107a..cc2dc531dc8 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: {
@@ -78,9 +104,15 @@ export default {
},
fields() {
const tagClass = this.isDesktop ? 'w-25' : '';
+ const tagInnerClass = this.isDesktop ? 'mw-m' : 'gl-justify-content-end';
return [
{ key: LIST_KEY_CHECKBOX, label: '', class: 'gl-w-16' },
- { key: LIST_KEY_TAG, label: LIST_LABEL_TAG, class: `${tagClass} js-tag-column` },
+ {
+ key: LIST_KEY_TAG,
+ label: LIST_LABEL_TAG,
+ class: `${tagClass} js-tag-column`,
+ innerClass: tagInnerClass,
+ },
{ key: LIST_KEY_IMAGE_ID, label: LIST_LABEL_IMAGE_ID },
{ key: LIST_KEY_SIZE, label: LIST_LABEL_SIZE },
{ key: LIST_KEY_LAST_UPDATED, label: LIST_LABEL_LAST_UPDATED },
@@ -110,20 +142,43 @@ 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;
+ },
+ },
+ mounted() {
+ this.requestTagsList({ params: this.$route.params.id });
},
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 +234,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 +255,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 +279,24 @@ export default {
<template>
<div v-gl-resize-observer="handleResize" class="my-3 w-100 slide-enter-to-element">
+ <gl-alert
+ v-if="deleteAlertType"
+ :variant="deleteAlertConfig.type"
+ :title="deleteAlertConfig.title"
+ class="my-2"
+ @dismiss="deleteAlertType = null"
+ >
+ <gl-sprintf :message="deleteAlertConfig.message">
+ <template #docLink="{content}">
+ <gl-link :href="config.garbageCollectionHelpPagePath" target="_blank">
+ {{ content }}
+ </gl-link>
+ </template>
+ </gl-sprintf>
+ </gl-alert>
<div class="d-flex my-3 align-items-center">
<h4>
- <gl-sprintf :message="s__('ContainerRegistry|%{imageName} tags')">
+ <gl-sprintf :message="$options.i18n.DETAILS_PAGE_TITLE">
<template #imageName>
{{ imageName }}
</template>
@@ -256,8 +319,8 @@ export default {
:disabled="!selectedItems || selectedItems.length === 0"
class="float-right"
variant="danger"
- :title="s__('ContainerRegistry|Remove selected tags')"
- :aria-label="s__('ContainerRegistry|Remove selected tags')"
+ :title="$options.i18n.REMOVE_TAGS_BUTTON_TITLE"
+ :aria-label="$options.i18n.REMOVE_TAGS_BUTTON_TITLE"
@click="deleteMultipleItems()"
>
<gl-icon name="remove" />
@@ -272,17 +335,24 @@ export default {
@change="updateSelectedItems(index)"
/>
</template>
- <template #cell(name)="{item}">
- <span ref="rowName">
- {{ item.name }}
- </span>
- <clipboard-button
- v-if="item.location"
- ref="rowClipboardButton"
- :title="item.location"
- :text="item.location"
- css-class="btn-default btn-transparent btn-clipboard"
- />
+ <template #cell(name)="{item, field}">
+ <div ref="rowName" :class="[field.innerClass, 'gl-display-flex']">
+ <span
+ v-gl-tooltip
+ data-testid="rowNameText"
+ :title="item.name"
+ class="gl-text-overflow-ellipsis gl-overflow-hidden gl-white-space-nowrap"
+ >
+ {{ item.name }}
+ </span>
+ <clipboard-button
+ v-if="item.location"
+ ref="rowClipboardButton"
+ :title="item.location"
+ :text="item.location"
+ css-class="btn-default btn-transparent btn-clipboard"
+ />
+ </div>
</template>
<template #cell(short_revision)="{value}">
<span ref="rowShortRevision">
@@ -299,15 +369,15 @@ export default {
</span>
</template>
<template #cell(created_at)="{value}">
- <span ref="rowTime">
+ <span ref="rowTime" v-gl-tooltip :title="tooltipTitle(value)">
{{ timeFormatted(value) }}
</span>
</template>
<template #cell(actions)="{index, item}">
<gl-deprecated-button
ref="singleDeleteButton"
- :title="s__('ContainerRegistry|Remove tag')"
- :aria-label="s__('ContainerRegistry|Remove tag')"
+ :title="$options.i18n.REMOVE_TAG_BUTTON_TITLE"
+ :aria-label="$options.i18n.REMOVE_TAG_BUTTON_TITLE"
:disabled="!item.destroy_path"
variant="danger"
class="js-delete-registry float-right btn-inverted btn-border-color btn-icon"
@@ -337,15 +407,9 @@ export default {
</template>
<gl-empty-state
v-else
- :title="s__('ContainerRegistry|This image has no active tags')"
+ :title="$options.i18n.EMPTY_IMAGE_REPOSITORY_TITLE"
:svg-path="config.noContainersImage"
- :description="
- 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.`,
- )
- "
+ :description="$options.i18n.EMPTY_IMAGE_REPOSITORY_MESSAGE"
class="mx-auto my-0"
/>
</template>