2020-03-13 15:44:24 +05:30
|
|
|
<script>
|
|
|
|
import { mapState, mapActions } from 'vuex';
|
|
|
|
import {
|
|
|
|
GlEmptyState,
|
|
|
|
GlPagination,
|
|
|
|
GlTooltipDirective,
|
2020-04-22 19:07:51 +05:30
|
|
|
GlDeprecatedButton,
|
2020-03-13 15:44:24 +05:30
|
|
|
GlIcon,
|
|
|
|
GlModal,
|
|
|
|
GlSprintf,
|
|
|
|
GlLink,
|
2020-04-22 19:07:51 +05:30
|
|
|
GlAlert,
|
2020-04-08 14:13:33 +05:30
|
|
|
GlSkeletonLoader,
|
2020-03-13 15:44:24 +05:30
|
|
|
} from '@gitlab/ui';
|
|
|
|
import Tracking from '~/tracking';
|
|
|
|
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
|
|
|
|
import ProjectEmptyState from '../components/project_empty_state.vue';
|
|
|
|
import GroupEmptyState from '../components/group_empty_state.vue';
|
2020-04-08 14:13:33 +05:30
|
|
|
import ProjectPolicyAlert from '../components/project_policy_alert.vue';
|
2020-04-22 19:07:51 +05:30
|
|
|
import QuickstartDropdown from '../components/quickstart_dropdown.vue';
|
|
|
|
import {
|
|
|
|
DELETE_IMAGE_SUCCESS_MESSAGE,
|
|
|
|
DELETE_IMAGE_ERROR_MESSAGE,
|
|
|
|
ASYNC_DELETE_IMAGE_ERROR_MESSAGE,
|
|
|
|
CONTAINER_REGISTRY_TITLE,
|
|
|
|
CONNECTION_ERROR_TITLE,
|
|
|
|
CONNECTION_ERROR_MESSAGE,
|
|
|
|
LIST_INTRO_TEXT,
|
|
|
|
LIST_DELETE_BUTTON_DISABLED,
|
|
|
|
REMOVE_REPOSITORY_LABEL,
|
|
|
|
REMOVE_REPOSITORY_MODAL_TEXT,
|
|
|
|
ROW_SCHEDULED_FOR_DELETION,
|
|
|
|
} from '../constants';
|
2020-03-13 15:44:24 +05:30
|
|
|
|
|
|
|
export default {
|
|
|
|
name: 'RegistryListApp',
|
|
|
|
components: {
|
|
|
|
GlEmptyState,
|
|
|
|
GlPagination,
|
|
|
|
ProjectEmptyState,
|
|
|
|
GroupEmptyState,
|
2020-04-08 14:13:33 +05:30
|
|
|
ProjectPolicyAlert,
|
2020-03-13 15:44:24 +05:30
|
|
|
ClipboardButton,
|
2020-04-22 19:07:51 +05:30
|
|
|
QuickstartDropdown,
|
|
|
|
GlDeprecatedButton,
|
2020-03-13 15:44:24 +05:30
|
|
|
GlIcon,
|
|
|
|
GlModal,
|
|
|
|
GlSprintf,
|
|
|
|
GlLink,
|
2020-04-22 19:07:51 +05:30
|
|
|
GlAlert,
|
2020-04-08 14:13:33 +05:30
|
|
|
GlSkeletonLoader,
|
2020-03-13 15:44:24 +05:30
|
|
|
},
|
|
|
|
directives: {
|
|
|
|
GlTooltip: GlTooltipDirective,
|
|
|
|
},
|
|
|
|
mixins: [Tracking.mixin()],
|
2020-04-08 14:13:33 +05:30
|
|
|
loader: {
|
|
|
|
repeat: 10,
|
|
|
|
width: 1000,
|
|
|
|
height: 40,
|
|
|
|
},
|
2020-04-22 19:07:51 +05:30
|
|
|
i18n: {
|
|
|
|
containerRegistryTitle: CONTAINER_REGISTRY_TITLE,
|
|
|
|
connectionErrorTitle: CONNECTION_ERROR_TITLE,
|
|
|
|
connectionErrorMessage: CONNECTION_ERROR_MESSAGE,
|
|
|
|
introText: LIST_INTRO_TEXT,
|
|
|
|
deleteButtonDisabled: LIST_DELETE_BUTTON_DISABLED,
|
|
|
|
removeRepositoryLabel: REMOVE_REPOSITORY_LABEL,
|
|
|
|
removeRepositoryModalText: REMOVE_REPOSITORY_MODAL_TEXT,
|
|
|
|
rowScheduledForDeletion: ROW_SCHEDULED_FOR_DELETION,
|
|
|
|
asyncDeleteErrorMessage: ASYNC_DELETE_IMAGE_ERROR_MESSAGE,
|
|
|
|
},
|
2020-03-13 15:44:24 +05:30
|
|
|
data() {
|
|
|
|
return {
|
|
|
|
itemToDelete: {},
|
2020-04-22 19:07:51 +05:30
|
|
|
deleteAlertType: null,
|
2020-03-13 15:44:24 +05:30
|
|
|
};
|
|
|
|
},
|
|
|
|
computed: {
|
|
|
|
...mapState(['config', 'isLoading', 'images', 'pagination']),
|
|
|
|
tracking() {
|
|
|
|
return {
|
|
|
|
label: 'registry_repository_delete',
|
|
|
|
};
|
|
|
|
},
|
|
|
|
currentPage: {
|
|
|
|
get() {
|
|
|
|
return this.pagination.page;
|
|
|
|
},
|
|
|
|
set(page) {
|
|
|
|
this.requestImagesList({ page });
|
|
|
|
},
|
|
|
|
},
|
2020-04-22 19:07:51 +05:30
|
|
|
showQuickStartDropdown() {
|
|
|
|
return Boolean(!this.isLoading && !this.config?.isGroupPage && this.images?.length);
|
|
|
|
},
|
|
|
|
showDeleteAlert() {
|
|
|
|
return this.deleteAlertType && this.itemToDelete?.path;
|
|
|
|
},
|
|
|
|
deleteImageAlertMessage() {
|
|
|
|
return this.deleteAlertType === 'success'
|
|
|
|
? DELETE_IMAGE_SUCCESS_MESSAGE
|
|
|
|
: DELETE_IMAGE_ERROR_MESSAGE;
|
|
|
|
},
|
2020-03-13 15:44:24 +05:30
|
|
|
},
|
|
|
|
methods: {
|
|
|
|
...mapActions(['requestImagesList', 'requestDeleteImage']),
|
|
|
|
deleteImage(item) {
|
|
|
|
this.track('click_button');
|
|
|
|
this.itemToDelete = item;
|
|
|
|
this.$refs.deleteModal.show();
|
|
|
|
},
|
2020-04-22 19:07:51 +05:30
|
|
|
handleDeleteImage() {
|
2020-03-13 15:44:24 +05:30
|
|
|
this.track('confirm_delete');
|
2020-04-22 19:07:51 +05:30
|
|
|
return this.requestDeleteImage(this.itemToDelete)
|
|
|
|
.then(() => {
|
|
|
|
this.deleteAlertType = 'success';
|
|
|
|
})
|
|
|
|
.catch(() => {
|
|
|
|
this.deleteAlertType = 'danger';
|
|
|
|
});
|
2020-03-13 15:44:24 +05:30
|
|
|
},
|
|
|
|
encodeListItem(item) {
|
|
|
|
const params = JSON.stringify({ name: item.path, tags_path: item.tags_path, id: item.id });
|
|
|
|
return window.btoa(params);
|
|
|
|
},
|
2020-04-22 19:07:51 +05:30
|
|
|
dismissDeleteAlert() {
|
|
|
|
this.deleteAlertType = null;
|
|
|
|
this.itemToDelete = {};
|
|
|
|
},
|
2020-03-13 15:44:24 +05:30
|
|
|
},
|
|
|
|
};
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<template>
|
2020-04-08 14:13:33 +05:30
|
|
|
<div class="w-100 slide-enter-from-element">
|
2020-04-22 19:07:51 +05:30
|
|
|
<gl-alert
|
|
|
|
v-if="showDeleteAlert"
|
|
|
|
:variant="deleteAlertType"
|
|
|
|
class="mt-2"
|
|
|
|
dismissible
|
|
|
|
@dismiss="dismissDeleteAlert"
|
|
|
|
>
|
|
|
|
<gl-sprintf :message="deleteImageAlertMessage">
|
|
|
|
<template #title>
|
|
|
|
{{ itemToDelete.path }}
|
|
|
|
</template>
|
|
|
|
</gl-sprintf>
|
|
|
|
</gl-alert>
|
|
|
|
|
|
|
|
<project-policy-alert v-if="!config.isGroupPage" class="mt-2" />
|
2020-04-08 14:13:33 +05:30
|
|
|
|
2020-03-13 15:44:24 +05:30
|
|
|
<gl-empty-state
|
|
|
|
v-if="config.characterError"
|
2020-04-22 19:07:51 +05:30
|
|
|
:title="$options.i18n.connectionErrorTitle"
|
2020-03-13 15:44:24 +05:30
|
|
|
:svg-path="config.containersErrorImage"
|
|
|
|
>
|
|
|
|
<template #description>
|
|
|
|
<p>
|
2020-04-22 19:07:51 +05:30
|
|
|
<gl-sprintf :message="$options.i18n.connectionErrorMessage">
|
2020-03-13 15:44:24 +05:30
|
|
|
<template #docLink="{content}">
|
|
|
|
<gl-link :href="`${config.helpPagePath}#docker-connection-error`" target="_blank">
|
|
|
|
{{ content }}
|
|
|
|
</gl-link>
|
|
|
|
</template>
|
|
|
|
</gl-sprintf>
|
|
|
|
</p>
|
|
|
|
</template>
|
|
|
|
</gl-empty-state>
|
|
|
|
|
|
|
|
<template v-else>
|
2020-04-08 14:13:33 +05:30
|
|
|
<div>
|
2020-04-22 19:07:51 +05:30
|
|
|
<div class="d-flex justify-content-between align-items-center">
|
|
|
|
<h4>{{ $options.i18n.containerRegistryTitle }}</h4>
|
|
|
|
<quickstart-dropdown v-if="showQuickStartDropdown" class="d-none d-sm-block" />
|
|
|
|
</div>
|
2020-04-08 14:13:33 +05:30
|
|
|
<p>
|
2020-04-22 19:07:51 +05:30
|
|
|
<gl-sprintf :message="$options.i18n.introText">
|
2020-04-08 14:13:33 +05:30
|
|
|
<template #docLink="{content}">
|
|
|
|
<gl-link :href="config.helpPagePath" target="_blank">
|
|
|
|
{{ content }}
|
|
|
|
</gl-link>
|
|
|
|
</template>
|
|
|
|
</gl-sprintf>
|
|
|
|
</p>
|
|
|
|
</div>
|
2020-03-13 15:44:24 +05:30
|
|
|
|
2020-04-08 14:13:33 +05:30
|
|
|
<div v-if="isLoading" class="mt-2">
|
|
|
|
<gl-skeleton-loader
|
|
|
|
v-for="index in $options.loader.repeat"
|
|
|
|
:key="index"
|
|
|
|
:width="$options.loader.width"
|
|
|
|
:height="$options.loader.height"
|
|
|
|
preserve-aspect-ratio="xMinYMax meet"
|
|
|
|
>
|
|
|
|
<rect width="500" x="10" y="10" height="20" rx="4" />
|
|
|
|
<circle cx="525" cy="20" r="10" />
|
|
|
|
<rect x="960" y="0" width="40" height="40" rx="4" />
|
|
|
|
</gl-skeleton-loader>
|
|
|
|
</div>
|
|
|
|
<template v-else>
|
|
|
|
<div v-if="images.length" ref="imagesList" class="d-flex flex-column">
|
|
|
|
<div
|
|
|
|
v-for="(listItem, index) in images"
|
|
|
|
:key="index"
|
|
|
|
ref="rowItem"
|
2020-04-22 19:07:51 +05:30
|
|
|
v-gl-tooltip="{
|
|
|
|
placement: 'left',
|
|
|
|
disabled: !listItem.deleting,
|
|
|
|
title: $options.i18n.rowScheduledForDeletion,
|
|
|
|
}"
|
2020-04-08 14:13:33 +05:30
|
|
|
>
|
2020-03-13 15:44:24 +05:30
|
|
|
<div
|
2020-04-22 19:07:51 +05:30
|
|
|
class="d-flex justify-content-between align-items-center py-2 px-1 border-bottom"
|
|
|
|
:class="{ 'border-top': index === 0, 'disabled-content': listItem.deleting }"
|
2020-03-13 15:44:24 +05:30
|
|
|
>
|
2020-04-22 19:07:51 +05:30
|
|
|
<div class="d-felx align-items-center">
|
|
|
|
<router-link
|
|
|
|
ref="detailsLink"
|
|
|
|
:to="{ name: 'details', params: { id: encodeListItem(listItem) } }"
|
|
|
|
>
|
|
|
|
{{ listItem.path }}
|
|
|
|
</router-link>
|
|
|
|
<clipboard-button
|
|
|
|
v-if="listItem.location"
|
|
|
|
ref="clipboardButton"
|
|
|
|
:disabled="listItem.deleting"
|
|
|
|
:text="listItem.location"
|
|
|
|
:title="listItem.location"
|
|
|
|
css-class="btn-default btn-transparent btn-clipboard"
|
|
|
|
/>
|
|
|
|
<gl-icon
|
|
|
|
v-if="listItem.failedDelete"
|
|
|
|
v-gl-tooltip
|
|
|
|
:title="$options.i18n.asyncDeleteErrorMessage"
|
|
|
|
name="warning"
|
|
|
|
class="text-warning align-middle"
|
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
<div
|
|
|
|
v-gl-tooltip="{ disabled: listItem.destroy_path }"
|
|
|
|
class="d-none d-sm-block"
|
|
|
|
:title="$options.i18n.deleteButtonDisabled"
|
2020-03-13 15:44:24 +05:30
|
|
|
>
|
2020-04-22 19:07:51 +05:30
|
|
|
<gl-deprecated-button
|
|
|
|
ref="deleteImageButton"
|
|
|
|
v-gl-tooltip
|
|
|
|
:disabled="!listItem.destroy_path || listItem.deleting"
|
|
|
|
:title="$options.i18n.removeRepositoryLabel"
|
|
|
|
:aria-label="$options.i18n.removeRepositoryLabel"
|
|
|
|
class="btn-inverted"
|
|
|
|
variant="danger"
|
|
|
|
@click="deleteImage(listItem)"
|
|
|
|
>
|
|
|
|
<gl-icon name="remove" />
|
|
|
|
</gl-deprecated-button>
|
|
|
|
</div>
|
2020-03-13 15:44:24 +05:30
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<gl-pagination
|
|
|
|
v-model="currentPage"
|
|
|
|
:per-page="pagination.perPage"
|
|
|
|
:total-items="pagination.total"
|
|
|
|
align="center"
|
|
|
|
class="w-100 mt-2"
|
|
|
|
/>
|
|
|
|
</div>
|
2020-04-08 14:13:33 +05:30
|
|
|
|
2020-03-13 15:44:24 +05:30
|
|
|
<template v-else>
|
|
|
|
<project-empty-state v-if="!config.isGroupPage" />
|
|
|
|
<group-empty-state v-else />
|
|
|
|
</template>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<gl-modal
|
|
|
|
ref="deleteModal"
|
|
|
|
modal-id="delete-image-modal"
|
|
|
|
ok-variant="danger"
|
2020-04-22 19:07:51 +05:30
|
|
|
@ok="handleDeleteImage"
|
2020-03-13 15:44:24 +05:30
|
|
|
@cancel="track('cancel_delete')"
|
|
|
|
>
|
2020-04-22 19:07:51 +05:30
|
|
|
<template #modal-title>{{ $options.i18n.removeRepositoryLabel }}</template>
|
2020-03-13 15:44:24 +05:30
|
|
|
<p>
|
2020-04-22 19:07:51 +05:30
|
|
|
<gl-sprintf :message="$options.i18n.removeRepositoryModalText">
|
2020-03-13 15:44:24 +05:30
|
|
|
<template #title>
|
|
|
|
<b>{{ itemToDelete.path }}</b>
|
|
|
|
</template>
|
|
|
|
</gl-sprintf>
|
|
|
|
</p>
|
|
|
|
<template #modal-ok>{{ __('Remove') }}</template>
|
|
|
|
</gl-modal>
|
|
|
|
</template>
|
|
|
|
</div>
|
|
|
|
</template>
|