Skip to content
代码片段 群组 项目
未验证 提交 8e927220 编辑于 作者: Alexander Turinske's avatar Alexander Turinske 提交者: GitLab
浏览文件

Merge branch '505619-policies-add-infinite-scroll-block-modification' into 'master'

No related branches found
No related tags found
无相关合并请求
...@@ -3,7 +3,7 @@ import { GlSprintf } from '@gitlab/ui'; ...@@ -3,7 +3,7 @@ import { GlSprintf } from '@gitlab/ui';
import { s__, sprintf } from '~/locale'; import { s__, sprintf } from '~/locale';
import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils'; import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
import { TYPENAME_GROUP } from '~/graphql_shared/constants'; import { TYPENAME_GROUP } from '~/graphql_shared/constants';
import getGroupsByIds from 'ee/security_orchestration/graphql/queries/get_groups_by_ids.qyery.graphql'; import getGroupsByIds from 'ee/security_orchestration/graphql/queries/get_groups_by_ids.query.graphql';
export default { export default {
name: 'BlockGroupBranchModificationSetting', name: 'BlockGroupBranchModificationSetting',
......
...@@ -7,13 +7,14 @@ import { ...@@ -7,13 +7,14 @@ import {
GlSprintf, GlSprintf,
GlTooltipDirective, GlTooltipDirective,
} from '@gitlab/ui'; } from '@gitlab/ui';
import produce from 'immer';
import { createAlert } from '~/alert'; import { createAlert } from '~/alert';
import { helpPagePath } from '~/helpers/help_page_helper'; import { helpPagePath } from '~/helpers/help_page_helper';
import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants'; import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
import { getSelectedOptionsText } from '~/lib/utils/listbox_helpers'; import { getSelectedOptionsText } from '~/lib/utils/listbox_helpers';
import { TYPENAME_GROUP } from '~/graphql_shared/constants'; import { TYPENAME_GROUP } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils'; import { convertToGraphQLId } from '~/graphql_shared/utils';
import getGroupsByIds from 'ee/security_orchestration/graphql/queries/get_groups_by_ids.qyery.graphql'; import getGroupsByIds from 'ee/security_orchestration/graphql/queries/get_groups_by_ids.query.graphql';
import { searchInItemsProperties } from '~/lib/utils/search_utils'; import { searchInItemsProperties } from '~/lib/utils/search_utils';
import { __, s__ } from '~/locale'; import { __, s__ } from '~/locale';
import { import {
...@@ -41,6 +42,7 @@ export default { ...@@ -41,6 +42,7 @@ export default {
}, },
update(data) { update(data) {
const groups = data.groups?.nodes?.map(createGroupObject) || []; const groups = data.groups?.nodes?.map(createGroupObject) || [];
this.pageInfo = data.groups?.pageInfo || {};
return this.joinUniqueGroups(groups); return this.joinUniqueGroups(groups);
}, },
async result() { async result() {
...@@ -82,6 +84,7 @@ export default { ...@@ -82,6 +84,7 @@ export default {
selectedExceptionType: this.exceptions.length ? EXCEPT_GROUPS : WITHOUT_EXCEPTIONS, selectedExceptionType: this.exceptions.length ? EXCEPT_GROUPS : WITHOUT_EXCEPTIONS,
searchValue: '', searchValue: '',
searching: false, searching: false,
pageInfo: {},
}; };
}, },
computed: { computed: {
...@@ -124,6 +127,9 @@ export default { ...@@ -124,6 +127,9 @@ export default {
maxOptionsShown: 2, maxOptionsShown: 2,
}); });
}, },
hasNextPage() {
return this.pageInfo.hasNextPage;
},
}, },
watch: { watch: {
enabled(value) { enabled(value) {
...@@ -181,6 +187,27 @@ export default { ...@@ -181,6 +187,27 @@ export default {
emitChangeEvent(value) { emitChangeEvent(value) {
this.$emit('change', value); this.$emit('change', value);
}, },
async loadMoreGroups() {
if (!this.hasNextPage) return [];
try {
return await this.$apollo.queries.groups.fetchMore({
variables: {
search: this.searchValue,
after: this.pageInfo.endCursor,
},
updateQuery(previousResult, { fetchMoreResult }) {
return produce(fetchMoreResult, (draftData) => {
draftData.groups.nodes = [
...previousResult.groups.nodes,
...fetchMoreResult.groups.nodes,
];
});
},
});
} catch {
return [];
}
},
}, },
GROUP_PROTECTED_BRANCHES_DOCS: helpPagePath('user/project/repository/branches/protected', { GROUP_PROTECTED_BRANCHES_DOCS: helpPagePath('user/project/repository/branches/protected', {
...@@ -216,9 +243,11 @@ export default { ...@@ -216,9 +243,11 @@ export default {
multiple multiple
searchable searchable
:items="filteredGroups" :items="filteredGroups"
:infinite-scroll="hasNextPage"
:loading="loading" :loading="loading"
:selected="exceptionIds" :selected="exceptionIds"
:toggle-text="toggleText" :toggle-text="toggleText"
@bottom-reached="loadMoreGroups"
@search="handleSearch" @search="handleSearch"
@select="updateGroupExceptionValue" @select="updateGroupExceptionValue"
> >
......
#import "~/graphql_shared/fragments/page_info.fragment.graphql" #import "~/graphql_shared/fragments/page_info.fragment.graphql"
query getGroupsByIds($ids: [ID!], $search: String, $topLevelOnly: Boolean) { query getGroupsByIds($ids: [ID!], $search: String, $topLevelOnly: Boolean, $after: String = "") {
groups(ids: $ids, search: $search, topLevelOnly: $topLevelOnly) { groups(ids: $ids, search: $search, topLevelOnly: $topLevelOnly, after: $after) {
nodes { nodes {
id id
name name
......
...@@ -8,7 +8,7 @@ import { createMockGroups } from 'ee_jest/security_orchestration/mocks/mock_data ...@@ -8,7 +8,7 @@ import { createMockGroups } from 'ee_jest/security_orchestration/mocks/mock_data
import { convertToGraphQLId } from '~/graphql_shared/utils'; import { convertToGraphQLId } from '~/graphql_shared/utils';
import { TYPENAME_GROUP } from '~/graphql_shared/constants'; import { TYPENAME_GROUP } from '~/graphql_shared/constants';
import createMockApollo from 'helpers/mock_apollo_helper'; import createMockApollo from 'helpers/mock_apollo_helper';
import getGroupsByIds from 'ee/security_orchestration/graphql/queries/get_groups_by_ids.qyery.graphql'; import getGroupsByIds from 'ee/security_orchestration/graphql/queries/get_groups_by_ids.query.graphql';
describe('BlockGroupBranchModificationSetting', () => { describe('BlockGroupBranchModificationSetting', () => {
let wrapper; let wrapper;
...@@ -52,6 +52,7 @@ describe('BlockGroupBranchModificationSetting', () => { ...@@ -52,6 +52,7 @@ describe('BlockGroupBranchModificationSetting', () => {
expect(requestHandler).toHaveBeenCalledWith({ expect(requestHandler).toHaveBeenCalledWith({
ids: exceptions.map(({ id }) => convertToGraphQLId(TYPENAME_GROUP, id)), ids: exceptions.map(({ id }) => convertToGraphQLId(TYPENAME_GROUP, id)),
after: '',
}); });
expect(findExceptions()).toHaveLength(2); expect(findExceptions()).toHaveLength(2);
expect(findExceptions().at(0).text()).toBe(groups[0].fullName); expect(findExceptions().at(0).text()).toBe(groups[0].fullName);
......
...@@ -10,7 +10,7 @@ import { ...@@ -10,7 +10,7 @@ import {
} from 'ee/security_orchestration/components/policy_editor/scan_result/lib/settings'; } from 'ee/security_orchestration/components/policy_editor/scan_result/lib/settings';
import BlockGroupBranchModification from 'ee/security_orchestration/components/policy_editor/scan_result/settings/block_group_branch_modification.vue'; import BlockGroupBranchModification from 'ee/security_orchestration/components/policy_editor/scan_result/settings/block_group_branch_modification.vue';
import { createMockGroups } from 'ee_jest/security_orchestration/mocks/mock_data'; import { createMockGroups } from 'ee_jest/security_orchestration/mocks/mock_data';
import getGroupsByIds from 'ee/security_orchestration/graphql/queries/get_groups_by_ids.qyery.graphql'; import getGroupsByIds from 'ee/security_orchestration/graphql/queries/get_groups_by_ids.query.graphql';
import { convertToGraphQLId } from '~/graphql_shared/utils'; import { convertToGraphQLId } from '~/graphql_shared/utils';
import { TYPENAME_GROUP } from '~/graphql_shared/constants'; import { TYPENAME_GROUP } from '~/graphql_shared/constants';
import createMockApollo from 'helpers/mock_apollo_helper'; import createMockApollo from 'helpers/mock_apollo_helper';
...@@ -21,12 +21,20 @@ describe('BlockGroupBranchModification', () => { ...@@ -21,12 +21,20 @@ describe('BlockGroupBranchModification', () => {
let wrapper; let wrapper;
let requestHandler; let requestHandler;
const defaultHandler = (nodes = createMockGroups()) => const defaultPageInfo = {
__typename: 'PageInfo',
hasNextPage: false,
hasPreviousPage: false,
startCursor: null,
endCursor: null,
};
const defaultHandler = (nodes = createMockGroups(), pageInfo = defaultPageInfo) =>
jest.fn().mockResolvedValue({ jest.fn().mockResolvedValue({
data: { data: {
groups: { groups: {
nodes, nodes,
pageInfo: {}, pageInfo,
}, },
}, },
}); });
...@@ -67,7 +75,7 @@ describe('BlockGroupBranchModification', () => { ...@@ -67,7 +75,7 @@ describe('BlockGroupBranchModification', () => {
}); });
it('renders when enabled', () => { it('renders when enabled', () => {
createComponent({ enabled: true }); createComponent({ propsData: { enabled: true } });
expect(findLink().attributes('href')).toBe( expect(findLink().attributes('href')).toBe(
'/help/user/project/repository/branches/protected#for-all-projects-in-a-group', '/help/user/project/repository/branches/protected#for-all-projects-in-a-group',
); );
...@@ -93,7 +101,7 @@ describe('BlockGroupBranchModification', () => { ...@@ -93,7 +101,7 @@ describe('BlockGroupBranchModification', () => {
}); });
it('retrieves top-level groups', () => { it('retrieves top-level groups', () => {
expect(requestHandler).toHaveBeenCalledWith({ topLevelOnly: true, search: '' }); expect(requestHandler).toHaveBeenCalledWith({ topLevelOnly: true, search: '', after: '' });
}); });
it('renders the except selection dropdown', () => { it('renders the except selection dropdown', () => {
...@@ -160,7 +168,7 @@ describe('BlockGroupBranchModification', () => { ...@@ -160,7 +168,7 @@ describe('BlockGroupBranchModification', () => {
it('searches for groups', async () => { it('searches for groups', async () => {
createComponent({ propsData: { enabled: true, exceptions: [{ id: 1 }, { id: 2 }] } }); createComponent({ propsData: { enabled: true, exceptions: [{ id: 1 }, { id: 2 }] } });
await findExceptionsDropdown().vm.$emit('search', 'git'); await findExceptionsDropdown().vm.$emit('search', 'git');
expect(requestHandler).toHaveBeenCalledWith({ search: 'git', topLevelOnly: true }); expect(requestHandler).toHaveBeenCalledWith({ search: 'git', topLevelOnly: true, after: '' });
}); });
}); });
...@@ -187,11 +195,42 @@ describe('BlockGroupBranchModification', () => { ...@@ -187,11 +195,42 @@ describe('BlockGroupBranchModification', () => {
await waitForPromises(); await waitForPromises();
expect(requestHandler).toHaveBeenCalledTimes(2); expect(requestHandler).toHaveBeenCalledTimes(2);
expect(requestHandler).toHaveBeenNthCalledWith(1, { topLevelOnly: true, search: '' }); expect(requestHandler).toHaveBeenNthCalledWith(1, {
topLevelOnly: true,
search: '',
after: '',
});
expect(requestHandler).toHaveBeenNthCalledWith(2, { expect(requestHandler).toHaveBeenNthCalledWith(2, {
after: '',
topLevelOnly: true, topLevelOnly: true,
ids: [7, 8].map((id) => convertToGraphQLId(TYPENAME_GROUP, id)), ids: [7, 8].map((id) => convertToGraphQLId(TYPENAME_GROUP, id)),
}); });
}); });
}); });
describe('infinite scroll', () => {
it('does not make a query to fetch more groups when there is no next page', async () => {
createComponent({ propsData: { enabled: true, exceptions: [{ id: 1 }, { id: 2 }] } });
await waitForPromises();
findExceptionsDropdown().vm.$emit('bottom-reached');
expect(requestHandler).toHaveBeenCalledTimes(1);
});
it('makes a query to fetch more groups when there is a next page', async () => {
createComponent({
propsData: { enabled: true, exceptions: [{ id: 1 }, { id: 2 }] },
handler: defaultHandler(createMockGroups(), { ...defaultPageInfo, hasNextPage: true }),
});
await waitForPromises();
findExceptionsDropdown().vm.$emit('bottom-reached');
expect(requestHandler).toHaveBeenCalledTimes(2);
expect(requestHandler).toHaveBeenNthCalledWith(2, {
after: null,
topLevelOnly: true,
search: '',
});
});
});
}); });
0% 加载中 .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册