diff --git a/ee/app/assets/javascripts/security_configuration/corpus_management/components/corpus_management.vue b/ee/app/assets/javascripts/security_configuration/corpus_management/components/corpus_management.vue index 1e69b31d639e36db71f7c8a688c496cf09fc8c92..23103b5260e42672531286c87195d760e437ade0 100644 --- a/ee/app/assets/javascripts/security_configuration/corpus_management/components/corpus_management.vue +++ b/ee/app/assets/javascripts/security_configuration/corpus_management/components/corpus_management.vue @@ -1,5 +1,5 @@ <script> -import { GlLoadingIcon, GlLink } from '@gitlab/ui'; +import { GlLoadingIcon, GlLink, GlKeysetPagination } from '@gitlab/ui'; import CorpusTable from 'ee/security_configuration/corpus_management/components/corpus_table.vue'; import CorpusUpload from 'ee/security_configuration/corpus_management/components/corpus_upload.vue'; import { s__, __ } from '~/locale'; @@ -9,6 +9,7 @@ export default { components: { GlLoadingIcon, GlLink, + GlKeysetPagination, CorpusTable, CorpusUpload, }, @@ -16,12 +17,14 @@ export default { states: { query: getCorpusesQuery, variables() { - return { - projectPath: this.projectFullPath, - }; + return this.queryVariables; }, update: (data) => { - return data; + const { pageInfo } = data.project.corpuses; + return { + ...data, + pageInfo, + }; }, error() { this.states = null; @@ -29,20 +32,67 @@ export default { }, }, inject: ['projectFullPath', 'corpusHelpPath'], + data() { + return { + pagination: { + firstPageSize: this.$options.pageSize, + lastPageSize: null, + }, + }; + }, + pageSize: 10, i18n: { header: s__('CorpusManagement|Fuzz testing corpus management'), subHeader: s__( 'CorpusManagement|Corpus are used in fuzz testing as mutation source to Improve future testing.', ), learnMore: __('Learn More'), + previousPage: __('Prev'), + nextPage: __('Next'), }, computed: { corpuses() { return this.states?.project.corpuses.nodes || []; }, + pageInfo() { + return this.states?.pageInfo || {}; + }, isLoading() { return this.$apollo.loading; }, + queryVariables() { + return { + projectPath: this.projectFullPath, + ...this.pagination, + }; + }, + hasPagination() { + return Boolean(this.states) && (this.pageInfo.hasPreviousPage || this.pageInfo.hasNextPage); + }, + }, + methods: { + fetchCorpuses() { + this.pagination = { + afterCursor: null, + beforeCursor: null, + firstPageSize: this.$options.pageSize, + }; + this.$apollo.queries.states.refetch(); + }, + nextPage() { + this.pagination = { + firstPageSize: this.$options.pageSize, + lastPageSize: null, + afterCursor: this.states.pageInfo.endCursor, + }; + }, + prevPage() { + this.pagination = { + firstPageSize: null, + lastPageSize: this.$options.pageSize, + beforeCursor: this.states.pageInfo.startCursor, + }; + }, }, }; </script> @@ -59,10 +109,21 @@ export default { </p> </header> - <gl-loading-icon v-if="isLoading" size="lg" /> + <corpus-upload @corpus-added="fetchCorpuses" /> + + <gl-loading-icon v-if="isLoading" size="lg" class="gl-py-13" /> <template v-else> - <corpus-upload /> <corpus-table :corpuses="corpuses" /> </template> + + <div v-if="hasPagination" class="gl-display-flex gl-justify-content-center gl-mt-5"> + <gl-keyset-pagination + v-bind="pageInfo" + :prev-text="$options.i18n.previousPage" + :next-text="$options.i18n.nextPage" + @prev="prevPage" + @next="nextPage" + /> + </div> </div> </template> diff --git a/ee/app/assets/javascripts/security_configuration/corpus_management/components/corpus_table.vue b/ee/app/assets/javascripts/security_configuration/corpus_management/components/corpus_table.vue index f8f00391dc954dd25af3cc0335fa8b196aa1bd0b..7a61f2401b5f22619972d929841cbec04f7452c7 100644 --- a/ee/app/assets/javascripts/security_configuration/corpus_management/components/corpus_table.vue +++ b/ee/app/assets/javascripts/security_configuration/corpus_management/components/corpus_table.vue @@ -52,6 +52,9 @@ export default { thClass, }, ], + i18n: { + emptyTable: s__('CorpusManagement|Currently, there are no uploaded or generated corpuses.'), + }, methods: { onDelete({ name }) { this.$apollo.mutate({ @@ -73,7 +76,11 @@ export default { }; </script> <template> - <gl-table :items="corpuses" :fields="$options.fields"> + <gl-table :items="corpuses" :fields="$options.fields" show-empty> + <template #empty> + {{ $options.i18n.emptyTable }} + </template> + <template #cell(name)="{ item }"> <name :corpus="item" /> </template> diff --git a/ee/app/assets/javascripts/security_configuration/corpus_management/components/corpus_upload.vue b/ee/app/assets/javascripts/security_configuration/corpus_management/components/corpus_upload.vue index 4c2f8c283052d2c8f0206d14582daa4c019f8a6c..4f0431d456b2f6ab5749e07b22066ba7f18c1d6d 100644 --- a/ee/app/assets/javascripts/security_configuration/corpus_management/components/corpus_upload.vue +++ b/ee/app/assets/javascripts/security_configuration/corpus_management/components/corpus_upload.vue @@ -5,7 +5,7 @@ import { s__, __ } from '~/locale'; import addCorpusMutation from '../graphql/mutations/add_corpus.mutation.graphql'; import resetCorpus from '../graphql/mutations/reset_corpus.mutation.graphql'; import uploadCorpus from '../graphql/mutations/upload_corpus.mutation.graphql'; -import getCorpusesQuery from '../graphql/queries/get_corpuses.query.graphql'; +import getUploadState from '../graphql/queries/get_upload_state.query.graphql'; import CorpusUploadForm from './corpus_upload_form.vue'; export default { @@ -26,10 +26,7 @@ export default { inject: ['projectFullPath'], apollo: { states: { - query: getCorpusesQuery, - variables() { - return this.queryVariables; - }, + query: getUploadState, update(data) { return data; }, @@ -76,20 +73,18 @@ export default { }, methods: { addCorpus() { - this.$apollo.mutate({ - mutation: addCorpusMutation, - refetchQueries: [ - { - query: getCorpusesQuery, - variables: this.queryVariables, + return this.$apollo + .mutate({ + mutation: addCorpusMutation, + variables: { + name: this.$options.i18n.newCorpus, + projectPath: this.projectFullPath, + packageId: this.states.uploadState.uploadedPackageId, }, - ], - variables: { - name: this.$options.i18n.newCorpus, - projectPath: this.projectFullPath, - packageId: this.states.uploadState.uploadedPackageId, - }, - }); + }) + .then(() => { + this.$emit('corpus-added'); + }); }, resetCorpus() { this.$apollo.mutate({ diff --git a/ee/app/assets/javascripts/security_configuration/corpus_management/graphql/fragments/uploadState.fragment.graphql b/ee/app/assets/javascripts/security_configuration/corpus_management/graphql/fragments/uploadState.fragment.graphql new file mode 100644 index 0000000000000000000000000000000000000000..d3e36cbadb6ddd83ff184b90d5b022ff2482b2a3 --- /dev/null +++ b/ee/app/assets/javascripts/security_configuration/corpus_management/graphql/fragments/uploadState.fragment.graphql @@ -0,0 +1,6 @@ +fragment UploadState on UploadState { + isUploading + progress + cancelSource + uploadedPackageId +} diff --git a/ee/app/assets/javascripts/security_configuration/corpus_management/graphql/queries/get_corpuses.query.graphql b/ee/app/assets/javascripts/security_configuration/corpus_management/graphql/queries/get_corpuses.query.graphql index a1454f3a31b8591e80f53c8fc1182b08dafa62be..4f15693581b7d96496a0fb7260132389f3854ff4 100644 --- a/ee/app/assets/javascripts/security_configuration/corpus_management/graphql/queries/get_corpuses.query.graphql +++ b/ee/app/assets/javascripts/security_configuration/corpus_management/graphql/queries/get_corpuses.query.graphql @@ -1,7 +1,21 @@ -query getCorpuses($projectPath: ID!) { +#import "~/graphql_shared/fragments/pageInfo.fragment.graphql" +#import "../fragments/uploadState.fragment.graphql" + +query getCorpuses( + $projectPath: ID! + $beforeCursor: String = "" + $afterCursor: String = "" + $firstPageSize: Int + $lastPageSize: Int +) { project(fullPath: $projectPath) { id - corpuses { + corpuses( + before: $beforeCursor + after: $afterCursor + first: $firstPageSize + last: $lastPageSize + ) { nodes { id package { @@ -24,12 +38,12 @@ query getCorpuses($projectPath: ID!) { } } } + pageInfo { + ...PageInfo + } } } - uploadState(projectPath: $projectPath) @client { - isUploading - progress - cancelSource - uploadedPackageId + uploadState @client { + ...UploadState } } diff --git a/ee/app/assets/javascripts/security_configuration/corpus_management/graphql/queries/get_upload_state.query.graphql b/ee/app/assets/javascripts/security_configuration/corpus_management/graphql/queries/get_upload_state.query.graphql new file mode 100644 index 0000000000000000000000000000000000000000..b0500883c6ae8641936df3daa68a33c56dcca615 --- /dev/null +++ b/ee/app/assets/javascripts/security_configuration/corpus_management/graphql/queries/get_upload_state.query.graphql @@ -0,0 +1,7 @@ +#import "../fragments/uploadState.fragment.graphql" + +query getUploadState { + uploadState @client { + ...UploadState + } +} diff --git a/ee/app/assets/javascripts/security_configuration/corpus_management/graphql/resolvers/resolvers.js b/ee/app/assets/javascripts/security_configuration/corpus_management/graphql/resolvers/resolvers.js index 1a5bef734570d4de46c2d92ba22d305e072bfd0d..fa4206da8edec0ef6b4c6968e0843dc1262d6e74 100644 --- a/ee/app/assets/javascripts/security_configuration/corpus_management/graphql/resolvers/resolvers.js +++ b/ee/app/assets/javascripts/security_configuration/corpus_management/graphql/resolvers/resolvers.js @@ -3,15 +3,14 @@ import { publishPackage } from '~/api/packages_api'; import axios from '~/lib/utils/axios_utils'; import { convertToGraphQLId } from '~/graphql_shared/utils'; import { TYPE_PACKAGES_PACKAGE } from '~/graphql_shared/constants'; -import getCorpusesQuery from '../queries/get_corpuses.query.graphql'; +import getUploadState from '../queries/get_upload_state.query.graphql'; import updateProgress from '../mutations/update_progress.mutation.graphql'; import uploadComplete from '../mutations/upload_complete.mutation.graphql'; import corpusCreate from '../mutations/corpus_create.mutation.graphql'; export default { Query: { - /* eslint-disable no-unused-vars */ - uploadState(_, { projectPath }) { + uploadState() { return { isUploading: false, progress: 0, @@ -24,7 +23,7 @@ export default { Mutation: { addCorpus: (_, { projectPath, packageId }, { cache, client }) => { const sourceData = cache.readQuery({ - query: getCorpusesQuery, + query: getUploadState, variables: { projectPath }, }); @@ -33,7 +32,7 @@ export default { draftState.uploadState.progress = 0; }); - cache.writeQuery({ query: getCorpusesQuery, data, variables: { projectPath } }); + cache.writeQuery({ query: getUploadState, data, variables: { projectPath } }); client.mutate({ mutation: corpusCreate, @@ -60,7 +59,7 @@ export default { const source = CancelToken.source(); const sourceData = cache.readQuery({ - query: getCorpusesQuery, + query: getUploadState, variables: { projectPath }, }); @@ -70,7 +69,7 @@ export default { uploadState.cancelSource = source; }); - cache.writeQuery({ query: getCorpusesQuery, data: targetData, variables: { projectPath } }); + cache.writeQuery({ query: getUploadState, data: targetData, variables: { projectPath } }); publishPackage( { projectPath, name, version: 0, fileName: `${name}.zip`, files }, @@ -83,13 +82,13 @@ export default { variables: { projectPath, packageId: data.package_id }, }); }) - .catch((e) => { + .catch(() => { /* TODO: Error handling */ }); }, uploadComplete: (_, { projectPath, packageId }, { cache }) => { const sourceData = cache.readQuery({ - query: getCorpusesQuery, + query: getUploadState, variables: { projectPath }, }); @@ -100,11 +99,11 @@ export default { uploadState.uploadedPackageId = packageId; }); - cache.writeQuery({ query: getCorpusesQuery, data, variables: { projectPath } }); + cache.writeQuery({ query: getUploadState, data, variables: { projectPath } }); }, updateProgress: (_, { projectPath, progress }, { cache }) => { const sourceData = cache.readQuery({ - query: getCorpusesQuery, + query: getUploadState, variables: { projectPath }, }); @@ -114,11 +113,11 @@ export default { uploadState.progress = progress; }); - cache.writeQuery({ query: getCorpusesQuery, data, variables: { projectPath } }); + cache.writeQuery({ query: getUploadState, data, variables: { projectPath } }); }, resetCorpus: (_, { projectPath }, { cache }) => { const sourceData = cache.readQuery({ - query: getCorpusesQuery, + query: getUploadState, variables: { projectPath }, }); @@ -131,7 +130,7 @@ export default { uploadState.cancelToken = null; }); - cache.writeQuery({ query: getCorpusesQuery, data, variables: { projectPath } }); + cache.writeQuery({ query: getUploadState, data, variables: { projectPath } }); }, }, }; diff --git a/ee/spec/frontend/security_configuration/corpus_management/corpus_management_spec.js b/ee/spec/frontend/security_configuration/corpus_management/corpus_management_spec.js index e534f40049b25965e781c7083eb5ca00dd64c130..d55cec0ca8c1d748de14c92f1d83ac7011773c8a 100644 --- a/ee/spec/frontend/security_configuration/corpus_management/corpus_management_spec.js +++ b/ee/spec/frontend/security_configuration/corpus_management/corpus_management_spec.js @@ -1,9 +1,18 @@ -import { GlLoadingIcon } from '@gitlab/ui'; +import { merge } from 'lodash'; +import { GlLoadingIcon, GlKeysetPagination } from '@gitlab/ui'; +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; import { shallowMount } from '@vue/test-utils'; + import CorpusManagement from 'ee/security_configuration/corpus_management/components/corpus_management.vue'; import CorpusTable from 'ee/security_configuration/corpus_management/components/corpus_table.vue'; import CorpusUpload from 'ee/security_configuration/corpus_management/components/corpus_upload.vue'; -import { corpuses } from './mock_data'; +import getCorpusesQuery from 'ee/security_configuration/corpus_management/graphql/queries/get_corpuses.query.graphql'; + +import createMockApollo from 'helpers/mock_apollo_helper'; +import waitForPromises from 'helpers/wait_for_promises'; + +import { getCorpusesQueryResponse } from './mock_data'; const TEST_PROJECT_FULL_PATH = '/namespace/project'; const TEST_CORPUS_HELP_PATH = '/docs/corpus-management'; @@ -11,19 +20,49 @@ const TEST_CORPUS_HELP_PATH = '/docs/corpus-management'; describe('EE - CorpusManagement', () => { let wrapper; - const createComponentFactory = (mountFn = shallowMount) => (options = {}) => { - const defaultMocks = { - $apollo: { - loading: false, + const createMockApolloProvider = ({ + getCorpusesQueryRequestHandler = jest.fn().mockResolvedValue(getCorpusesQueryResponse), + } = {}) => { + Vue.use(VueApollo); + + const requestHandlers = [[getCorpusesQuery, getCorpusesQueryRequestHandler]]; + + const mockResolvers = { + Query: { + uploadState() { + return { + isUploading: false, + progress: 0, + cancelSource: null, + uploadedPackageId: null, + __typename: 'UploadState', + }; + }, }, }; + return createMockApollo(requestHandlers, mockResolvers); + }; + + const findPagination = () => wrapper.findComponent(GlKeysetPagination); + + const nextPage = (cursor) => { + findPagination().vm.$emit('next', cursor); + return findPagination().vm.$nextTick(); + }; + + const prevPage = (cursor) => { + findPagination().vm.$emit('prev', cursor); + return findPagination().vm.$nextTick(); + }; + + const createComponentFactory = (mountFn = shallowMount) => (options = {}) => { wrapper = mountFn(CorpusManagement, { - mocks: defaultMocks, provide: { projectFullPath: TEST_PROJECT_FULL_PATH, corpusHelpPath: TEST_CORPUS_HELP_PATH, }, + apolloProvider: createMockApolloProvider(), ...options, }); }; @@ -36,39 +75,119 @@ describe('EE - CorpusManagement', () => { describe('corpus management', () => { describe('when loaded', () => { - beforeEach(() => { - const data = () => { - return { states: { project: { corpuses } } }; - }; - - createComponent({ data }); - }); + it('bootstraps and renders the component', async () => { + createComponent(); + await waitForPromises(); - it('bootstraps and renders the component', () => { expect(wrapper.findComponent(CorpusManagement).exists()).toBe(true); expect(wrapper.findComponent(CorpusTable).exists()).toBe(true); expect(wrapper.findComponent(CorpusUpload).exists()).toBe(true); expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(false); }); - it('renders the correct header', () => { + it('renders the correct header', async () => { + createComponent(); + await waitForPromises(); + const header = wrapper.findComponent(CorpusManagement).find('header'); expect(header.element).toMatchSnapshot(); }); + + describe('pagination', () => { + it('hides pagination when no previous or next pages are available', async () => { + createComponent({ + apolloProvider: createMockApolloProvider({ + getCorpusesQueryRequestHandler: jest.fn().mockResolvedValue( + merge({}, getCorpusesQueryResponse, { + data: { + project: { + corpuses: { + pageInfo: { + hasNextPage: false, + hasPreviousPage: false, + }, + }, + }, + }, + }), + ), + }), + }); + await waitForPromises(); + + expect(findPagination().exists()).toBe(false); + }); + + it('passes correct props to GlKeysetPagination', async () => { + createComponent(); + await waitForPromises(); + + expect(findPagination().exists()).toBe(true); + expect(findPagination().props()).toMatchObject({ + disabled: false, + endCursor: 'end-cursor', + hasNextPage: true, + hasPreviousPage: true, + nextButtonLink: null, + nextText: 'Next', + prevButtonLink: null, + prevText: 'Prev', + startCursor: 'start-cursor', + }); + }); + + it('updates query variables when going to previous page', async () => { + const getCorpusesQueryRequestHandler = jest + .fn() + .mockResolvedValue(getCorpusesQueryResponse); + + createComponent({ + apolloProvider: createMockApolloProvider({ getCorpusesQueryRequestHandler }), + }); + await waitForPromises(); + + await prevPage(getCorpusesQueryResponse.data.project.corpuses.pageInfo.startCursor); + + expect(getCorpusesQueryRequestHandler).toHaveBeenCalledWith({ + beforeCursor: getCorpusesQueryResponse.data.project.corpuses.pageInfo.startCursor, + afterCursor: '', + projectPath: TEST_PROJECT_FULL_PATH, + lastPageSize: 10, + firstPageSize: null, + }); + }); + + it('updates query variables when going to next page', async () => { + const getCorpusesQueryRequestHandler = jest + .fn() + .mockResolvedValue(getCorpusesQueryResponse); + + createComponent({ + apolloProvider: createMockApolloProvider({ getCorpusesQueryRequestHandler }), + }); + await waitForPromises(); + + await nextPage(getCorpusesQueryResponse.data.project.corpuses.pageInfo.endCursor); + + expect(getCorpusesQueryRequestHandler).toHaveBeenLastCalledWith({ + afterCursor: getCorpusesQueryResponse.data.project.corpuses.pageInfo.endCursor, + beforeCursor: '', + projectPath: TEST_PROJECT_FULL_PATH, + firstPageSize: 10, + lastPageSize: null, + }); + }); + }); }); describe('when loading', () => { it('shows loading state when loading', () => { - const mocks = { - $apollo: { - loading: jest.fn().mockResolvedValue(true), - }, - }; - createComponent({ mocks }); + createComponent(); + expect(wrapper.findComponent(CorpusManagement).exists()).toBe(true); + expect(wrapper.findComponent(CorpusUpload).exists()).toBe(true); expect(wrapper.findComponent(GlLoadingIcon).exists()).toBe(true); expect(wrapper.findComponent(CorpusTable).exists()).toBe(false); - expect(wrapper.findComponent(CorpusUpload).exists()).toBe(false); }); }); }); diff --git a/ee/spec/frontend/security_configuration/corpus_management/corpus_table_spec.js b/ee/spec/frontend/security_configuration/corpus_management/corpus_table_spec.js index 85adfb39bf59ba48675aaacabb03ccbb28b08e26..275dd550ccc83146426a846f535b0960754f7e5c 100644 --- a/ee/spec/frontend/security_configuration/corpus_management/corpus_table_spec.js +++ b/ee/spec/frontend/security_configuration/corpus_management/corpus_table_spec.js @@ -60,5 +60,13 @@ describe('Corpus table', () => { actionComponent.vm.$emit('delete', 'corpus-name'); expect(mutate).toHaveBeenCalledTimes(1); }); + + describe('with no corpuses', () => { + it('renders the empty state', async () => { + wrapper.setProps({ corpuses: [] }); + await wrapper.vm.$nextTick(); + expect(wrapper.text()).toContain('Currently, there are no uploaded or generated corpuses'); + }); + }); }); }); diff --git a/ee/spec/frontend/security_configuration/corpus_management/mock_data.js b/ee/spec/frontend/security_configuration/corpus_management/mock_data.js index a893c728104cc236b8adb135ddc74730d6552450..7908454d0dc9b38bb88fd08101e27fa52ddb8bb1 100644 --- a/ee/spec/frontend/security_configuration/corpus_management/mock_data.js +++ b/ee/spec/frontend/security_configuration/corpus_management/mock_data.js @@ -1,9 +1,10 @@ const pipelines = { nodes: [ { + id: 'gid://gitlab/Packages::PackagePipelines/1', ref: 'farias-gl/go-fuzzing-example', path: 'gitlab-examples/security/security-reports/-/jobs/1107103952', - updatedAt: new Date(2020, 4, 3).toString(), + createdAt: new Date(2020, 4, 3).toString(), }, ], }; @@ -11,6 +12,7 @@ const pipelines = { const packageFiles = { nodes: [ { + id: 'gid://gitlab/Packages::PackageFile/1', downloadPath: '/download-path', size: 4e8, }, @@ -19,7 +21,9 @@ const packageFiles = { export const corpuses = [ { + id: 'gid://gitlab/AppSec::Fuzzing::Coverage::Corpus/1', package: { + id: 'gid://gitlab/Packages::Package/1', name: 'Corpus-sample-1-13830-23932', updatedAt: new Date(2021, 2, 12).toString(), pipelines, @@ -27,7 +31,9 @@ export const corpuses = [ }, }, { + id: 'gid://gitlab/AppSec::Fuzzing::Coverage::Corpus/2', package: { + id: 'gid://gitlab/Packages::Package/2', name: 'Corpus-sample-2-5830-2393', updatedAt: new Date(2021, 3, 12).toString(), pipelines, @@ -35,7 +41,9 @@ export const corpuses = [ }, }, { + id: 'gid://gitlab/AppSec::Fuzzing::Coverage::Corpus/3', package: { + id: 'gid://gitlab/Packages::Package/3', name: 'Corpus-sample-3-1431-4425', updatedAt: new Date(2021, 4, 12).toString(), pipelines: { @@ -49,6 +57,7 @@ export const corpuses = [ packageFiles: { nodes: [ { + id: 'gid://gitlab/Packages::PackageFile/1', downloadPath: '/download-path', size: 3.21e8, }, @@ -57,7 +66,9 @@ export const corpuses = [ }, }, { + id: 'gid://gitlab/AppSec::Fuzzing::Coverage::Corpus/4', package: { + id: 'gid://gitlab/Packages::Package/3', name: 'Corpus-sample-4-5830-1393', updatedAt: new Date(2021, 5, 12).toString(), pipelines, @@ -65,7 +76,9 @@ export const corpuses = [ }, }, { + id: 'gid://gitlab/AppSec::Fuzzing::Coverage::Corpus/5', package: { + id: 'gid://gitlab/Packages::Package/4', name: 'Corpus-sample-5-13830-23932', updatedAt: new Date(2021, 6, 12).toString(), pipelines, @@ -73,7 +86,9 @@ export const corpuses = [ }, }, { + id: 'gid://gitlab/AppSec::Fuzzing::Coverage::Corpus/6', package: { + id: 'gid://gitlab/Packages::Package/5', name: 'Corpus-sample-6-2450-2393', updatedAt: new Date(2021, 7, 12).toString(), pipelines, @@ -81,3 +96,20 @@ export const corpuses = [ }, }, ]; + +export const getCorpusesQueryResponse = { + data: { + project: { + id: 'gid://gitlab/Project/8', + corpuses: { + nodes: corpuses, + pageInfo: { + hasNextPage: true, + hasPreviousPage: true, + startCursor: 'start-cursor', + endCursor: 'end-cursor', + }, + }, + }, + }, +}; diff --git a/locale/gitlab.pot b/locale/gitlab.pot index fb5ae5d8ee20a58386f299de24e678887856647c..9f17aa7b5c3fb7ed50f738b28ccd0ae7a99efca6 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -9763,6 +9763,9 @@ msgstr "" msgid "CorpusManagement|Corpus name" msgstr "" +msgid "CorpusManagement|Currently, there are no uploaded or generated corpuses." +msgstr "" + msgid "CorpusManagement|Fuzz testing corpus management" msgstr ""