Commit 6a8f2b60 authored by Peter Hegman's avatar Peter Hegman

Merge branch '345088-corpus-table-fetch' into 'master'

Render Corpus table with real data

See merge request gitlab-org/gitlab!74480
parents 84a3fff2 41bd7fc3
...@@ -30,11 +30,13 @@ export default { ...@@ -30,11 +30,13 @@ export default {
}, },
computed: { computed: {
downloadPath() { downloadPath() {
/* return this.corpus.package.packageFiles.nodes[0].downloadPath;
* TODO: Replace with relative path when we complete backend },
* https://gitlab.com/gitlab-org/gitlab/-/issues/321618 name() {
*/ return this.corpus.package.name;
return `https://www.gitlab.com/${this.corpus.downloadPath}`; },
directiveName() {
return `confirmation-modal-${this.name}`;
}, },
}, },
}; };
...@@ -43,7 +45,7 @@ export default { ...@@ -43,7 +45,7 @@ export default {
<span> <span>
<gl-button class="gl-mr-2" icon="download" :href="downloadPath" /> <gl-button class="gl-mr-2" icon="download" :href="downloadPath" />
<gl-button <gl-button
v-gl-modal-directive="`confirmation-modal-${corpus.name}`" v-gl-modal-directive="directiveName"
icon="remove" icon="remove"
category="secondary" category="secondary"
variant="danger" variant="danger"
...@@ -54,7 +56,7 @@ export default { ...@@ -54,7 +56,7 @@ export default {
body-class="gl-display-none" body-class="gl-display-none"
size="sm" size="sm"
:title="$options.i18n.deleteCorpusMessage" :title="$options.i18n.deleteCorpusMessage"
:modal-id="`confirmation-modal-${corpus.name}`" :modal-id="directiveName"
:action-primary="$options.modal.actionPrimary" :action-primary="$options.modal.actionPrimary"
:action-cancel="$options.modal.actionCancel" :action-cancel="$options.modal.actionCancel"
@primary="$emit('delete', corpus)" @primary="$emit('delete', corpus)"
......
...@@ -18,17 +18,19 @@ export default { ...@@ -18,17 +18,19 @@ export default {
}, },
computed: { computed: {
fileSize() { fileSize() {
return decimalBytes(this.corpus.size); return decimalBytes(this.corpus.package.packageFiles.nodes[0].size);
}, },
jobUrl() { jobUrl() {
/* return this.corpus.package.pipelines.nodes[0]?.path;
* TODO: Replace with relative path when we complete backend
* https://gitlab.com/gitlab-org/gitlab/-/issues/321618
*/
return `https://www.gitlab.com/${this.corpus.latestJobPath}`;
}, },
jobPath() { ref() {
return this.corpus.latestJobPath; return this.corpus.package.pipelines.nodes[0]?.ref;
},
latestJob() {
return `${this.jobURL} (${this.ref})`;
},
name() {
return this.corpus.package.name;
}, },
}, },
}; };
...@@ -36,13 +38,13 @@ export default { ...@@ -36,13 +38,13 @@ export default {
<template> <template>
<div> <div>
<div class="gl-text-gray-900" data-testid="corpus-name"> <div class="gl-text-gray-900" data-testid="corpus-name">
{{ corpus.name }} {{ name }}
<span class="gl-text-gray-500" data-testid="file-size">({{ fileSize }})</span> <span class="gl-text-gray-500" data-testid="file-size">({{ fileSize }})</span>
</div> </div>
<div data-testid="latest-job"> <div data-testid="latest-job">
{{ this.$options.i18n.latestJob }} {{ this.$options.i18n.latestJob }}
<gl-link v-if="jobPath" class="gl-display-inline-block" :href="jobUrl" target="_blank"> <gl-link v-if="jobUrl" class="gl-display-inline-block" :href="jobUrl" target="_blank">
{{ jobPath }} {{ latestJob }}
</gl-link> </gl-link>
<template v-else>-</template> <template v-else>-</template>
</div> </div>
......
...@@ -12,7 +12,8 @@ export default { ...@@ -12,7 +12,8 @@ export default {
props: { props: {
target: { target: {
type: String, type: String,
required: true, required: false,
default: '',
}, },
}, },
i18n: { i18n: {
......
...@@ -37,15 +37,12 @@ export default { ...@@ -37,15 +37,12 @@ export default {
learnMore: __('Learn More'), learnMore: __('Learn More'),
}, },
computed: { computed: {
mockedData() { corpuses() {
return this.states?.mockedPackages.data || []; return this.states?.project.corpuses.nodes || [];
}, },
isLoading() { isLoading() {
return this.$apollo.loading; return this.$apollo.loading;
}, },
totalSize() {
return this.states?.mockedPackages.totalSize;
},
}, },
}; };
</script> </script>
...@@ -64,8 +61,8 @@ export default { ...@@ -64,8 +61,8 @@ export default {
<gl-loading-icon v-if="isLoading" size="lg" /> <gl-loading-icon v-if="isLoading" size="lg" />
<template v-else> <template v-else>
<corpus-upload :total-size="totalSize" /> <corpus-upload />
<corpus-table :corpuses="mockedData" /> <corpus-table :corpuses="corpuses" />
</template> </template>
</div> </div>
</template> </template>
...@@ -59,6 +59,15 @@ export default { ...@@ -59,6 +59,15 @@ export default {
variables: { name, projectPath: this.projectFullPath }, variables: { name, projectPath: this.projectFullPath },
}); });
}, },
target(corpus) {
return corpus.package.pipelines.nodes[0]?.ref;
},
lastUpdated(corpus) {
return corpus.package.updatedAt;
},
lastUsed(corpus) {
return corpus.package.pipelines.nodes[0]?.updatedAt;
},
}, },
dateFormat: ISO_SHORT_FORMAT, dateFormat: ISO_SHORT_FORMAT,
}; };
...@@ -70,15 +79,15 @@ export default { ...@@ -70,15 +79,15 @@ export default {
</template> </template>
<template #cell(target)="{ item }"> <template #cell(target)="{ item }">
<target :target="item.target" /> <target :target="target(item)" />
</template> </template>
<template #cell(lastUpdated)="{ item }"> <template #cell(lastUpdated)="{ item }">
<user-date :date="item.lastUpdated" :date-format="$options.dateFormat" /> <user-date :date="lastUpdated(item)" :date-format="$options.dateFormat" />
</template> </template>
<template #cell(lastUsed)="{ item }"> <template #cell(lastUsed)="{ item }">
<user-date :date="item.lastUsed" :date-format="$options.dateFormat" /> <user-date :date="lastUsed(item)" :date-format="$options.dateFormat" />
</template> </template>
<template #cell(actions)="{ item }"> <template #cell(actions)="{ item }">
......
...@@ -28,9 +28,7 @@ export default { ...@@ -28,9 +28,7 @@ export default {
states: { states: {
query: getCorpusesQuery, query: getCorpusesQuery,
variables() { variables() {
return { return this.queryVariables;
projectPath: this.projectFullPath,
};
}, },
update(data) { update(data) {
return data; return data;
...@@ -46,10 +44,16 @@ export default { ...@@ -46,10 +44,16 @@ export default {
props: { props: {
totalSize: { totalSize: {
type: Number, type: Number,
required: true, required: false,
default: null,
}, },
}, },
computed: { computed: {
queryVariables() {
return {
projectPath: this.projectFullPath,
};
},
formattedFileSize() { formattedFileSize() {
return decimalBytes(this.totalSize); return decimalBytes(this.totalSize);
}, },
...@@ -74,6 +78,12 @@ export default { ...@@ -74,6 +78,12 @@ export default {
addCorpus() { addCorpus() {
this.$apollo.mutate({ this.$apollo.mutate({
mutation: addCorpusMutation, mutation: addCorpusMutation,
refetchQueries: [
{
query: getCorpusesQuery,
variables: this.queryVariables,
},
],
variables: { variables: {
name: this.$options.i18n.newCorpus, name: this.$options.i18n.newCorpus,
projectPath: this.projectFullPath, projectPath: this.projectFullPath,
...@@ -100,7 +110,7 @@ export default { ...@@ -100,7 +110,7 @@ export default {
<div <div
class="gl-h-11 gl-bg-gray-10 gl-display-flex gl-justify-content-space-between gl-align-items-center" class="gl-h-11 gl-bg-gray-10 gl-display-flex gl-justify-content-space-between gl-align-items-center"
> >
<div class="gl-ml-5"> <div v-if="totalSize" class="gl-ml-5">
<gl-sprintf :message="$options.i18n.totalSize"> <gl-sprintf :message="$options.i18n.totalSize">
<template #totalSize> <template #totalSize>
<span class="gl-font-weight-bold">{{ formattedFileSize }}</span> <span class="gl-font-weight-bold">{{ formattedFileSize }}</span>
...@@ -108,7 +118,11 @@ export default { ...@@ -108,7 +118,11 @@ export default {
</gl-sprintf> </gl-sprintf>
</div> </div>
<gl-button v-gl-modal-directive="$options.modal.modalId" class="gl-mr-5" variant="confirm"> <gl-button
v-gl-modal-directive="$options.modal.modalId"
class="gl-mr-5 gl-ml-auto"
variant="confirm"
>
{{ $options.i18n.newCorpus }} {{ $options.i18n.newCorpus }}
</gl-button> </gl-button>
......
query getCorpuses($projectPath: ID!) { query getCorpuses($projectPath: ID!) {
mockedPackages(projectPath: $projectPath) @client { project(fullPath: $projectPath) {
data id
totalSize corpuses {
nodes {
id
package {
id
name
updatedAt
packageFiles(last: 1) {
nodes {
id
size
downloadPath
}
}
pipelines(last: 1) {
nodes {
id
createdAt
ref
}
}
}
}
}
} }
uploadState(projectPath: $projectPath) @client { uploadState(projectPath: $projectPath) @client {
isUploading isUploading
......
import produce from 'immer'; import produce from 'immer';
import { corpuses } from 'ee_jest/security_configuration/corpus_management/mock_data';
import { publishPackage } from '~/api/packages_api'; import { publishPackage } from '~/api/packages_api';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { convertToGraphQLId } from '~/graphql_shared/utils'; import { convertToGraphQLId } from '~/graphql_shared/utils';
...@@ -11,15 +10,6 @@ import corpusCreate from '../mutations/corpus_create.mutation.graphql'; ...@@ -11,15 +10,6 @@ import corpusCreate from '../mutations/corpus_create.mutation.graphql';
export default { export default {
Query: { Query: {
/* eslint-disable no-unused-vars */
mockedPackages(_, { projectPath }) {
return {
// Mocked data goes here
totalSize: 20.45e8,
data: corpuses,
__typename: 'MockedPackages',
};
},
/* eslint-disable no-unused-vars */ /* eslint-disable no-unused-vars */
uploadState(_, { projectPath }) { uploadState(_, { projectPath }) {
return { return {
...@@ -32,7 +22,7 @@ export default { ...@@ -32,7 +22,7 @@ export default {
}, },
}, },
Mutation: { Mutation: {
addCorpus: (_, { name, projectPath, packageId }, { cache, client }) => { addCorpus: (_, { projectPath, packageId }, { cache, client }) => {
const sourceData = cache.readQuery({ const sourceData = cache.readQuery({
query: getCorpusesQuery, query: getCorpusesQuery,
variables: { projectPath }, variables: { projectPath },
...@@ -41,21 +31,6 @@ export default { ...@@ -41,21 +31,6 @@ export default {
const data = produce(sourceData, (draftState) => { const data = produce(sourceData, (draftState) => {
draftState.uploadState.isUploading = false; draftState.uploadState.isUploading = false;
draftState.uploadState.progress = 0; draftState.uploadState.progress = 0;
draftState.mockedPackages.data = [
...draftState.mockedPackages.data,
{
name,
lastUpdated: new Date().toString(),
lastUsed: new Date().toString(),
latestJobPath: '',
target: '',
downloadPath: 'farias-gl/go-fuzzing-example/-/jobs/959593462/artifacts/download',
size: 4e8,
__typename: 'CorpusData',
},
];
draftState.mockedPackages.totalSize += 4e8;
}); });
cache.writeQuery({ query: getCorpusesQuery, data, variables: { projectPath } }); cache.writeQuery({ query: getCorpusesQuery, data, variables: { projectPath } });
...@@ -70,25 +45,8 @@ export default { ...@@ -70,25 +45,8 @@ export default {
}, },
}); });
}, },
deleteCorpus: (_, { name, projectPath }, { cache }) => { deleteCorpus: () => {
const sourceData = cache.readQuery({ // NO-OP
query: getCorpusesQuery,
variables: { projectPath },
});
const data = produce(sourceData, (draftState) => {
const mockedCorpuses = draftState.mockedPackages;
// Filter out deleted corpus
mockedCorpuses.data = mockedCorpuses.data.filter((corpus) => {
return corpus.name !== name;
});
// Re-compute total file size
mockedCorpuses.totalSize = mockedCorpuses.data.reduce((totalSize, corpus) => {
return totalSize + corpus.size;
}, 0);
});
cache.writeQuery({ query: getCorpusesQuery, data, variables: { projectPath } });
}, },
uploadCorpus: (_, { projectPath, name, files }, { cache, client }) => { uploadCorpus: (_, { projectPath, name, files }, { cache, client }) => {
const onUploadProgress = (e) => { const onUploadProgress = (e) => {
......
...@@ -15,7 +15,7 @@ exports[`Corpus Upload component renders header 1`] = ` ...@@ -15,7 +15,7 @@ exports[`Corpus Upload component renders header 1`] = `
<gl-button-stub <gl-button-stub
buttontextclasses="" buttontextclasses=""
category="primary" category="primary"
class="gl-mr-5" class="gl-mr-5 gl-ml-auto"
icon="" icon=""
role="button" role="button"
size="medium" size="medium"
......
...@@ -6,7 +6,7 @@ exports[`Name component renders name with correct file size 1`] = ` ...@@ -6,7 +6,7 @@ exports[`Name component renders name with correct file size 1`] = `
data-testid="corpus-name" data-testid="corpus-name"
> >
Test corpus 1 Corpus-sample-1-13830-23932
<span <span
class="gl-text-gray-500" class="gl-text-gray-500"
...@@ -23,7 +23,7 @@ exports[`Name component renders the latest job 1`] = ` ...@@ -23,7 +23,7 @@ exports[`Name component renders the latest job 1`] = `
data-testid="corpus-name" data-testid="corpus-name"
> >
Test corpus 1 Corpus-sample-1-13830-23932
<span <span
class="gl-text-gray-500" class="gl-text-gray-500"
...@@ -40,7 +40,7 @@ exports[`Name component without job path renders a - string instead of a link 1` ...@@ -40,7 +40,7 @@ exports[`Name component without job path renders a - string instead of a link 1`
data-testid="corpus-name" data-testid="corpus-name"
> >
Corpus-sample-2-1431-4425 Corpus-sample-3-1431-4425
<span <span
class="gl-text-gray-500" class="gl-text-gray-500"
......
...@@ -3,6 +3,7 @@ import { shallowMount } from '@vue/test-utils'; ...@@ -3,6 +3,7 @@ import { shallowMount } from '@vue/test-utils';
import CorpusManagement from 'ee/security_configuration/corpus_management/components/corpus_management.vue'; 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 CorpusTable from 'ee/security_configuration/corpus_management/components/corpus_table.vue';
import CorpusUpload from 'ee/security_configuration/corpus_management/components/corpus_upload.vue'; import CorpusUpload from 'ee/security_configuration/corpus_management/components/corpus_upload.vue';
import { corpuses } from './mock_data';
const TEST_PROJECT_FULL_PATH = '/namespace/project'; const TEST_PROJECT_FULL_PATH = '/namespace/project';
const TEST_CORPUS_HELP_PATH = '/docs/corpus-management'; const TEST_CORPUS_HELP_PATH = '/docs/corpus-management';
...@@ -37,7 +38,7 @@ describe('EE - CorpusManagement', () => { ...@@ -37,7 +38,7 @@ describe('EE - CorpusManagement', () => {
describe('when loaded', () => { describe('when loaded', () => {
beforeEach(() => { beforeEach(() => {
const data = () => { const data = () => {
return { states: { mockedPackages: { totalSize: 12 } } }; return { states: { project: { corpuses } } };
}; };
createComponent({ data }); createComponent({ data });
......
const pipelines = {
nodes: [
{
ref: 'farias-gl/go-fuzzing-example',
path: 'gitlab-examples/security/security-reports/-/jobs/1107103952',
updatedAt: new Date(2020, 4, 3).toString(),
},
],
};
const packageFiles = {
nodes: [
{
downloadPath: '/download-path',
size: 4e8,
},
],
};
export const corpuses = [ export const corpuses = [
{ {
name: 'Test corpus 1', package: {
lastUpdated: new Date(2021, 1, 12).toString(), name: 'Corpus-sample-1-13830-23932',
lastUsed: new Date(2020, 4, 3).toString(), updatedAt: new Date(2021, 2, 12).toString(),
latestJobPath: 'gitlab-examples/security/security-reports/-/jobs/1107103952', pipelines,
target: '', packageFiles,
downloadPath: 'farias-gl/go-fuzzing-example/-/jobs/959593462/artifacts/download', },
size: 4e8,
}, },
{ {
name: 'Corpus-sample-1-5830-2393', package: {
lastUpdated: new Date(2021, 2, 5).toString(), name: 'Corpus-sample-2-5830-2393',
lastUsed: new Date(2021, 6, 3).toString(), updatedAt: new Date(2021, 3, 12).toString(),
latestJobPath: 'gitlab-examples/security/security-reports/-/jobs/1107103952', pipelines,
downloadPath: 'farias-gl/go-fuzzing-example/-/jobs/959593462/artifacts/download', packageFiles,
target: '294444-apollo-management-table', },
size: 2.34e8,
}, },
{ {
name: 'Corpus-sample-2-1431-4425', package: {
lastUpdated: new Date(2021, 1, 17).toString(), name: 'Corpus-sample-3-1431-4425',
lastUsed: new Date(2020, 4, 23).toString(), updatedAt: new Date(2021, 4, 12).toString(),
latestJobPath: '', pipelines: {
target: '120498-another-branch', nodes: [
size: 3.21e8, {
...pipelines.nodes[0],
path: '',
},
],
},
packageFiles: {
nodes: [
{
downloadPath: '/download-path',
size: 3.21e8,
},
],
},
},
}, },
{ {
name: 'Corpus-sample-5-5830-1393', package: {
lastUpdated: new Date(2021, 4, 9).toString(), name: 'Corpus-sample-4-5830-1393',
lastUsed: new Date(2020, 8, 4).toString(), updatedAt: new Date(2021, 5, 12).toString(),
latestJobPath: 'gitlab-examples/security/security-reports/-/jobs/1107103952', pipelines,
downloadPath: 'farias-gl/go-fuzzing-example/-/jobs/959593462/artifacts/download', packageFiles,
target: '120341-feature-branch', },
size: 1.34e8,
}, },
{ {
name: 'Corpus-sample-8-1830-1393', package: {
lastUpdated: new Date(2020, 4, 9).toString(), name: 'Corpus-sample-5-13830-23932',
lastUsed: new Date(2019, 8, 4).toString(), updatedAt: new Date(2021, 6, 12).toString(),
latestJobPath: 'gitlab-examples/security/security-reports/-/jobs/1107103952', pipelines,
downloadPath: 'farias-gl/go-fuzzing-example/-/jobs/959593462/artifacts/download', packageFiles,
target: '', },
size: 6.34e8,
}, },
{ {
name: 'Corpus-sample-9-2450-2393', package: {
lastUpdated: new Date(2019, 4, 6).toString(), name: 'Corpus-sample-6-2450-2393',
lastUsed: new Date(2020, 3, 12).toString(), updatedAt: new Date(2021, 7, 12).toString(),
latestJobPath: 'gitlab-examples/security/security-reports/-/jobs/1107103952', pipelines,
downloadPath: 'farias-gl/go-fuzzing-example/-/jobs/959593462/artifacts/download', packageFiles,
target: '403847-feature-branch', },
size: 3.22e8,
}, },
]; ];
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment