Commit 87303215 authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Merge branch 'pipeline-editor/refactor-branch-switcher' into 'master'

Refactor branch switcher in pipeline editor

See merge request gitlab-org/gitlab!62871
parents 34cf081c 7944c1ee
...@@ -7,6 +7,8 @@ import { ...@@ -7,6 +7,8 @@ import {
GlLoadingIcon, GlLoadingIcon,
GlSearchBoxByType, GlSearchBoxByType,
} from '@gitlab/ui'; } from '@gitlab/ui';
import { produce } from 'immer';
import { fetchPolicies } from '~/lib/graphql';
import { historyPushState } from '~/lib/utils/common_utils'; import { historyPushState } from '~/lib/utils/common_utils';
import { setUrlParams } from '~/lib/utils/url_utility'; import { setUrlParams } from '~/lib/utils/url_utility';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
...@@ -43,12 +45,12 @@ export default { ...@@ -43,12 +45,12 @@ export default {
}, },
data() { data() {
return { return {
branches: [], availableBranches: [],
page: { filteredBranches: [],
limit: this.paginationLimit, isSearchingBranches: false,
offset: 0, pageLimit: this.paginationLimit,
pageCounter: 0,
searchTerm: '', searchTerm: '',
},
}; };
}, },
apollo: { apollo: {
...@@ -56,28 +58,20 @@ export default { ...@@ -56,28 +58,20 @@ export default {
query: getAvailableBranches, query: getAvailableBranches,
variables() { variables() {
return { return {
limit: this.page.limit, limit: this.paginationLimit,
offset: this.page.offset, offset: 0,
projectFullPath: this.projectFullPath, projectFullPath: this.projectFullPath,
searchPattern: this.searchPattern, searchPattern: '*',
}; };
}, },
update(data) { update(data) {
return data.project?.repository?.branchNames || []; return data.project?.repository?.branchNames || [];
}, },
result({ data }) { result() {
const newBranches = data.project?.repository?.branchNames || []; this.pageCounter += 1;
// check that we're not re-concatenating existing fetch results
if (!this.branches.includes(newBranches[0])) {
this.branches = this.branches.concat(newBranches);
}
}, },
error() { error() {
this.$emit('showError', { this.showFetchError();
type: DEFAULT_FAILURE,
reasons: [this.$options.i18n.fetchError],
});
}, },
}, },
currentBranch: { currentBranch: {
...@@ -85,36 +79,57 @@ export default { ...@@ -85,36 +79,57 @@ export default {
}, },
}, },
computed: { computed: {
branches() {
return this.searchTerm.length > 0 ? this.filteredBranches : this.availableBranches;
},
isBranchesLoading() { isBranchesLoading() {
return this.$apollo.queries.availableBranches.loading; return this.$apollo.queries.availableBranches.loading || this.isSearchingBranches;
}, },
showBranchSwitcher() { showBranchSwitcher() {
return this.branches.length > 0 || this.page.searchTerm.length > 0; return this.branches.length > 0 || this.searchTerm.length > 0;
},
}, },
searchPattern() { methods: {
if (this.page.searchTerm === '') { availableBranchesQueryVars() {
return '*'; if (this.searchTerm.length > 0) {
return {
limit: this.totalBranches,
offset: 0,
projectFullPath: this.projectFullPath,
searchPattern: `*${this.searchTerm}*`,
};
} }
return `*${this.page.searchTerm}*`; return {
}, limit: this.paginationLimit,
offset: this.pageCounter * this.paginationLimit,
projectFullPath: this.projectFullPath,
searchPattern: '*',
};
}, },
methods: {
// if there is no searchPattern, paginate by {paginationLimit} branches // if there is no searchPattern, paginate by {paginationLimit} branches
fetchNextBranches() { fetchNextBranches() {
if ( if (
this.isBranchesLoading || this.isBranchesLoading ||
this.page.searchTerm.length > 0 || this.searchTerm.length > 0 ||
this.branches.length === this.totalBranches this.branches.length === this.totalBranches
) { ) {
return; return;
} }
this.page = { this.$apollo.queries.availableBranches
...this.page, .fetchMore({
limit: this.paginationLimit, variables: this.availableBranchesQueryVars(),
offset: this.page.offset + this.paginationLimit, updateQuery(previousResult, { fetchMoreResult }) {
}; const previousBranches = previousResult.project.repository.branchNames;
const newBranches = fetchMoreResult.project.repository.branchNames;
return produce(fetchMoreResult, (draftData) => {
draftData.project.repository.branchNames = previousBranches.concat(newBranches);
});
},
})
.catch(this.showFetchError);
}, },
async selectBranch(newBranch) { async selectBranch(newBranch) {
if (newBranch === this.currentBranch) { if (newBranch === this.currentBranch) {
...@@ -131,13 +146,32 @@ export default { ...@@ -131,13 +146,32 @@ export default {
this.$emit('refetchContent'); this.$emit('refetchContent');
}, },
setSearchTerm(newSearchTerm) { async setSearchTerm(newSearchTerm) {
this.branches = []; this.pageCounter = 0;
this.page = { this.searchTerm = newSearchTerm.trim();
limit: newSearchTerm.trim() === '' ? this.paginationLimit : this.totalBranches,
offset: 0, if (this.searchTerm === '') {
searchTerm: newSearchTerm.trim(), this.pageLimit = this.paginationLimit;
}; return;
}
this.isSearchingBranches = true;
const fetchResults = await this.$apollo
.query({
query: getAvailableBranches,
fetchPolicy: fetchPolicies.NETWORK_ONLY,
variables: this.availableBranchesQueryVars(),
})
.catch(this.showFetchError);
this.isSearchingBranches = false;
this.filteredBranches = fetchResults?.data?.project?.repository?.branchNames || [];
},
showFetchError() {
this.$emit('showError', {
type: DEFAULT_FAILURE,
reasons: [this.$options.i18n.fetchError],
});
}, },
}, },
}; };
......
...@@ -58,7 +58,7 @@ describe('Pipeline editor branch switcher', () => { ...@@ -58,7 +58,7 @@ describe('Pipeline editor branch switcher', () => {
}, },
data() { data() {
return { return {
branches: ['main'], availableBranches: ['main'],
currentBranch: mockDefaultBranch, currentBranch: mockDefaultBranch,
}; };
}, },
...@@ -99,6 +99,16 @@ describe('Pipeline editor branch switcher', () => { ...@@ -99,6 +99,16 @@ describe('Pipeline editor branch switcher', () => {
wrapper.destroy(); wrapper.destroy();
}); });
const testErrorHandling = () => {
expect(wrapper.emitted('showError')).toBeDefined();
expect(wrapper.emitted('showError')[0]).toEqual([
{
reasons: [wrapper.vm.$options.i18n.fetchError],
type: DEFAULT_FAILURE,
},
]);
};
describe('when querying for the first time', () => { describe('when querying for the first time', () => {
beforeEach(() => { beforeEach(() => {
createComponentWithApollo(); createComponentWithApollo();
...@@ -152,13 +162,7 @@ describe('Pipeline editor branch switcher', () => { ...@@ -152,13 +162,7 @@ describe('Pipeline editor branch switcher', () => {
}); });
it('shows an error message', () => { it('shows an error message', () => {
expect(wrapper.emitted('showError')).toBeDefined(); testErrorHandling();
expect(wrapper.emitted('showError')[0]).toEqual([
{
reasons: [wrapper.vm.$options.i18n.fetchError],
type: DEFAULT_FAILURE,
},
]);
}); });
}); });
...@@ -215,11 +219,26 @@ describe('Pipeline editor branch switcher', () => { ...@@ -215,11 +219,26 @@ describe('Pipeline editor branch switcher', () => {
mockAvailableBranchQuery.mockResolvedValue(mockProjectBranches); mockAvailableBranchQuery.mockResolvedValue(mockProjectBranches);
createComponentWithApollo(mount); createComponentWithApollo(mount);
await waitForPromises(); await waitForPromises();
});
mockAvailableBranchQuery.mockResolvedValue(mockSearchBranches); afterEach(() => {
mockAvailableBranchQuery.mockClear();
});
it('shows error message on fetch error', async () => {
mockAvailableBranchQuery.mockResolvedValue(new Error());
findSearchBox().vm.$emit('input', 'te');
await waitForPromises();
testErrorHandling();
}); });
describe('with a search term', () => { describe('with a search term', () => {
beforeEach(async () => {
mockAvailableBranchQuery.mockResolvedValue(mockSearchBranches);
});
it('calls query with correct variables', async () => { it('calls query with correct variables', async () => {
findSearchBox().vm.$emit('input', 'te'); findSearchBox().vm.$emit('input', 'te');
await waitForPromises(); await waitForPromises();
...@@ -253,6 +272,7 @@ describe('Pipeline editor branch switcher', () => { ...@@ -253,6 +272,7 @@ describe('Pipeline editor branch switcher', () => {
describe('without a search term', () => { describe('without a search term', () => {
beforeEach(async () => { beforeEach(async () => {
mockAvailableBranchQuery.mockResolvedValue(mockSearchBranches);
findSearchBox().vm.$emit('input', 'te'); findSearchBox().vm.$emit('input', 'te');
await waitForPromises(); await waitForPromises();
...@@ -326,6 +346,15 @@ describe('Pipeline editor branch switcher', () => { ...@@ -326,6 +346,15 @@ describe('Pipeline editor branch switcher', () => {
searchPattern: '*', searchPattern: '*',
}); });
}); });
it('shows error message on fetch error', async () => {
mockAvailableBranchQuery.mockResolvedValue(new Error());
findInfiniteScroll().vm.$emit('bottomReached');
await waitForPromises();
testErrorHandling();
});
}); });
describe('when search term exists', () => { describe('when search term exists', () => {
......
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