diff options
Diffstat (limited to 'app/assets/javascripts/registry/explorer/pages/details.vue')
-rw-r--r-- | app/assets/javascripts/registry/explorer/pages/details.vue | 177 |
1 files changed, 115 insertions, 62 deletions
diff --git a/app/assets/javascripts/registry/explorer/pages/details.vue b/app/assets/javascripts/registry/explorer/pages/details.vue index a60ef5c4982..540f02d58d4 100644 --- a/app/assets/javascripts/registry/explorer/pages/details.vue +++ b/app/assets/javascripts/registry/explorer/pages/details.vue @@ -1,8 +1,9 @@ <script> -import { mapState, mapActions } from 'vuex'; -import { GlPagination, GlResizeObserverDirective } from '@gitlab/ui'; +import { GlKeysetPagination, GlResizeObserverDirective } from '@gitlab/ui'; import { GlBreakpointInstance } from '@gitlab/ui/dist/utils'; +import createFlash from '~/flash'; import Tracking from '~/tracking'; +import { joinPaths } from '~/lib/utils/url_utility'; import DeleteAlert from '../components/details_page/delete_alert.vue'; import PartialCleanupAlert from '../components/details_page/partial_cleanup_alert.vue'; import DeleteModal from '../components/details_page/delete_modal.vue'; @@ -11,11 +12,16 @@ import TagsList from '../components/details_page/tags_list.vue'; import TagsLoader from '../components/details_page/tags_loader.vue'; import EmptyTagsState from '../components/details_page/empty_tags_state.vue'; +import getContainerRepositoryDetailsQuery from '../graphql/queries/get_container_repository_details.query.graphql'; +import deleteContainerRepositoryTagsMutation from '../graphql/mutations/delete_container_repository_tags.mutation.graphql'; + import { ALERT_SUCCESS_TAG, ALERT_DANGER_TAG, ALERT_SUCCESS_TAGS, ALERT_DANGER_TAGS, + GRAPHQL_PAGE_SIZE, + FETCH_IMAGES_LIST_ERROR_MESSAGE, } from '../constants/index'; export default { @@ -23,28 +29,61 @@ export default { DeleteAlert, PartialCleanupAlert, DetailsHeader, - GlPagination, + GlKeysetPagination, DeleteModal, TagsList, TagsLoader, EmptyTagsState, }, + inject: ['breadCrumbState', 'config'], directives: { GlResizeObserver: GlResizeObserverDirective, }, mixins: [Tracking.mixin()], + apollo: { + image: { + query: getContainerRepositoryDetailsQuery, + variables() { + return this.queryVariables; + }, + update(data) { + return data.containerRepository; + }, + result({ data }) { + this.tagsPageInfo = data.containerRepository?.tags?.pageInfo; + this.breadCrumbState.updateName(data.containerRepository?.name); + }, + error() { + createFlash({ message: FETCH_IMAGES_LIST_ERROR_MESSAGE }); + }, + }, + }, data() { return { + image: {}, + tagsPageInfo: {}, itemsToBeDeleted: [], isMobile: false, + mutationLoading: false, deleteAlertType: null, dismissPartialCleanupWarning: false, }; }, computed: { - ...mapState(['tagsPagination', 'isLoading', 'config', 'tags', 'imageDetails']), + queryVariables() { + return { + id: joinPaths(this.config.gidPrefix, `${this.$route.params.id}`), + first: GRAPHQL_PAGE_SIZE, + }; + }, + isLoading() { + return this.$apollo.queries.image.loading || this.mutationLoading; + }, + tags() { + return this.image?.tags?.nodes || []; + }, showPartialCleanupWarning() { - return this.imageDetails?.cleanup_policy_started_at && !this.dismissPartialCleanupWarning; + return this.image?.expirationPolicyStartedAt && !this.dismissPartialCleanupWarning; }, tracking() { return { @@ -52,66 +91,78 @@ export default { this.itemsToBeDeleted?.length > 1 ? 'bulk_registry_tag_delete' : 'registry_tag_delete', }; }, - currentPage: { - get() { - return this.tagsPagination.page; - }, - set(page) { - this.requestTagsList({ page }); - }, + showPagination() { + return this.tagsPageInfo.hasPreviousPage || this.tagsPageInfo.hasNextPage; }, }, - mounted() { - this.requestImageDetailsAndTagsList(this.$route.params.id); - }, methods: { - ...mapActions([ - 'requestTagsList', - 'requestDeleteTag', - 'requestDeleteTags', - 'requestImageDetailsAndTagsList', - ]), deleteTags(toBeDeleted) { this.itemsToBeDeleted = this.tags.filter(tag => toBeDeleted[tag.name]); this.track('click_button'); this.$refs.deleteModal.show(); }, - handleSingleDelete() { - const [itemToDelete] = this.itemsToBeDeleted; - this.itemsToBeDeleted = []; - return this.requestDeleteTag({ tag: itemToDelete }) - .then(() => { - this.deleteAlertType = ALERT_SUCCESS_TAG; - }) - .catch(() => { - this.deleteAlertType = ALERT_DANGER_TAG; - }); - }, - handleMultipleDelete() { + async handleDelete() { + this.track('confirm_delete'); const { itemsToBeDeleted } = this; this.itemsToBeDeleted = []; - - return this.requestDeleteTags({ - ids: itemsToBeDeleted.map(x => x.name), - }) - .then(() => { - this.deleteAlertType = ALERT_SUCCESS_TAGS; - }) - .catch(() => { - this.deleteAlertType = ALERT_DANGER_TAGS; + this.mutationLoading = true; + try { + const { data } = await this.$apollo.mutate({ + mutation: deleteContainerRepositoryTagsMutation, + variables: { + id: this.queryVariables.id, + tagNames: itemsToBeDeleted.map(i => i.name), + }, + awaitRefetchQueries: true, + refetchQueries: [ + { + query: getContainerRepositoryDetailsQuery, + variables: this.queryVariables, + }, + ], }); - }, - onDeletionConfirmed() { - this.track('confirm_delete'); - if (this.itemsToBeDeleted.length > 1) { - this.handleMultipleDelete(); - } else { - this.handleSingleDelete(); + + if (data?.destroyContainerRepositoryTags?.errors[0]) { + throw new Error(); + } + this.deleteAlertType = + itemsToBeDeleted.length === 0 ? ALERT_SUCCESS_TAG : ALERT_SUCCESS_TAGS; + } catch (e) { + this.deleteAlertType = itemsToBeDeleted.length === 0 ? ALERT_DANGER_TAG : ALERT_DANGER_TAGS; } + + this.mutationLoading = false; }, handleResize() { this.isMobile = GlBreakpointInstance.getBreakpointSize() === 'xs'; }, + fetchNextPage() { + if (this.tagsPageInfo?.hasNextPage) { + this.$apollo.queries.image.fetchMore({ + variables: { + after: this.tagsPageInfo?.endCursor, + first: GRAPHQL_PAGE_SIZE, + }, + updateQuery(previousResult, { fetchMoreResult }) { + return fetchMoreResult; + }, + }); + } + }, + fetchPreviousPage() { + if (this.tagsPageInfo?.hasPreviousPage) { + this.$apollo.queries.image.fetchMore({ + variables: { + first: null, + before: this.tagsPageInfo?.startCursor, + last: GRAPHQL_PAGE_SIZE, + }, + updateQuery(previousResult, { fetchMoreResult }) { + return fetchMoreResult; + }, + }); + } + }, }, }; </script> @@ -132,28 +183,30 @@ export default { @dismiss="dismissPartialCleanupWarning = true" /> - <details-header :image-name="imageDetails.name" /> + <details-header :image="image" /> <tags-loader v-if="isLoading" /> <template v-else> <empty-tags-state v-if="tags.length === 0" :no-containers-image="config.noContainersImage" /> - <tags-list v-else :tags="tags" :is-mobile="isMobile" @delete="deleteTags" /> + <template v-else> + <tags-list :tags="tags" :is-mobile="isMobile" @delete="deleteTags" /> + <div class="gl-display-flex gl-justify-content-center"> + <gl-keyset-pagination + v-if="showPagination" + :has-next-page="tagsPageInfo.hasNextPage" + :has-previous-page="tagsPageInfo.hasPreviousPage" + class="gl-mt-3" + @prev="fetchPreviousPage" + @next="fetchNextPage" + /> + </div> + </template> </template> - <gl-pagination - v-if="!isLoading" - ref="pagination" - v-model="currentPage" - :per-page="tagsPagination.perPage" - :total-items="tagsPagination.total" - align="center" - class="gl-w-full gl-mt-3" - /> - <delete-modal ref="deleteModal" :items-to-be-deleted="itemsToBeDeleted" - @confirmDelete="onDeletionConfirmed" + @confirmDelete="handleDelete" @cancel="track('cancel_delete')" /> </div> |