Drop updateQuery from DAST profiles queries

This removes deprecated updateQuery usages from DAST profiles queries.
It is being replaced by ApolloClient's concatPagination merge strategy.
Additionally, the optimistic profile removal is now done with the
.evicts method to prevent the merge strategy from being hit again, which
would result in duplicated items being displayed.
parent bdd5faad
......@@ -138,7 +138,6 @@ export default {
$apollo.queries[profileType]
.fetchMore({
variables: { after: pageInfo.endCursor },
updateQuery: cacheUtils.appendToPreviousResult(profileType),
})
.catch((error) => {
this.handleError({
......@@ -157,12 +156,8 @@ export default {
graphQL: { deletion },
},
},
$apollo: {
queries: {
[profileType]: { options: queryOptions },
},
},
} = this;
const profile = this.profileTypes[profileType].profiles.find(({ id }) => id === profileId);
this.resetErrors(profileType);
......@@ -179,13 +174,8 @@ export default {
if (errors.length === 0) {
cacheUtils.removeProfile({
profileId,
profileType,
profile,
store,
queryBody: {
query: queryOptions.query,
variables: queryOptions.variables,
},
});
} else {
handleError({
......
import { gql } from '@apollo/client/core';
import { produce } from 'immer';
import dastSiteProfilesQuery from 'ee/security_configuration/dast_profiles/graphql/dast_site_profiles.query.graphql';
/**
* Appends paginated results to existing ones
* - to be used with $apollo.queries.x.fetchMore
* Evicts a profile from the cache
*
* @param {*} profileType
* @returns {function(*, {fetchMoreResult: *}): *}
*/
export const appendToPreviousResult = (profileType) => (previousResult, { fetchMoreResult }) => {
const newResult = { ...fetchMoreResult };
const previousNodes = previousResult.project[profileType].nodes;
const newNodes = newResult.project[profileType].nodes;
newResult.project[profileType].nodes = [...previousNodes, ...newNodes];
return newResult;
};
/**
* Removes profile with given id from the cache and writes the result to it
*
* @param profileId
* @param profileType
* @param profile
* @param store
* @param queryBody
*/
export const removeProfile = ({ profileId, profileType, store, queryBody }) => {
const sourceData = store.readQuery(queryBody);
const data = produce(sourceData, (draftState) => {
draftState.project[profileType].nodes = draftState.project[profileType].nodes.filter((node) => {
return node.id !== profileId;
});
});
store.writeQuery({ ...queryBody, data });
};
export const removeProfile = ({ profile, store }) => store.evict({ id: store.identify(profile) });
/**
* Returns an object representing a optimistic response for site-profile deletion
......
......@@ -4,8 +4,7 @@ query DastSiteProfiles($fullPath: ID!, $after: String, $before: String, $first:
project(fullPath: $fullPath) {
__typename
id
siteProfiles: dastSiteProfiles(after: $after, before: $before, first: $first, last: $last)
@connection(key: "dastSiteProfiles") {
siteProfiles: dastSiteProfiles(after: $after, before: $before, first: $first, last: $last) {
__typename
pageInfo {
__typename
......
import { concatPagination } from '@apollo/client/utilities';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
Vue.use(VueApollo);
const profilesCachePolicy = () => ({
keyArgs: ['fullPath'],
});
const profilesPagination = () => ({
fields: {
nodes: concatPagination(),
},
});
export default new VueApollo({
defaultClient: createDefaultClient(),
defaultClient: createDefaultClient(
{},
{
cacheConfig: {
typePolicies: {
Project: {
fields: {
dastSiteProfiles: profilesCachePolicy(),
dastScannerProfiles: profilesCachePolicy(),
},
},
DastSiteProfileConnection: profilesPagination(),
DastScannerProfileConnection: profilesPagination(),
},
},
},
),
});
import { gql } from '@apollo/client/core';
import {
appendToPreviousResult,
removeProfile,
dastProfilesDeleteResponse,
updateSiteProfilesStatuses,
......@@ -8,58 +7,22 @@ import {
import { siteProfiles } from '../mocks/mock_data';
describe('EE - DastProfiles GraphQL CacheUtils', () => {
describe('appendToPreviousResult', () => {
it.each(['siteProfiles', 'scannerProfiles'])(
'appends new results to previous',
(profileType) => {
const previousResult = { project: { [profileType]: { nodes: ['foo'] } } };
const fetchMoreResult = { project: { [profileType]: { nodes: ['bar'] } } };
const expected = { project: { [profileType]: { nodes: ['foo', 'bar'] } } };
const result = appendToPreviousResult(profileType)(previousResult, { fetchMoreResult });
expect(result).toEqual(expected);
},
);
});
describe('removeProfile', () => {
it.each(['foo', 'bar'])(
'removes the profile with the given id from the cache',
(profileType) => {
const mockQueryBody = { query: 'foo', variables: { foo: 'bar' } };
const mockProfiles = [{ id: 0 }, { id: 1 }];
const mockData = {
project: {
[profileType]: {
nodes: [mockProfiles[0], mockProfiles[1]],
},
},
};
const mockStore = {
readQuery: () => mockData,
writeQuery: jest.fn(),
};
it('removes the profile from the cache', () => {
const [profileToBeRemoved] = siteProfiles;
const mockStore = {
identify: jest.fn().mockReturnValue(profileToBeRemoved.id),
evict: jest.fn(),
};
removeProfile({
store: mockStore,
queryBody: mockQueryBody,
profileId: mockProfiles[0].id,
profileType,
});
removeProfile({
profile: profileToBeRemoved,
store: mockStore,
});
expect(mockStore.writeQuery).toHaveBeenCalledWith({
...mockQueryBody,
data: {
project: {
[profileType]: {
nodes: [mockProfiles[1]],
},
},
},
});
},
);
expect(mockStore.identify).toHaveBeenCalledWith(profileToBeRemoved);
expect(mockStore.evict).toHaveBeenCalledWith({ id: profileToBeRemoved.id });
});
});
describe('dastProfilesDeleteResponse', () => {
......
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