diff --git a/app/assets/javascripts/add_context_commits_modal/components/add_context_commits_modal_wrapper.vue b/app/assets/javascripts/add_context_commits_modal/components/add_context_commits_modal_wrapper.vue
index c66b595ffdc1c165eac2ac586fb23f90bf05d2f5..a5f8f369604dd281bff0a23384a15f239c99662c 100644
--- a/app/assets/javascripts/add_context_commits_modal/components/add_context_commits_modal_wrapper.vue
+++ b/app/assets/javascripts/add_context_commits_modal/components/add_context_commits_modal_wrapper.vue
@@ -1,10 +1,15 @@
+
+
+
+
diff --git a/app/assets/javascripts/add_context_commits_modal/store/actions.js b/app/assets/javascripts/add_context_commits_modal/store/actions.js
index de9c7488ace7c09904450a12ffb387889d0c73b2..f085b0d0e5eebdb8e2a7a5f1e76ed3bf111f26e7 100644
--- a/app/assets/javascripts/add_context_commits_modal/store/actions.js
+++ b/app/assets/javascripts/add_context_commits_modal/store/actions.js
@@ -1,8 +1,11 @@
import _ from 'lodash';
+import * as Sentry from '@sentry/browser';
import Api from '~/api';
import { createAlert } from '~/alert';
import axios from '~/lib/utils/axios_utils';
import { s__ } from '~/locale';
+import { joinPaths } from '~/lib/utils/url_utility';
+import { ACTIVE_AND_BLOCKED_USER_STATES } from '~/users_select/constants';
import * as types from './mutation_types';
export const setBaseConfig = ({ commit }, options) => {
@@ -11,14 +14,14 @@ export const setBaseConfig = ({ commit }, options) => {
export const setTabIndex = ({ commit }, tabIndex) => commit(types.SET_TABINDEX, tabIndex);
-export const searchCommits = ({ dispatch, commit, state }, searchText) => {
+export const searchCommits = ({ dispatch, commit, state }, search = {}) => {
commit(types.FETCH_COMMITS);
let params = {};
- if (searchText) {
+ if (search) {
params = {
params: {
- search: searchText,
+ ...search,
per_page: 40,
},
};
@@ -37,7 +40,7 @@ export const searchCommits = ({ dispatch, commit, state }, searchText) => {
}
return c;
});
- if (!searchText) {
+ if (!search) {
dispatch('setCommits', { commits: [...commits, ...state.contextCommits] });
} else {
dispatch('setCommits', { commits });
@@ -131,6 +134,23 @@ export const setSelectedCommits = ({ commit }, selected) => {
commit(types.SET_SELECTED_COMMITS, selectedCommits);
};
+export const fetchAuthors = ({ dispatch, state }, author = null) => {
+ const { projectId } = state;
+ return axios
+ .get(joinPaths(gon.relative_url_root || '', '/-/autocomplete/users.json'), {
+ params: {
+ project_id: projectId,
+ states: ACTIVE_AND_BLOCKED_USER_STATES,
+ search: author,
+ },
+ })
+ .then(({ data }) => data)
+ .catch((error) => {
+ Sentry.captureException(error);
+ dispatch('receiveAuthorsError');
+ });
+};
+
export const setSearchText = ({ commit }, searchText) => commit(types.SET_SEARCH_TEXT, searchText);
export const setToRemoveCommits = ({ commit }, data) => commit(types.SET_TO_REMOVE_COMMITS, data);
diff --git a/app/assets/javascripts/add_context_commits_modal/store/index.js b/app/assets/javascripts/add_context_commits_modal/store/index.js
index 0bf3441379b4edb8bf856c3f8fe33d1858b8d5f8..560834a26aefe13e6cf734b73fe0bbe5b3003c67 100644
--- a/app/assets/javascripts/add_context_commits_modal/store/index.js
+++ b/app/assets/javascripts/add_context_commits_modal/store/index.js
@@ -1,5 +1,6 @@
import Vue from 'vue';
import Vuex from 'vuex';
+import filters from '~/vue_shared/components/filtered_search_bar/store/modules/filters';
import * as actions from './actions';
import mutations from './mutations';
import state from './state';
@@ -12,4 +13,5 @@ export default () =>
state: state(),
actions,
mutations,
+ modules: { filters },
});
diff --git a/app/assets/javascripts/add_context_commits_modal/store/state.js b/app/assets/javascripts/add_context_commits_modal/store/state.js
index 37239adccbbf589f4415d03d01f779eb8397ba1e..fed3148bc9e4c4b240bc6005df541af9225176ff 100644
--- a/app/assets/javascripts/add_context_commits_modal/store/state.js
+++ b/app/assets/javascripts/add_context_commits_modal/store/state.js
@@ -1,4 +1,5 @@
export default () => ({
+ projectId: '',
contextCommitsPath: '',
tabIndex: 0,
isLoadingCommits: false,
diff --git a/app/assets/stylesheets/pages/commits.scss b/app/assets/stylesheets/pages/commits.scss
index 225c32c19892ce284f087dfc17a09c1759019846..83f51588f434d934a4738d6312f771c81637eafe 100644
--- a/app/assets/stylesheets/pages/commits.scss
+++ b/app/assets/stylesheets/pages/commits.scss
@@ -332,3 +332,18 @@
height: 100%;
}
}
+
+.add-review-item-modal {
+ .modal-content {
+ position: absolute;
+ top: 5%;
+ }
+
+ .title-hint-text {
+ color: $gl-text-color-secondary;
+ }
+
+ .gl-filtered-search-suggestion-list.dropdown-menu {
+ width: $gl-max-dropdown-max-height;
+ }
+}
diff --git a/app/finders/context_commits_finder.rb b/app/finders/context_commits_finder.rb
index 4a45817cc61096f03d5d21054ec6a4f7271cbad4..a186ca92c7b26caed1b727eb86340ea99556484a 100644
--- a/app/finders/context_commits_finder.rb
+++ b/app/finders/context_commits_finder.rb
@@ -21,20 +21,24 @@ def execute
attr_reader :project, :merge_request, :search, :author, :committed_before, :committed_after, :limit
def init_collection
- if search.present?
+ if search_params_present?
search_commits
else
project.repository.commits(merge_request.target_branch, { limit: limit })
end
end
+ def search_params_present?
+ [search, author, committed_before, committed_after].map(&:present?).any?
+ end
+
def filter_existing_commits(commits)
commits.select! { |commit| already_included_ids.exclude?(commit.id) }
commits
end
def search_commits
- key = search.strip
+ key = search&.strip
commits = []
if Commit.valid_hash?(key)
mr_existing_commits_ids = merge_request.commits.map(&:id)
diff --git a/app/models/repository.rb b/app/models/repository.rb
index 587b71315c2825e2071df0d1b527f8d252255b76..b4a0eaf0324e1ff47b50d8cd3336a25f6b2f72ce 100644
--- a/app/models/repository.rb
+++ b/app/models/repository.rb
@@ -199,7 +199,7 @@ def find_commits_by_message(query, ref = nil, path = nil, limit = 1000, offset =
def list_commits_by(query, ref, author: nil, before: nil, after: nil, limit: 1000)
return [] unless exists?
return [] unless has_visible_content?
- return [] unless query.present? && ref.present?
+ return [] unless ref.present?
commits = raw_repository.list_commits_by(
query, ref, author: author, before: before, after: after, limit: limit).map do |c|
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index a794c64a788fa2bc2a70f01fd76dca61a1981578..61cc4de0ef3f1d7c3a8a4e9164040c88d2d52b6b 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -10547,6 +10547,12 @@ msgstr ""
msgid "Committed by"
msgstr ""
+msgid "Committed-after"
+msgstr ""
+
+msgid "Committed-before"
+msgstr ""
+
msgid "CommonJS module"
msgstr ""
@@ -38527,9 +38533,6 @@ msgstr ""
msgid "Search by author"
msgstr ""
-msgid "Search by commit title or SHA"
-msgstr ""
-
msgid "Search by message"
msgstr ""
@@ -38575,6 +38578,9 @@ msgstr ""
msgid "Search or create tag"
msgstr ""
+msgid "Search or filter commits"
+msgstr ""
+
msgid "Search or filter results..."
msgstr ""
@@ -52970,6 +52976,9 @@ msgstr ""
msgid "your settings"
msgstr ""
+msgid "yyyy-mm-dd"
+msgstr ""
+
msgid "{group}"
msgstr ""
diff --git a/spec/finders/context_commits_finder_spec.rb b/spec/finders/context_commits_finder_spec.rb
index c22675bc67d564b759ce6fd0477c681039f2c90d..3de1d29b695c4c20d5446294a66aff865bc16451 100644
--- a/spec/finders/context_commits_finder_spec.rb
+++ b/spec/finders/context_commits_finder_spec.rb
@@ -26,27 +26,30 @@
end
it 'returns commits based in author filter' do
- params = { search: 'test text', author: 'Job van der Voort' }
+ params = { author: 'Job van der Voort' }
commits = described_class.new(project, merge_request, params).execute
expect(commits.length).to eq(1)
expect(commits[0].id).to eq('b83d6e391c22777fca1ed3012fce84f633d7fed0')
end
- it 'returns commits based in before filter' do
- params = { search: 'test text', committed_before: 1474828200 }
+ it 'returns commits based in committed before and after filter' do
+ params = { committed_before: 1471631400, committed_after: 1471458600 } # August 18, 2016 - # August 20, 2016
commits = described_class.new(project, merge_request, params).execute
- expect(commits.length).to eq(1)
- expect(commits[0].id).to eq('498214de67004b1da3d820901307bed2a68a8ef6')
+ expect(commits.length).to eq(2)
+ expect(commits[0].id).to eq('1b12f15a11fc6e62177bef08f47bc7b5ce50b141')
+ expect(commits[1].id).to eq('38008cb17ce1466d8fec2dfa6f6ab8dcfe5cf49e')
end
- it 'returns commits based in after filter' do
- params = { search: 'test text', committed_after: 1474828200 }
- commits = described_class.new(project, merge_request, params).execute
+ it 'returns commits from target branch if no filter is applied' do
+ expect(project.repository).to receive(:commits).with(merge_request.target_branch, anything).and_call_original
- expect(commits.length).to eq(1)
+ commits = described_class.new(project, merge_request).execute
+
+ expect(commits.length).to eq(37)
expect(commits[0].id).to eq('b83d6e391c22777fca1ed3012fce84f633d7fed0')
+ expect(commits[1].id).to eq('498214de67004b1da3d820901307bed2a68a8ef6')
end
end
end
diff --git a/spec/frontend/add_context_commits_modal/components/__snapshots__/add_context_commits_modal_spec.js.snap b/spec/frontend/add_context_commits_modal/components/__snapshots__/add_context_commits_modal_spec.js.snap
index 2c2151bfb419f335d1cf25fb2c41513838e0206a..e379aba094c54a08586837ebd6d77e9c605a2391 100644
--- a/spec/frontend/add_context_commits_modal/components/__snapshots__/add_context_commits_modal_spec.js.snap
+++ b/spec/frontend/add_context_commits_modal/components/__snapshots__/add_context_commits_modal_spec.js.snap
@@ -6,8 +6,9 @@ exports[`AddContextCommitsModal renders modal with 2 tabs 1`] = `
body-class="add-review-item pt-0"
cancel-variant="light"
dismisslabel="Close"
- modalclass=""
+ modalclass="add-review-item-modal"
modalid="add-review-item"
+ nofocusonshow="true"
ok-disabled="true"
ok-title="Save changes"
scrollable="true"
@@ -27,9 +28,13 @@ exports[`AddContextCommitsModal renders modal with 2 tabs 1`] = `
-
diff --git a/spec/frontend/add_context_commits_modal/components/add_context_commits_modal_spec.js b/spec/frontend/add_context_commits_modal/components/add_context_commits_modal_spec.js
index 5e96da9af7efffaa6a268eb999856c1a40e3ca3d..27fe010c35415b8cb155125ff4adfedcaebf4bfb 100644
--- a/spec/frontend/add_context_commits_modal/components/add_context_commits_modal_spec.js
+++ b/spec/frontend/add_context_commits_modal/components/add_context_commits_modal_spec.js
@@ -1,4 +1,4 @@
-import { GlModal, GlSearchBoxByType } from '@gitlab/ui';
+import { GlModal, GlFilteredSearch } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
@@ -49,7 +49,7 @@ describe('AddContextCommitsModal', () => {
};
const findModal = () => wrapper.findComponent(GlModal);
- const findSearch = () => wrapper.findComponent(GlSearchBoxByType);
+ const findSearch = () => wrapper.findComponent(GlFilteredSearch);
beforeEach(() => {
wrapper = createWrapper();
@@ -68,12 +68,29 @@ describe('AddContextCommitsModal', () => {
expect(findSearch().exists()).toBe(true);
});
- it('when user starts entering text in search box, it calls action "searchCommits" after waiting for 500s', () => {
- const searchText = 'abcd';
- findSearch().vm.$emit('input', searchText);
- expect(searchCommits).not.toHaveBeenCalled();
- jest.advanceTimersByTime(500);
- expect(searchCommits).toHaveBeenCalledWith(expect.anything(), searchText);
+ it('when user submits after entering filters in search box, then it calls action "searchCommits"', () => {
+ const search = [
+ 'abcd',
+ {
+ type: 'author',
+ value: { operator: '=', data: 'abhi' },
+ },
+ {
+ type: 'committed-before-date',
+ value: { operator: '=', data: '2022-10-31' },
+ },
+ {
+ type: 'committed-after-date',
+ value: { operator: '=', data: '2022-10-28' },
+ },
+ ];
+ findSearch().vm.$emit('submit', search);
+ expect(searchCommits).toHaveBeenCalledWith(expect.anything(), {
+ searchText: 'abcd',
+ author: 'abhi',
+ committed_before: '2022-10-31',
+ committed_after: '2022-10-28',
+ });
});
it('disabled ok button when no row is selected', () => {
diff --git a/spec/models/repository_spec.rb b/spec/models/repository_spec.rb
index f970e818db9e0d2c1c7212f2006474cb2fb387cc..72011693e20dc4385f9bc84ca0a2e25c4ba2dc4a 100644
--- a/spec/models/repository_spec.rb
+++ b/spec/models/repository_spec.rb
@@ -597,6 +597,15 @@ def expect_to_raise_storage_error
end
describe '#list_commits_by' do
+ it 'returns commits when no filter is applied' do
+ commit_ids = repository.list_commits_by(nil, 'master', limit: 2).map(&:id)
+
+ expect(commit_ids).to include(
+ 'b83d6e391c22777fca1ed3012fce84f633d7fed0',
+ '498214de67004b1da3d820901307bed2a68a8ef6'
+ )
+ end
+
it 'returns commits with messages containing a given string' do
commit_ids = repository.list_commits_by('test text', 'master').map(&:id)