Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Léo-Paul Géneau
gitlab-ce
Commits
8fa001e7
Commit
8fa001e7
authored
Mar 13, 2018
by
Simon Knox
Committed by
Fatih Acet
Mar 13, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Resolve "Projects::MergeRequestsController#show is slow (implement skeleton loading)"
parent
9a1af4a3
Changes
8
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
117 additions
and
14 deletions
+117
-14
app/assets/javascripts/notes.js
app/assets/javascripts/notes.js
+68
-0
app/controllers/projects/discussions_controller.rb
app/controllers/projects/discussions_controller.rb
+6
-0
app/views/discussions/_diff_with_notes.html.haml
app/views/discussions/_diff_with_notes.html.haml
+21
-10
app/views/discussions/_discussion.html.haml
app/views/discussions/_discussion.html.haml
+1
-1
changelogs/unreleased/35475-lazy-diff.yml
changelogs/unreleased/35475-lazy-diff.yml
+5
-0
config/routes/project.rb
config/routes/project.rb
+1
-1
spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb
.../user_resolves_diff_notes_and_discussions_resolve_spec.rb
+1
-0
spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb
...atures/merge_request/user_scrolls_to_note_on_load_spec.rb
+14
-2
No files found.
app/assets/javascripts/notes.js
View file @
8fa001e7
...
@@ -16,6 +16,10 @@ import Autosize from 'autosize';
...
@@ -16,6 +16,10 @@ import Autosize from 'autosize';
import
'
vendor/jquery.caret
'
;
// required by jquery.atwho
import
'
vendor/jquery.caret
'
;
// required by jquery.atwho
import
'
vendor/jquery.atwho
'
;
import
'
vendor/jquery.atwho
'
;
import
AjaxCache
from
'
~/lib/utils/ajax_cache
'
;
import
AjaxCache
from
'
~/lib/utils/ajax_cache
'
;
import
Vue
from
'
vue
'
;
import
syntaxHighlight
from
'
~/syntax_highlight
'
;
import
SkeletonLoadingContainer
from
'
~/vue_shared/components/skeleton_loading_container.vue
'
;
import
{
__
}
from
'
~/locale
'
;
import
axios
from
'
./lib/utils/axios_utils
'
;
import
axios
from
'
./lib/utils/axios_utils
'
;
import
{
getLocationHash
}
from
'
./lib/utils/url_utility
'
;
import
{
getLocationHash
}
from
'
./lib/utils/url_utility
'
;
import
Flash
from
'
./flash
'
;
import
Flash
from
'
./flash
'
;
...
@@ -99,6 +103,13 @@ export default class Notes {
...
@@ -99,6 +103,13 @@ export default class Notes {
$
(
'
.note-edit-form
'
).
clone
()
$
(
'
.note-edit-form
'
).
clone
()
.
addClass
(
'
mr-note-edit-form
'
).
insertAfter
(
'
.note-edit-form
'
);
.
addClass
(
'
mr-note-edit-form
'
).
insertAfter
(
'
.note-edit-form
'
);
}
}
const
hash
=
getLocationHash
();
const
$anchor
=
hash
&&
document
.
getElementById
(
hash
);
if
(
$anchor
)
{
this
.
loadLazyDiff
({
currentTarget
:
$anchor
});
}
}
}
setViewType
(
view
)
{
setViewType
(
view
)
{
...
@@ -135,6 +146,8 @@ export default class Notes {
...
@@ -135,6 +146,8 @@ export default class Notes {
this
.
$wrapperEl
.
on
(
'
click
'
,
'
.js-close-discussion-note-form
'
,
this
.
cancelDiscussionForm
);
this
.
$wrapperEl
.
on
(
'
click
'
,
'
.js-close-discussion-note-form
'
,
this
.
cancelDiscussionForm
);
// toggle commit list
// toggle commit list
this
.
$wrapperEl
.
on
(
'
click
'
,
'
.system-note-commit-list-toggler
'
,
this
.
toggleCommitList
);
this
.
$wrapperEl
.
on
(
'
click
'
,
'
.system-note-commit-list-toggler
'
,
this
.
toggleCommitList
);
this
.
$wrapperEl
.
on
(
'
click
'
,
'
.js-toggle-lazy-diff
'
,
this
.
loadLazyDiff
);
// fetch notes when tab becomes visible
// fetch notes when tab becomes visible
this
.
$wrapperEl
.
on
(
'
visibilitychange
'
,
this
.
visibilityChange
);
this
.
$wrapperEl
.
on
(
'
visibilitychange
'
,
this
.
visibilityChange
);
// when issue status changes, we need to refresh data
// when issue status changes, we need to refresh data
...
@@ -173,6 +186,7 @@ export default class Notes {
...
@@ -173,6 +186,7 @@ export default class Notes {
this
.
$wrapperEl
.
off
(
'
keydown
'
,
'
.js-note-text
'
);
this
.
$wrapperEl
.
off
(
'
keydown
'
,
'
.js-note-text
'
);
this
.
$wrapperEl
.
off
(
'
click
'
,
'
.js-comment-resolve-button
'
);
this
.
$wrapperEl
.
off
(
'
click
'
,
'
.js-comment-resolve-button
'
);
this
.
$wrapperEl
.
off
(
'
click
'
,
'
.system-note-commit-list-toggler
'
);
this
.
$wrapperEl
.
off
(
'
click
'
,
'
.system-note-commit-list-toggler
'
);
this
.
$wrapperEl
.
off
(
'
click
'
,
'
.js-toggle-lazy-diff
'
);
this
.
$wrapperEl
.
off
(
'
ajax:success
'
,
'
.js-main-target-form
'
);
this
.
$wrapperEl
.
off
(
'
ajax:success
'
,
'
.js-main-target-form
'
);
this
.
$wrapperEl
.
off
(
'
ajax:success
'
,
'
.js-discussion-note-form
'
);
this
.
$wrapperEl
.
off
(
'
ajax:success
'
,
'
.js-discussion-note-form
'
);
this
.
$wrapperEl
.
off
(
'
ajax:complete
'
,
'
.js-main-target-form
'
);
this
.
$wrapperEl
.
off
(
'
ajax:complete
'
,
'
.js-main-target-form
'
);
...
@@ -1207,6 +1221,60 @@ export default class Notes {
...
@@ -1207,6 +1221,60 @@ export default class Notes {
return
this
.
notesCountBadge
.
text
(
parseInt
(
this
.
notesCountBadge
.
text
(),
10
)
+
updateCount
);
return
this
.
notesCountBadge
.
text
(
parseInt
(
this
.
notesCountBadge
.
text
(),
10
)
+
updateCount
);
}
}
static
renderPlaceholderComponent
(
$container
)
{
const
el
=
$container
.
find
(
'
.js-code-placeholder
'
).
get
(
0
);
new
Vue
({
// eslint-disable-line no-new
el
,
components
:
{
SkeletonLoadingContainer
,
},
render
(
createElement
)
{
return
createElement
(
'
skeleton-loading-container
'
);
},
});
}
static
renderDiffContent
(
$container
,
data
)
{
const
{
discussion_html
}
=
data
;
const
lines
=
$
(
discussion_html
).
find
(
'
.line_holder
'
);
lines
.
addClass
(
'
fade-in
'
);
$container
.
find
(
'
tbody
'
).
prepend
(
lines
);
const
fileHolder
=
$container
.
find
(
'
.file-holder
'
);
$container
.
find
(
'
.line-holder-placeholder
'
).
remove
();
syntaxHighlight
(
fileHolder
);
}
static
renderDiffError
(
$container
)
{
$container
.
find
(
'
.line_content
'
).
html
(
$
(
`
<div class="nothing-here-block">
${
__
(
'
Unable to load the diff.
'
)}
<a class="js-toggle-lazy-diff" href="javascript:void(0)">Try again</a>?
</div>
`
),
);
}
loadLazyDiff
(
e
)
{
const
$container
=
$
(
e
.
currentTarget
).
closest
(
'
.js-toggle-container
'
);
Notes
.
renderPlaceholderComponent
(
$container
);
$container
.
find
(
'
.js-toggle-lazy-diff
'
).
removeClass
(
'
js-toggle-lazy-diff
'
);
const
tableEl
=
$container
.
find
(
'
tbody
'
);
if
(
tableEl
.
length
===
0
)
return
;
const
fileHolder
=
$container
.
find
(
'
.file-holder
'
);
const
url
=
fileHolder
.
data
(
'
linesPath
'
);
axios
.
get
(
url
)
.
then
(({
data
})
=>
{
Notes
.
renderDiffContent
(
$container
,
data
);
})
.
catch
(()
=>
{
Notes
.
renderDiffError
(
$container
);
});
}
toggleCommitList
(
e
)
{
toggleCommitList
(
e
)
{
const
$element
=
$
(
e
.
currentTarget
);
const
$element
=
$
(
e
.
currentTarget
);
const
$closestSystemCommitList
=
$element
.
siblings
(
'
.system-note-commit-list
'
);
const
$closestSystemCommitList
=
$element
.
siblings
(
'
.system-note-commit-list
'
);
...
...
app/controllers/projects/discussions_controller.rb
View file @
8fa001e7
...
@@ -19,6 +19,12 @@ class Projects::DiscussionsController < Projects::ApplicationController
...
@@ -19,6 +19,12 @@ class Projects::DiscussionsController < Projects::ApplicationController
render_discussion
render_discussion
end
end
def
show
render
json:
{
discussion_html:
view_to_html_string
(
'discussions/_diff_with_notes'
,
discussion:
discussion
,
expanded:
true
)
}
end
private
private
def
render_discussion
def
render_discussion
...
...
app/views/discussions/_diff_with_notes.html.haml
View file @
8fa001e7
...
@@ -2,8 +2,12 @@
...
@@ -2,8 +2,12 @@
-
blob
=
discussion
.
blob
-
blob
=
discussion
.
blob
-
discussions
=
{
discussion
.
original_line_code
=>
[
discussion
]
}
-
discussions
=
{
discussion
.
original_line_code
=>
[
discussion
]
}
-
diff_file_class
=
diff_file
.
text?
?
'text-file'
:
'js-image-file'
-
diff_file_class
=
diff_file
.
text?
?
'text-file'
:
'js-image-file'
-
diff_data
=
{}
-
expanded
=
discussion
.
expanded?
||
local_assigns
.
fetch
(
:expanded
,
nil
)
-
unless
expanded
-
diff_data
=
{
lines_path:
project_merge_request_discussion_path
(
discussion
.
project
,
discussion
.
noteable
,
discussion
)
}
.diff-file.file-holder
{
class:
diff_file_class
}
.diff-file.file-holder
{
class:
diff_file_class
,
data:
diff_data
}
.js-file-title.file-title.file-title-flex-parent
.js-file-title.file-title.file-title-flex-parent
.file-header-content
.file-header-content
=
render
"projects/diffs/file_header"
,
diff_file:
diff_file
,
url:
discussion_path
(
discussion
),
show_toggle:
false
=
render
"projects/diffs/file_header"
,
diff_file:
diff_file
,
url:
discussion_path
(
discussion
),
show_toggle:
false
...
@@ -11,17 +15,24 @@
...
@@ -11,17 +15,24 @@
-
if
diff_file
.
text?
-
if
diff_file
.
text?
.diff-content.code.js-syntax-highlight
.diff-content.code.js-syntax-highlight
%table
%table
=
render
partial:
"projects/diffs/line"
,
-
if
expanded
collection:
discussion
.
truncated_diff_lines
,
-
discussions
=
{
discussion
.
original_line_code
=>
[
discussion
]
}
as: :line
,
=
render
partial:
"projects/diffs/line"
,
locals:
{
diff_file:
diff_file
,
collection:
discussion
.
truncated_diff_lines
,
discussions:
discussions
,
as: :line
,
discussion_expanded:
true
,
locals:
{
diff_file:
diff_file
,
plain:
true
}
discussions:
discussions
,
discussion_expanded:
true
,
plain:
true
}
-
else
%tr
.line_holder.line-holder-placeholder
%td
.old_line.diff-line-num
%td
.new_line.diff-line-num
%td
.line_content
.js-code-placeholder
=
render
"discussions/diff_discussion"
,
discussions:
[
discussion
],
expanded:
true
-
else
-
else
-
partial
=
(
diff_file
.
new_file?
||
diff_file
.
deleted_file?
)
?
'single_image_diff'
:
'replaced_image_diff'
-
partial
=
(
diff_file
.
new_file?
||
diff_file
.
deleted_file?
)
?
'single_image_diff'
:
'replaced_image_diff'
=
render
partial:
"projects/diffs/
#{
partial
}
"
,
locals:
{
diff_file:
diff_file
,
position:
discussion
.
position
.
to_json
,
click_to_comment:
false
}
=
render
partial:
"projects/diffs/
#{
partial
}
"
,
locals:
{
diff_file:
diff_file
,
position:
discussion
.
position
.
to_json
,
click_to_comment:
false
}
.note-container
.note-container
=
render
partial:
"discussions/notes"
,
locals:
{
discussion:
discussion
,
show_toggle:
false
,
show_image_comment_badge:
true
,
disable_collapse_class:
true
}
=
render
partial:
"discussions/notes"
,
locals:
{
discussion:
discussion
,
show_toggle:
false
,
show_image_comment_badge:
true
,
disable_collapse_class:
true
}
app/views/discussions/_discussion.html.haml
View file @
8fa001e7
...
@@ -8,7 +8,7 @@
...
@@ -8,7 +8,7 @@
.discussion.js-toggle-container
{
data:
{
discussion_id:
discussion
.
id
}
}
.discussion.js-toggle-container
{
data:
{
discussion_id:
discussion
.
id
}
}
.discussion-header
.discussion-header
.discussion-actions
.discussion-actions
%button
.note-action-button.discussion-toggle-button.js-toggle-button
{
type:
"button"
}
%button
.note-action-button.discussion-toggle-button.js-toggle-button
{
type:
"button"
,
class:
(
"js-toggle-lazy-diff"
unless
expanded
)
}
-
if
expanded
-
if
expanded
=
icon
(
"chevron-up"
)
=
icon
(
"chevron-up"
)
-
else
-
else
...
...
changelogs/unreleased/35475-lazy-diff.yml
0 → 100644
View file @
8fa001e7
---
title
:
lazy load diffs on merge request discussions
merge_request
:
author
:
type
:
performance
config/routes/project.rb
View file @
8fa001e7
...
@@ -130,7 +130,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
...
@@ -130,7 +130,7 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
post
:bulk_update
post
:bulk_update
end
end
resources
:discussions
,
only:
[],
constraints:
{
id:
/\h{40}/
}
do
resources
:discussions
,
only:
[
:show
],
constraints:
{
id:
/\h{40}/
}
do
member
do
member
do
post
:resolve
post
:resolve
delete
:resolve
,
action: :unresolve
delete
:resolve
,
action: :unresolve
...
...
spec/features/merge_request/user_resolves_diff_notes_and_discussions_resolve_spec.rb
View file @
8fa001e7
...
@@ -108,6 +108,7 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
...
@@ -108,6 +108,7 @@ describe 'Merge request > User resolves diff notes and discussions', :js do
it
'shows resolved discussion when toggled'
do
it
'shows resolved discussion when toggled'
do
find
(
".timeline-content .discussion[data-discussion-id='
#{
note
.
discussion_id
}
'] .discussion-toggle-button"
).
click
find
(
".timeline-content .discussion[data-discussion-id='
#{
note
.
discussion_id
}
'] .discussion-toggle-button"
).
click
expect
(
page
.
find
(
".line-holder-placeholder"
)).
to
be_visible
expect
(
page
.
find
(
".timeline-content #note_
#{
note
.
id
}
"
)).
to
be_visible
expect
(
page
.
find
(
".timeline-content #note_
#{
note
.
id
}
"
)).
to
be_visible
end
end
end
end
...
...
spec/features/merge_request/user_scrolls_to_note_on_load_spec.rb
View file @
8fa001e7
...
@@ -5,15 +5,18 @@ describe 'Merge request > User scrolls to note on load', :js do
...
@@ -5,15 +5,18 @@ describe 'Merge request > User scrolls to note on load', :js do
let
(
:user
)
{
project
.
creator
}
let
(
:user
)
{
project
.
creator
}
let
(
:merge_request
)
{
create
(
:merge_request
,
source_project:
project
,
author:
user
)
}
let
(
:merge_request
)
{
create
(
:merge_request
,
source_project:
project
,
author:
user
)
}
let
(
:note
)
{
create
(
:diff_note_on_merge_request
,
noteable:
merge_request
,
project:
project
)
}
let
(
:note
)
{
create
(
:diff_note_on_merge_request
,
noteable:
merge_request
,
project:
project
)
}
let
(
:resolved_note
)
{
create
(
:diff_note_on_merge_request
,
:resolved
,
noteable:
merge_request
,
project:
project
)
}
let
(
:fragment_id
)
{
"#note_
#{
note
.
id
}
"
}
let
(
:fragment_id
)
{
"#note_
#{
note
.
id
}
"
}
let
(
:collapsed_fragment_id
)
{
"#note_
#{
resolved_note
.
id
}
"
}
before
do
before
do
sign_in
(
user
)
sign_in
(
user
)
page
.
current_window
.
resize_to
(
1000
,
300
)
page
.
current_window
.
resize_to
(
1000
,
300
)
visit
"
#{
project_merge_request_path
(
project
,
merge_request
)
}#{
fragment_id
}
"
end
end
it
'scrolls down to fragment'
do
it
'scrolls note into view'
do
visit
"
#{
project_merge_request_path
(
project
,
merge_request
)
}#{
fragment_id
}
"
page_height
=
page
.
current_window
.
size
[
1
]
page_height
=
page
.
current_window
.
size
[
1
]
page_scroll_y
=
page
.
evaluate_script
(
"window.scrollY"
)
page_scroll_y
=
page
.
evaluate_script
(
"window.scrollY"
)
fragment_position_top
=
page
.
evaluate_script
(
"Math.round($('
#{
fragment_id
}
').offset().top)"
)
fragment_position_top
=
page
.
evaluate_script
(
"Math.round($('
#{
fragment_id
}
').offset().top)"
)
...
@@ -23,4 +26,13 @@ describe 'Merge request > User scrolls to note on load', :js do
...
@@ -23,4 +26,13 @@ describe 'Merge request > User scrolls to note on load', :js do
expect
(
fragment_position_top
).
to
be
>=
page_scroll_y
expect
(
fragment_position_top
).
to
be
>=
page_scroll_y
expect
(
fragment_position_top
).
to
be
<
(
page_scroll_y
+
page_height
)
expect
(
fragment_position_top
).
to
be
<
(
page_scroll_y
+
page_height
)
end
end
it
'expands collapsed notes'
do
visit
"
#{
project_merge_request_path
(
project
,
merge_request
)
}#{
collapsed_fragment_id
}
"
note_element
=
find
(
collapsed_fragment_id
)
note_container
=
note_element
.
ancestor
(
'.js-toggle-container'
)
expect
(
note_element
.
visible?
).
to
eq
true
expect
(
note_container
.
find
(
'.line_content.noteable_line.old'
,
match: :first
).
visible?
).
to
eq
true
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment