diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-01-05 18:10:02 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-01-05 18:10:02 +0300 |
commit | 2c2b5aeac04350b0d3e13d4b52add0b520bf2ebb (patch) | |
tree | 1b006a6d334908dcbdb84d8868ab7cde79a519d7 /app/assets/javascripts/registry | |
parent | 797182cd82922765fe79a13bc0ed6bd5672d4283 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets/javascripts/registry')
8 files changed, 142 insertions, 100 deletions
diff --git a/app/assets/javascripts/registry/explorer/components/list_page/image_list.vue b/app/assets/javascripts/registry/explorer/components/list_page/image_list.vue index f8b3233438f..10ad99d5956 100644 --- a/app/assets/javascripts/registry/explorer/components/list_page/image_list.vue +++ b/app/assets/javascripts/registry/explorer/components/list_page/image_list.vue @@ -13,6 +13,11 @@ export default { type: Array, required: true, }, + metadataLoading: { + type: Boolean, + default: false, + required: false, + }, pageInfo: { type: Object, required: true, @@ -33,6 +38,7 @@ export default { :key="index" :item="listItem" :first="index === 0" + :metadata-loading="metadataLoading" @delete="$emit('delete', $event)" /> <div class="gl-display-flex gl-justify-content-center"> diff --git a/app/assets/javascripts/registry/explorer/components/list_page/image_list_row.vue b/app/assets/javascripts/registry/explorer/components/list_page/image_list_row.vue index f37bc987eb9..264a3c27cde 100644 --- a/app/assets/javascripts/registry/explorer/components/list_page/image_list_row.vue +++ b/app/assets/javascripts/registry/explorer/components/list_page/image_list_row.vue @@ -1,5 +1,5 @@ <script> -import { GlTooltipDirective, GlIcon, GlSprintf } from '@gitlab/ui'; +import { GlTooltipDirective, GlIcon, GlSprintf, GlSkeletonLoader } from '@gitlab/ui'; import { n__ } from '~/locale'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; @@ -25,6 +25,7 @@ export default { GlSprintf, GlIcon, ListItem, + GlSkeletonLoader, }, directives: { GlTooltip: GlTooltipDirective, @@ -34,6 +35,11 @@ export default { type: Object, required: true, }, + metadataLoading: { + type: Boolean, + default: false, + required: false, + }, }, i18n: { LIST_DELETE_BUTTON_DISABLED, @@ -107,7 +113,11 @@ export default { /> </template> <template #left-secondary> - <span class="gl-display-flex gl-align-items-center" data-testid="tagsCount"> + <span + v-if="!metadataLoading" + class="gl-display-flex gl-align-items-center" + data-testid="tags-count" + > <gl-icon name="tag" class="gl-mr-2" /> <gl-sprintf :message="tagsCountText"> <template #count> @@ -115,6 +125,13 @@ export default { </template> </gl-sprintf> </span> + + <div v-else class="gl-w-full"> + <gl-skeleton-loader :width="900" :height="16" preserve-aspect-ratio="xMinYMax meet"> + <circle cx="6" cy="8" r="6" /> + <rect x="16" y="4" width="100" height="8" rx="4" /> + </gl-skeleton-loader> + </div> </template> <template #right-action> <delete-button diff --git a/app/assets/javascripts/registry/explorer/graphql/fragments/container_repository.fragment.graphql b/app/assets/javascripts/registry/explorer/graphql/fragments/container_repository.fragment.graphql deleted file mode 100644 index 9a3579ee8e0..00000000000 --- a/app/assets/javascripts/registry/explorer/graphql/fragments/container_repository.fragment.graphql +++ /dev/null @@ -1,11 +0,0 @@ -fragment ContainerRepositoryFields on ContainerRepository { - id - name - path - status - location - canDelete - createdAt - tagsCount - expirationPolicyStartedAt -} diff --git a/app/assets/javascripts/registry/explorer/graphql/index.js b/app/assets/javascripts/registry/explorer/graphql/index.js index 16152eb81f6..d934bcc7419 100644 --- a/app/assets/javascripts/registry/explorer/graphql/index.js +++ b/app/assets/javascripts/registry/explorer/graphql/index.js @@ -8,6 +8,7 @@ export const apolloProvider = new VueApollo({ defaultClient: createDefaultClient( {}, { + batchMax: 1, assumeImmutableResults: true, }, ), diff --git a/app/assets/javascripts/registry/explorer/graphql/queries/get_container_repositories_details.query.graphql b/app/assets/javascripts/registry/explorer/graphql/queries/get_container_repositories_details.query.graphql new file mode 100644 index 00000000000..8b6d778c655 --- /dev/null +++ b/app/assets/javascripts/registry/explorer/graphql/queries/get_container_repositories_details.query.graphql @@ -0,0 +1,26 @@ +query getContainerRepositoriesDetails( + $fullPath: ID! + $name: String + $first: Int + $last: Int + $after: String + $before: String + $isGroupPage: Boolean! +) { + project(fullPath: $fullPath) @skip(if: $isGroupPage) { + containerRepositories(name: $name, after: $after, before: $before, first: $first, last: $last) { + nodes { + id + tagsCount + } + } + } + group(fullPath: $fullPath) @include(if: $isGroupPage) { + containerRepositories(name: $name, after: $after, before: $before, first: $first, last: $last) { + nodes { + id + tagsCount + } + } + } +} diff --git a/app/assets/javascripts/registry/explorer/graphql/queries/get_group_container_repositories.query.graphql b/app/assets/javascripts/registry/explorer/graphql/queries/get_group_container_repositories.query.graphql deleted file mode 100644 index 348eda97ea7..00000000000 --- a/app/assets/javascripts/registry/explorer/graphql/queries/get_group_container_repositories.query.graphql +++ /dev/null @@ -1,23 +0,0 @@ -#import "~/graphql_shared/fragments/pageInfo.fragment.graphql" -#import "../fragments/container_repository.fragment.graphql" - -query getGroupContainerRepositories( - $fullPath: ID! - $name: String - $first: Int - $last: Int - $after: String - $before: String -) { - group(fullPath: $fullPath) { - containerRepositoriesCount - containerRepositories(name: $name, after: $after, before: $before, first: $first, last: $last) { - nodes { - ...ContainerRepositoryFields - } - pageInfo { - ...PageInfo - } - } - } -} diff --git a/app/assets/javascripts/registry/explorer/graphql/queries/get_project_container_repositories.query.graphql b/app/assets/javascripts/registry/explorer/graphql/queries/get_project_container_repositories.query.graphql deleted file mode 100644 index 338e27745f7..00000000000 --- a/app/assets/javascripts/registry/explorer/graphql/queries/get_project_container_repositories.query.graphql +++ /dev/null @@ -1,23 +0,0 @@ -#import "~/graphql_shared/fragments/pageInfo.fragment.graphql" -#import "../fragments/container_repository.fragment.graphql" - -query getProjectContainerRepositories( - $fullPath: ID! - $name: String - $first: Int - $last: Int - $after: String - $before: String -) { - project(fullPath: $fullPath) { - containerRepositoriesCount - containerRepositories(name: $name, after: $after, before: $before, first: $first, last: $last) { - nodes { - ...ContainerRepositoryFields - } - pageInfo { - ...PageInfo - } - } - } -} diff --git a/app/assets/javascripts/registry/explorer/pages/list.vue b/app/assets/javascripts/registry/explorer/pages/list.vue index 2aa28d450d7..7cbcdb9a5cb 100644 --- a/app/assets/javascripts/registry/explorer/pages/list.vue +++ b/app/assets/javascripts/registry/explorer/pages/list.vue @@ -9,17 +9,13 @@ import { GlSkeletonLoader, GlSearchBoxByClick, } from '@gitlab/ui'; +import { get } from 'lodash'; +import getContainerRepositoriesQuery from 'shared_queries/container_registry/get_container_repositories.query.graphql'; import Tracking from '~/tracking'; import createFlash from '~/flash'; - -import ProjectEmptyState from '../components/list_page/project_empty_state.vue'; -import GroupEmptyState from '../components/list_page/group_empty_state.vue'; import RegistryHeader from '../components/list_page/registry_header.vue'; -import ImageList from '../components/list_page/image_list.vue'; -import CliCommands from '../components/list_page/cli_commands.vue'; -import getProjectContainerRepositoriesQuery from '../graphql/queries/get_project_container_repositories.query.graphql'; -import getGroupContainerRepositoriesQuery from '../graphql/queries/get_group_container_repositories.query.graphql'; +import getContainerRepositoriesDetails from '../graphql/queries/get_container_repositories_details.query.graphql'; import deleteContainerRepositoryMutation from '../graphql/mutations/delete_container_repository.mutation.graphql'; import { @@ -41,9 +37,22 @@ export default { name: 'RegistryListPage', components: { GlEmptyState, - ProjectEmptyState, - GroupEmptyState, - ImageList, + ProjectEmptyState: () => + import( + /* webpackChunkName: 'container_registry_components' */ '../components/list_page/project_empty_state.vue' + ), + GroupEmptyState: () => + import( + /* webpackChunkName: 'container_registry_components' */ '../components/list_page/group_empty_state.vue' + ), + ImageList: () => + import( + /* webpackChunkName: 'container_registry_components' */ '../components/list_page/image_list.vue' + ), + CliCommands: () => + import( + /* webpackChunkName: 'container_registry_components' */ '../components/list_page/cli_commands.vue' + ), GlModal, GlSprintf, GlLink, @@ -51,7 +60,6 @@ export default { GlSkeletonLoader, GlSearchBoxByClick, RegistryHeader, - CliCommands, }, inject: ['config'], directives: { @@ -74,10 +82,8 @@ export default { EMPTY_RESULT_MESSAGE, }, apollo: { - images: { - query() { - return this.graphQlQuery; - }, + baseImages: { + query: getContainerRepositoriesQuery, variables() { return this.queryVariables; }, @@ -92,10 +98,26 @@ export default { createFlash({ message: FETCH_IMAGES_LIST_ERROR_MESSAGE }); }, }, + additionalDetails: { + skip() { + return !this.fetchAdditionalDetails; + }, + query: getContainerRepositoriesDetails, + variables() { + return this.queryVariables; + }, + update(data) { + return data[this.graphqlResource]?.containerRepositories.nodes; + }, + error() { + createFlash({ message: FETCH_IMAGES_LIST_ERROR_MESSAGE }); + }, + }, }, data() { return { - images: [], + baseImages: [], + additionalDetails: [], pageInfo: {}, containerRepositoriesCount: 0, itemToDelete: {}, @@ -103,21 +125,24 @@ export default { searchValue: null, name: null, mutationLoading: false, + fetchAdditionalDetails: false, }; }, computed: { + images() { + return this.baseImages.map((image, index) => ({ + ...image, + ...get(this.additionalDetails, index, {}), + })); + }, graphqlResource() { return this.config.isGroupPage ? 'group' : 'project'; }, - graphQlQuery() { - return this.config.isGroupPage - ? getGroupContainerRepositoriesQuery - : getProjectContainerRepositoriesQuery; - }, queryVariables() { return { name: this.name, fullPath: this.config.isGroupPage ? this.config.groupPath : this.config.projectPath, + isGroupPage: this.config.isGroupPage, first: GRAPHQL_PAGE_SIZE, }; }, @@ -127,7 +152,7 @@ export default { }; }, isLoading() { - return this.$apollo.queries.images.loading || this.mutationLoading; + return this.$apollo.queries.baseImages.loading || this.mutationLoading; }, showCommands() { return Boolean(!this.isLoading && !this.config?.isGroupPage && this.images?.length); @@ -141,6 +166,13 @@ export default { : DELETE_IMAGE_ERROR_MESSAGE; }, }, + mounted() { + // If the two graphql calls - which are not batched - resolve togheter we will have a race + // condition when apollo sets the cache, with this we give the 'base' call an headstart + setTimeout(() => { + this.fetchAdditionalDetails = true; + }, 200); + }, methods: { deleteImage(item) { this.track('click_button'); @@ -175,30 +207,46 @@ export default { this.deleteAlertType = null; this.itemToDelete = {}; }, - fetchNextPage() { + updateQuery(_, { fetchMoreResult }) { + return fetchMoreResult; + }, + async fetchNextPage() { if (this.pageInfo?.hasNextPage) { - this.$apollo.queries.images.fetchMore({ - variables: { - after: this.pageInfo?.endCursor, - first: GRAPHQL_PAGE_SIZE, - }, - updateQuery(previousResult, { fetchMoreResult }) { - return fetchMoreResult; - }, + 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, }); } }, - fetchPreviousPage() { + async fetchPreviousPage() { if (this.pageInfo?.hasPreviousPage) { - this.$apollo.queries.images.fetchMore({ - variables: { - first: null, - before: this.pageInfo?.startCursor, - last: GRAPHQL_PAGE_SIZE, - }, - updateQuery(previousResult, { fetchMoreResult }) { - return fetchMoreResult; - }, + 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, }); } }, @@ -286,6 +334,7 @@ export default { <image-list v-if="images.length" :images="images" + :metadata-loading="$apollo.queries.additionalDetails.loading" :page-info="pageInfo" @delete="deleteImage" @prev-page="fetchPreviousPage" |