Commit 77bfad1f authored by Fatih Acet's avatar Fatih Acet

Merge branch '18435-autocomplete-is-not-performant' into 'master'

Make autocomplete request performant

## What does this MR do?

Restricts the `autocomplete_sources`action to returning the `json`of one specific `at` type at a time.

Makes sure all commands start by immediately showing the `loading` dropdown.

If the `loading` dropdown is active, we will request and load in the data for that specific `at` type. We manually trigger the filter again. This time, if `loading` dropdown is not active, initiate default filter behaviour and use the correct data template.

Also fixes an issue where `setup` was called multiple times by only setting up and destroying atwho on a focused/blured input.

## Are there points in the code the reviewer needs to double check?

## Why was this MR needed?

`autocomplete_sources` was requested on page load and is large.

## Screenshots (if relevant)

3 requests for 3 different first-time references.

![Screen_Shot_2016-10-14_at_14.43.12](/uploads/0b04eab0d0bf3638d6d6e431036b8089/Screen_Shot_2016-10-14_at_14.43.12.png)

## Does this MR meet the acceptance criteria?

- [x] [CHANGELOG](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CHANGELOG) entry added
- [ ] [Documentation created/updated](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/development/doc_styleguide.md)
- [ ] API support added
- Tests
  - [x] Added for this feature/bug
  - [x] All builds are passing
- [x] Conform by the [merge request performance guides](http://docs.gitlab.com/ce/development/merge_request_performance_guidelines.html)
- [x] Conform by the [style guides](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md#style-guides)
- [x] Branch has no merge conflicts with `master` (if it does - rebase it please)
- [x] [Squashed related commits together](https://git-scm.com/book/en/Git-Tools-Rewriting-History#Squashing-Commits)

## What are the relevant issue numbers?

Closes #22802

Closes #18435

See merge request !6856
parents e7b995e8 1356e40f
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
this.form.addClass('gfm-form'); this.form.addClass('gfm-form');
// remove notify commit author checkbox for non-commit notes // remove notify commit author checkbox for non-commit notes
gl.utils.disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button')); gl.utils.disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button'));
GitLab.GfmAutoComplete.setup(this.form.find('.js-gfm-input')); gl.GfmAutoComplete.setup(this.form.find('.js-gfm-input'));
new DropzoneInput(this.form); new DropzoneInput(this.form);
autosize(this.textarea); autosize(this.textarea);
// form and textarea event listeners // form and textarea event listeners
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
this.renderWipExplanation = bind(this.renderWipExplanation, this); this.renderWipExplanation = bind(this.renderWipExplanation, this);
this.resetAutosave = bind(this.resetAutosave, this); this.resetAutosave = bind(this.resetAutosave, this);
this.handleSubmit = bind(this.handleSubmit, this); this.handleSubmit = bind(this.handleSubmit, this);
GitLab.GfmAutoComplete.setup(); gl.GfmAutoComplete.setup();
new UsersSelect(); new UsersSelect();
new ZenMode(); new ZenMode();
this.titleField = this.form.find("input[name*='[title]']"); this.titleField = this.form.find("input[name*='[title]']");
......
class Projects::AutocompleteSourcesController < Projects::ApplicationController
before_action :load_autocomplete_service, except: [:emojis, :members]
def emojis
render json: Gitlab::AwardEmoji.urls
end
def members
render json: ::Projects::ParticipantsService.new(@project, current_user).execute(noteable)
end
def issues
render json: @autocomplete_service.issues
end
def merge_requests
render json: @autocomplete_service.merge_requests
end
def labels
render json: @autocomplete_service.labels
end
def milestones
render json: @autocomplete_service.milestones
end
def commands
render json: @autocomplete_service.commands(noteable, params[:type])
end
private
def load_autocomplete_service
@autocomplete_service = ::Projects::AutocompleteService.new(@project, current_user)
end
def noteable
case params[:type]
when 'Issue'
IssuesFinder.new(current_user, project_id: @project.id).execute.find_by(iid: params[:type_id])
when 'MergeRequest'
MergeRequestsFinder.new(current_user, project_id: @project.id).execute.find_by(iid: params[:type_id])
when 'Commit'
@project.commit(params[:type_id])
end
end
end
...@@ -127,39 +127,6 @@ class ProjectsController < Projects::ApplicationController ...@@ -127,39 +127,6 @@ class ProjectsController < Projects::ApplicationController
redirect_to edit_project_path(@project), alert: ex.message redirect_to edit_project_path(@project), alert: ex.message
end end
def autocomplete_sources
noteable =
case params[:type]
when 'Issue'
IssuesFinder.new(current_user, project_id: @project.id).
execute.find_by(iid: params[:type_id])
when 'MergeRequest'
MergeRequestsFinder.new(current_user, project_id: @project.id).
execute.find_by(iid: params[:type_id])
when 'Commit'
@project.commit(params[:type_id])
else
nil
end
autocomplete = ::Projects::AutocompleteService.new(@project, current_user)
participants = ::Projects::ParticipantsService.new(@project, current_user).execute(noteable)
@suggestions = {
emojis: Gitlab::AwardEmoji.urls,
issues: autocomplete.issues,
milestones: autocomplete.milestones,
mergerequests: autocomplete.merge_requests,
labels: autocomplete.labels,
members: participants,
commands: autocomplete.commands(noteable, params[:type])
}
respond_to do |format|
format.json { render json: @suggestions }
end
end
def new_issue_address def new_issue_address
return render_404 unless Gitlab::IncomingEmail.supports_issue_creation? return render_404 unless Gitlab::IncomingEmail.supports_issue_creation?
......
...@@ -3,6 +3,14 @@ ...@@ -3,6 +3,14 @@
- if project - if project
:javascript :javascript
GitLab.GfmAutoComplete.dataSource = "#{autocomplete_sources_namespace_project_path(project.namespace, project, type: noteable_type, type_id: params[:id])}" gl.GfmAutoComplete.dataSources = {
GitLab.GfmAutoComplete.cachedData = undefined; emojis: "#{emojis_namespace_project_autocomplete_sources_path(project.namespace, project)}",
GitLab.GfmAutoComplete.setup(); members: "#{members_namespace_project_autocomplete_sources_path(project.namespace, project, type: noteable_type, type_id: params[:id])}",
issues: "#{issues_namespace_project_autocomplete_sources_path(project.namespace, project)}",
mergeRequests: "#{merge_requests_namespace_project_autocomplete_sources_path(project.namespace, project)}",
labels: "#{labels_namespace_project_autocomplete_sources_path(project.namespace, project)}",
milestones: "#{milestones_namespace_project_autocomplete_sources_path(project.namespace, project)}",
commands: "#{commands_namespace_project_autocomplete_sources_path(project.namespace, project, type: noteable_type, type_id: params[:id])}"
};
gl.GfmAutoComplete.setup();
---
title: Made comment autocomplete more performant and removed some loading bugs
merge_request: 6856
author:
...@@ -11,6 +11,18 @@ constraints(ProjectUrlConstrainer.new) do ...@@ -11,6 +11,18 @@ constraints(ProjectUrlConstrainer.new) do
module: :projects, module: :projects,
as: :project) do as: :project) do
resources :autocomplete_sources, only: [] do
collection do
get 'emojis'
get 'members'
get 'issues'
get 'merge_requests'
get 'labels'
get 'milestones'
get 'commands'
end
end
# #
# Templates # Templates
# #
...@@ -316,7 +328,6 @@ constraints(ProjectUrlConstrainer.new) do ...@@ -316,7 +328,6 @@ constraints(ProjectUrlConstrainer.new) do
post :remove_export post :remove_export
post :generate_new_export post :generate_new_export
get :download_export get :download_export
get :autocomplete_sources
get :activity get :activity
get :refs get :refs
put :new_issue_address put :new_issue_address
......
require 'spec_helper' require 'spec_helper'
feature 'Member autocomplete', feature: true do feature 'Member autocomplete', feature: true do
include WaitForAjax
let(:project) { create(:project, :public) } let(:project) { create(:project, :public) }
let(:user) { create(:user) } let(:user) { create(:user) }
let(:participant) { create(:user) } let(:participant) { create(:user) }
...@@ -79,11 +81,10 @@ feature 'Member autocomplete', feature: true do ...@@ -79,11 +81,10 @@ feature 'Member autocomplete', feature: true do
end end
def open_member_suggestions def open_member_suggestions
sleep 1
page.within('.new-note') do page.within('.new-note') do
sleep 1 find('#note_note').send_keys('@')
find('#note_note').native.send_keys('@')
end end
wait_for_ajax
end end
def visit_issue(project, issue) def visit_issue(project, issue)
......
...@@ -10,12 +10,12 @@ describe 'GFM autocomplete loading', feature: true, js: true do ...@@ -10,12 +10,12 @@ describe 'GFM autocomplete loading', feature: true, js: true do
end end
it 'does not load on project#show' do it 'does not load on project#show' do
expect(evaluate_script('GitLab.GfmAutoComplete.dataSource')).to eq('') expect(evaluate_script('gl.GfmAutoComplete.dataSources')).to eq({})
end end
it 'loads on new issue page' do it 'loads on new issue page' do
visit new_namespace_project_issue_path(project.namespace, project) visit new_namespace_project_issue_path(project.namespace, project)
expect(evaluate_script('GitLab.GfmAutoComplete.dataSource')).not_to eq('') expect(evaluate_script('gl.GfmAutoComplete.dataSources')).not_to eq({})
end end
end end
...@@ -80,10 +80,6 @@ describe 'project routing' do ...@@ -80,10 +80,6 @@ describe 'project routing' do
expect(get('/gitlab/gitlabhq/edit')).to route_to('projects#edit', namespace_id: 'gitlab', id: 'gitlabhq') expect(get('/gitlab/gitlabhq/edit')).to route_to('projects#edit', namespace_id: 'gitlab', id: 'gitlabhq')
end end
it 'to #autocomplete_sources' do
expect(get('/gitlab/gitlabhq/autocomplete_sources')).to route_to('projects#autocomplete_sources', namespace_id: 'gitlab', id: 'gitlabhq')
end
describe 'to #show' do describe 'to #show' do
context 'regular name' do context 'regular name' do
it { expect(get('/gitlab/gitlabhq')).to route_to('projects#show', namespace_id: 'gitlab', id: 'gitlabhq') } it { expect(get('/gitlab/gitlabhq')).to route_to('projects#show', namespace_id: 'gitlab', id: 'gitlabhq') }
...@@ -117,6 +113,21 @@ describe 'project routing' do ...@@ -117,6 +113,21 @@ describe 'project routing' do
end end
end end
# emojis_namespace_project_autocomplete_sources_path GET /:project_id/autocomplete_sources/emojis(.:format) projects/autocomplete_sources#emojis
# members_namespace_project_autocomplete_sources_path GET /:project_id/autocomplete_sources/members(.:format) projects/autocomplete_sources#members
# issues_namespace_project_autocomplete_sources_path GET /:project_id/autocomplete_sources/issues(.:format) projects/autocomplete_sources#issues
# merge_requests_namespace_project_autocomplete_sources_path GET /:project_id/autocomplete_sources/merge_requests(.:format) projects/autocomplete_sources#merge_requests
# labels_namespace_project_autocomplete_sources_path GET /:project_id/autocomplete_sources/labels(.:format) projects/autocomplete_sources#labels
# milestones_namespace_project_autocomplete_sources_path GET /:project_id/autocomplete_sources/milestones(.:format) projects/autocomplete_sources#milestones
# commands_namespace_project_autocomplete_sources_path GET /:project_id/autocomplete_sources/commands(.:format) projects/autocomplete_sources#commands
describe Projects::AutocompleteSourcesController, 'routing' do
[:emojis, :members, :issues, :merge_requests, :labels, :milestones, :commands].each do |action|
it "to ##{action}" do
expect(get("/gitlab/gitlabhq/autocomplete_sources/#{action}")).to route_to("projects/autocomplete_sources##{action}", namespace_id: 'gitlab', project_id: 'gitlabhq')
end
end
end
# pages_project_wikis GET /:project_id/wikis/pages(.:format) projects/wikis#pages # pages_project_wikis GET /:project_id/wikis/pages(.:format) projects/wikis#pages
# history_project_wiki GET /:project_id/wikis/:id/history(.:format) projects/wikis#history # history_project_wiki GET /:project_id/wikis/:id/history(.:format) projects/wikis#history
# project_wikis POST /:project_id/wikis(.:format) projects/wikis#create # project_wikis POST /:project_id/wikis(.:format) projects/wikis#create
......
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