diff options
Diffstat (limited to 'app/assets/javascripts/packages_and_registries/container_registry/explorer')
10 files changed, 109 insertions, 115 deletions
diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/details_header.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/details_header.vue index da88f768c03..75af0286e12 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/details_header.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/details_header.vue @@ -1,5 +1,10 @@ <script> -import { GlIcon, GlTooltipDirective, GlDropdown, GlDropdownItem } from '@gitlab/ui'; +import { + GlDisclosureDropdown, + GlDisclosureDropdownItem, + GlIcon, + GlTooltipDirective, +} from '@gitlab/ui'; import { sprintf, n__, s__ } from '~/locale'; import MetadataItem from '~/vue_shared/components/registry/metadata_item.vue'; import TitleArea from '~/vue_shared/components/registry/title_area.vue'; @@ -17,6 +22,8 @@ import { CLEANUP_ONGOING_TOOLTIP, CLEANUP_UNFINISHED_TOOLTIP, CLEANUP_DISABLED_TOOLTIP, + DELETE_IMAGE_TEXT, + MORE_ACTIONS_TEXT, UNFINISHED_STATUS, UNSCHEDULED_STATUS, SCHEDULED_STATUS, @@ -29,7 +36,7 @@ import { getImageName } from '../../utils'; export default { name: 'DetailsHeader', - components: { GlIcon, TitleArea, MetadataItem, GlDropdown, GlDropdownItem }, + components: { GlDisclosureDropdown, GlDisclosureDropdownItem, GlIcon, TitleArea, MetadataItem }, directives: { GlTooltip: GlTooltipDirective, }, @@ -108,6 +115,10 @@ export default { return size ? numberToHumanSize(Number(size)) : null; }, }, + i18n: { + DELETE_IMAGE_TEXT, + MORE_ACTIONS_TEXT, + }, }; </script> @@ -152,20 +163,23 @@ export default { data-testid="created-and-visibility" /> </template> - <template #right-actions> - <gl-dropdown - v-if="!deleteButtonDisabled" - icon="ellipsis_v" - text="More actions" - :text-sr-only="true" + <template v-if="!deleteButtonDisabled" #right-actions> + <gl-disclosure-dropdown category="tertiary" + icon="ellipsis_v" + placement="right" + :toggle-text="$options.i18n.MORE_ACTIONS_TEXT" + text-sr-only no-caret - right > - <gl-dropdown-item variant="danger" @click="$emit('delete')"> - {{ __('Delete image repository') }} - </gl-dropdown-item> - </gl-dropdown> + <gl-disclosure-dropdown-item @action="$emit('delete')"> + <template #list-item> + <span class="gl-text-red-500"> + {{ $options.i18n.DELETE_IMAGE_TEXT }} + </span> + </template> + </gl-disclosure-dropdown-item> + </gl-disclosure-dropdown> </template> </title-area> </template> diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue index 9ea1958a0d1..b58e2249829 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue @@ -2,9 +2,11 @@ import { GlEmptyState } from '@gitlab/ui'; import { createAlert } from '~/alert'; import { n__ } from '~/locale'; +import { fetchPolicies } from '~/lib/graphql'; import { joinPaths } from '~/lib/utils/url_utility'; import Tracking from '~/tracking'; import RegistryList from '~/packages_and_registries/shared/components/registry_list.vue'; +import PersistedPagination from '~/packages_and_registries/shared/components/persisted_pagination.vue'; import PersistedSearch from '~/packages_and_registries/shared/components/persisted_search.vue'; import TagsLoader from '~/packages_and_registries/shared/components/tags_loader.vue'; import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; @@ -26,6 +28,7 @@ import { import getContainerRepositoryTagsQuery from '../../graphql/queries/get_container_repository_tags.query.graphql'; import deleteContainerRepositoryTagsMutation from '../../graphql/mutations/delete_container_repository_tags.mutation.graphql'; import DeleteModal from '../delete_modal.vue'; +import { getPageParams, getNextPageParams, getPreviousPageParams } from '../../utils'; import TagsListRow from './tags_list_row.vue'; export default { @@ -36,6 +39,7 @@ export default { TagsListRow, TagsLoader, RegistryList, + PersistedPagination, PersistedSearch, }, mixins: [Tracking.mixin()], @@ -61,7 +65,7 @@ export default { required: false, }, }, - searchConfig: { NAME_SORT_FIELD }, + sortableFields: [NAME_SORT_FIELD], i18n: { REMOVE_TAGS_BUTTON_TITLE, TAGS_LIST_TITLE, @@ -69,6 +73,7 @@ export default { apollo: { containerRepository: { query: getContainerRepositoryTagsQuery, + fetchPolicy: fetchPolicies.CACHE_AND_NETWORK, skip() { return !this.sort; }, @@ -85,8 +90,9 @@ export default { containerRepository: {}, filters: {}, itemsToBeDeleted: [], - mutationLoading: false, + isDeleteInProgress: false, sort: null, + pageParams: {}, }; }, computed: { @@ -108,6 +114,7 @@ export default { first: GRAPHQL_PAGE_SIZE, name: this.filters?.name, sort: this.sort, + ...this.pageParams, }; }, hasNoTags() { @@ -117,7 +124,7 @@ export default { return ( this.isImageLoading || this.$apollo.queries.containerRepository.loading || - this.mutationLoading || + this.isDeleteInProgress || !this.sort ); }, @@ -149,7 +156,7 @@ export default { async handleDeleteTag() { this.track('confirm_delete'); const { itemsToBeDeleted } = this; - this.mutationLoading = true; + this.isDeleteInProgress = true; try { const { data } = await this.$apollo.mutate({ mutation: deleteContainerRepositoryTagsMutation, @@ -176,27 +183,17 @@ export default { } catch (e) { this.$emit('delete', itemsToBeDeleted.length === 1 ? ALERT_DANGER_TAG : ALERT_DANGER_TAGS); } finally { - this.mutationLoading = false; + this.isDeleteInProgress = false; } }, fetchNextPage() { - this.$apollo.queries.containerRepository.fetchMore({ - variables: { - after: this.tagsPageInfo?.endCursor, - first: GRAPHQL_PAGE_SIZE, - }, - }); + this.pageParams = getNextPageParams(this.tagsPageInfo?.endCursor); }, fetchPreviousPage() { - this.$apollo.queries.containerRepository.fetchMore({ - variables: { - first: null, - before: this.tagsPageInfo?.startCursor, - last: GRAPHQL_PAGE_SIZE, - }, - }); + this.pageParams = getPreviousPageParams(this.tagsPageInfo?.startCursor); }, - handleSearchUpdate({ sort, filters }) { + handleSearchUpdate({ sort, filters, pageInfo }) { + this.pageParams = getPageParams(pageInfo); this.sort = sort; const parsed = { @@ -223,10 +220,8 @@ export default { <div> <persisted-search class="gl-mb-5" - :sortable-fields="/* eslint-disable @gitlab/vue-no-new-non-primitive-in-template */ [ - $options.searchConfig.NAME_SORT_FIELD, - ] /* eslint-enable @gitlab/vue-no-new-non-primitive-in-template */" - :default-order="$options.searchConfig.NAME_SORT_FIELD.orderBy" + :sortable-fields="$options.sortableFields" + :default-order="$options.sortableFields[0].orderBy" default-sort="asc" @update="handleSearchUpdate" /> @@ -243,11 +238,8 @@ export default { <registry-list :hidden-delete="hideBulkDelete" :title="listTitle" - :pagination="tagsPageInfo" :items="tags" id-property="name" - @prev-page="fetchPreviousPage" - @next-page="fetchNextPage" @delete="deleteTags" > <template #default="{ selectItem, isSelected, item, first }"> @@ -271,5 +263,14 @@ export default { /> </template> </template> + + <div v-if="!isDeleteInProgress" class="gl-display-flex gl-justify-content-center"> + <persisted-pagination + class="gl-mt-3" + :pagination="tagsPageInfo" + @prev="fetchPreviousPage" + @next="fetchNextPage" + /> + </div> </div> </template> diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue index a3f58cc3323..c8a4f32d5a7 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list_row.vue @@ -81,7 +81,6 @@ export default { extraAttrs: { class: 'gl-text-red-500!', 'data-testid': 'single-delete-button', - 'data-qa-selector': 'tag_delete_button', }, action: () => { this.$emit('delete'); @@ -143,7 +142,6 @@ export default { <div v-gl-tooltip="{ title: tag.name }" data-testid="name" - data-qa-selector="tag_name_content" class="gl-text-overflow-ellipsis gl-overflow-hidden gl-white-space-nowrap" :class="mobileClasses" > @@ -201,7 +199,6 @@ export default { placement="right" :class="{ 'gl-opacity-0 gl-pointer-events-none': disabled }" data-testid="additional-actions" - data-qa-selector="more_actions_menu" :items="items" /> </template> diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list.vue index 6f1f67e251f..ffba64f58f8 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list.vue @@ -1,11 +1,9 @@ <script> -import { GlKeysetPagination } from '@gitlab/ui'; import ImageListRow from './image_list_row.vue'; export default { name: 'ImageList', components: { - GlKeysetPagination, ImageListRow, }, props: { @@ -18,21 +16,12 @@ export default { default: false, required: false, }, - pageInfo: { - type: Object, - required: true, - }, expirationPolicy: { type: Object, default: () => ({}), required: false, }, }, - computed: { - showPagination() { - return this.pageInfo.hasPreviousPage || this.pageInfo.hasNextPage; - }, - }, }; </script> @@ -46,15 +35,5 @@ export default { :expiration-policy="expirationPolicy" @delete="$emit('delete', $event)" /> - <div class="gl-display-flex gl-justify-content-center"> - <gl-keyset-pagination - v-if="showPagination" - :has-next-page="pageInfo.hasNextPage" - :has-previous-page="pageInfo.hasPreviousPage" - class="gl-mt-3" - @prev="$emit('prev-page')" - @next="$emit('next-page')" - /> - </div> </div> </template> diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue index f6f816f435c..d7043626446 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/list_page/image_list_row.vue @@ -133,7 +133,6 @@ export default { ref="imageName" class="gl-text-body gl-font-weight-bold" data-testid="details-link" - data-qa-selector="registry_image_content" :to="{ name: 'details', params: { id } }" > {{ imageName }} diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/details.js b/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/details.js index 3a5992d182a..ab848d209db 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/details.js +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/constants/details.js @@ -93,6 +93,7 @@ export const DETAILS_DELETE_IMAGE_ERROR_MESSAGE = s__( 'ContainerRegistry|Something went wrong while scheduling the image for deletion.', ); +export const DELETE_IMAGE_TEXT = s__('ContainerRegistry|Delete image repository'); export const DELETE_IMAGE_CONFIRMATION_TITLE = s__('ContainerRegistry|Delete image repository?'); export const DELETE_IMAGE_CONFIRMATION_TEXT = s__( 'ContainerRegistry|Deleting the image repository will delete all images and tags inside. This action cannot be undone. Please type the following to confirm: %{code}', diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/details.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/details.vue index 3126af69c2c..c266dbf7e98 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/details.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/details.vue @@ -1,11 +1,10 @@ <script> -import { GlResizeObserverDirective, GlEmptyState } from '@gitlab/ui'; +import { GlResizeObserverDirective, GlEmptyState, GlSkeletonLoader } from '@gitlab/ui'; import { GlBreakpointInstance } from '@gitlab/ui/dist/utils'; import { createAlert } from '~/alert'; import axios from '~/lib/utils/axios_utils'; import { joinPaths } from '~/lib/utils/url_utility'; import Tracking from '~/tracking'; -import TagsLoader from '~/packages_and_registries/shared/components/tags_loader.vue'; import DeleteImage from '../components/delete_image.vue'; import DeleteAlert from '../components/details_page/delete_alert.vue'; import DeleteModal from '../components/delete_modal.vue'; @@ -28,12 +27,12 @@ export default { name: 'RegistryDetailsPage', components: { GlEmptyState, + GlSkeletonLoader, DeleteAlert, PartialCleanupAlert, DetailsHeader, DeleteModal, TagsList, - TagsLoader, StatusAlert, DeleteImage, }, @@ -151,16 +150,17 @@ export default { <status-alert v-if="containerRepository.status" :status="containerRepository.status" /> + <div v-if="isLoading" class="gl-my-6"> + <gl-skeleton-loader /> + </div> <details-header - v-if="!isLoading" + v-else :image="containerRepository" :disabled="pageActionsAreDisabled" @delete="deleteImage" /> - <tags-loader v-if="isLoading" /> <tags-list - v-else :id="$route.params.id" :is-image-loading="isLoading" :is-mobile="isMobile" diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/index.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/index.vue index dca63e1a569..ca0261f1036 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/index.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/index.vue @@ -1,3 +1,4 @@ +<!-- eslint-disable vue/multi-word-component-names --> <template> <div> <router-view ref="router-view" /> diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/list.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/list.vue index fe29fa8fdd7..df87ee79111 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/list.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/list.vue @@ -12,7 +12,9 @@ import { get } from 'lodash'; import getContainerRepositoriesQuery from 'shared_queries/container_registry/get_container_repositories.query.graphql'; import { createAlert } from '~/alert'; import { WORKSPACE_GROUP, WORKSPACE_PROJECT } from '~/issues/constants'; +import { fetchPolicies } from '~/lib/graphql'; import Tracking from '~/tracking'; +import PersistedPagination from '~/packages_and_registries/shared/components/persisted_pagination.vue'; import PersistedSearch from '~/packages_and_registries/shared/components/persisted_search.vue'; import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; import DeleteImage from '../components/delete_image.vue'; @@ -32,6 +34,7 @@ import { SETTINGS_TEXT, } from '../constants/index'; import getContainerRepositoriesDetails from '../graphql/queries/get_container_repositories_details.query.graphql'; +import { getPageParams, getNextPageParams, getPreviousPageParams } from '../utils'; export default { name: 'RegistryListPage', @@ -61,6 +64,7 @@ export default { GlSkeletonLoader, RegistryHeader, DeleteImage, + PersistedPagination, PersistedSearch, }, directives: { @@ -87,6 +91,7 @@ export default { return !this.fetchBaseQuery; }, query: getContainerRepositoriesQuery, + fetchPolicy: fetchPolicies.CACHE_AND_NETWORK, variables() { return this.queryVariables; }, @@ -109,6 +114,7 @@ export default { return !this.fetchAdditionalDetails; }, query: getContainerRepositoriesDetails, + fetchPolicy: fetchPolicies.CACHE_AND_NETWORK, variables() { return this.queryVariables; }, @@ -133,6 +139,7 @@ export default { mutationLoading: false, fetchBaseQuery: false, fetchAdditionalDetails: false, + pageParams: {}, }; }, computed: { @@ -158,6 +165,7 @@ export default { fullPath: this.config.isGroupPage ? this.config.groupPath : this.config.projectPath, isGroupPage: this.config.isGroupPage, first: GRAPHQL_PAGE_SIZE, + ...this.pageParams, }; }, tracking() { @@ -193,54 +201,18 @@ export default { this.deleteAlertType = null; this.itemToDelete = {}; }, - updateQuery(_, { fetchMoreResult }) { - return fetchMoreResult; + fetchNextPage() { + this.pageParams = getNextPageParams(this.pageInfo?.endCursor); }, - async fetchNextPage() { - if (this.pageInfo?.hasNextPage) { - const variables = { - after: this.pageInfo?.endCursor, - first: GRAPHQL_PAGE_SIZE, - }; - - this.$apollo.queries.baseImages.fetchMore({ - variables, - updateQuery: this.updateQuery, - }); - - await this.$nextTick(); - - this.$apollo.queries.additionalDetails.fetchMore({ - variables, - updateQuery: this.updateQuery, - }); - } - }, - async fetchPreviousPage() { - if (this.pageInfo?.hasPreviousPage) { - const variables = { - first: null, - before: this.pageInfo?.startCursor, - last: GRAPHQL_PAGE_SIZE, - }; - this.$apollo.queries.baseImages.fetchMore({ - variables, - updateQuery: this.updateQuery, - }); - - await this.$nextTick(); - - this.$apollo.queries.additionalDetails.fetchMore({ - variables, - updateQuery: this.updateQuery, - }); - } + fetchPreviousPage() { + this.pageParams = getPreviousPageParams(this.pageInfo?.startCursor); }, startDelete() { this.track('confirm_delete'); this.mutationLoading = true; }, - handleSearchUpdate({ sort, filters }) { + handleSearchUpdate({ sort, filters, pageInfo }) { + this.pageParams = getPageParams(pageInfo); this.sorting = sort; const search = filters.find((i) => i.type === FILTERED_SEARCH_TERM); @@ -346,11 +318,8 @@ export default { v-if="images.length" :images="images" :metadata-loading="$apollo.queries.additionalDetails.loading" - :page-info="pageInfo" :expiration-policy="config.expirationPolicy" @delete="deleteImage" - @prev-page="fetchPreviousPage" - @next-page="fetchNextPage" /> <gl-empty-state @@ -370,6 +339,15 @@ export default { </template> </template> + <div v-if="!mutationLoading" class="gl-display-flex gl-justify-content-center"> + <persisted-pagination + class="gl-mt-3" + :pagination="pageInfo" + @prev="fetchPreviousPage" + @next="fetchNextPage" + /> + </div> + <delete-image :id="itemToDelete.id" @start="startDelete" diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/utils.js b/app/assets/javascripts/packages_and_registries/container_registry/explorer/utils.js index 751ab5180a1..7ed4ff52b06 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/utils.js +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/utils.js @@ -1,4 +1,5 @@ import { approximateDuration, calculateRemainingMilliseconds } from '~/lib/utils/datetime_utility'; +import { GRAPHQL_PAGE_SIZE } from './constants/index'; export const getImageName = (image = {}) => { return image.name || image.project?.path; @@ -10,3 +11,26 @@ export const timeTilRun = (time) => { const difference = calculateRemainingMilliseconds(time); return approximateDuration(difference / 1000); }; + +export const getNextPageParams = (cursor) => ({ + after: cursor, + first: GRAPHQL_PAGE_SIZE, +}); + +export const getPreviousPageParams = (cursor) => ({ + first: null, + before: cursor, + last: GRAPHQL_PAGE_SIZE, +}); + +export const getPageParams = (pageInfo = {}) => { + if (pageInfo.before) { + return getPreviousPageParams(pageInfo.before); + } + + if (pageInfo.after) { + return getNextPageParams(pageInfo.after); + } + + return {}; +}; |