Commit fe5086c2 authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'diff-changed-files-dropdown' into 'master'

Moved changed files into a dropdown

Closes #29778

See merge request !13128
parents 0ef8fd0d ae96e6a3
...@@ -115,7 +115,7 @@ GitLabDropdownFilter = (function() { ...@@ -115,7 +115,7 @@ GitLabDropdownFilter = (function() {
} else { } else {
elements = this.options.elements(); elements = this.options.elements();
if (search_text) { if (search_text) {
return elements.each(function() { elements.each(function() {
var $el, matches; var $el, matches;
$el = $(this); $el = $(this);
matches = fuzzaldrinPlus.match($el.text().trim(), search_text); matches = fuzzaldrinPlus.match($el.text().trim(), search_text);
...@@ -128,8 +128,10 @@ GitLabDropdownFilter = (function() { ...@@ -128,8 +128,10 @@ GitLabDropdownFilter = (function() {
} }
}); });
} else { } else {
return elements.show().removeClass('option-hidden'); elements.show().removeClass('option-hidden');
} }
elements.parent().find('.dropdown-menu-empty-link').toggleClass('hidden', elements.is(':visible'));
} }
}; };
...@@ -732,9 +734,15 @@ GitLabDropdown = (function() { ...@@ -732,9 +734,15 @@ GitLabDropdown = (function() {
GitLabDropdown.prototype.focusTextInput = function(triggerFocus = false) { GitLabDropdown.prototype.focusTextInput = function(triggerFocus = false) {
if (this.options.filterable) { if (this.options.filterable) {
this.dropdown.one('transitionend', () => { this.dropdown.one('transitionend', () => {
const initialScrollTop = $(window).scrollTop();
if (this.dropdown.is('.open')) { if (this.dropdown.is('.open')) {
this.filterInput.focus(); this.filterInput.focus();
} }
if ($(window).scrollTop() < initialScrollTop) {
$(window).scrollTop(initialScrollTop);
}
}); });
if (triggerFocus) { if (triggerFocus) {
......
...@@ -86,8 +86,9 @@ ...@@ -86,8 +86,9 @@
// This is required to handle non-unicode characters in hash // This is required to handle non-unicode characters in hash
hash = decodeURIComponent(hash); hash = decodeURIComponent(hash);
var fixedTabs = document.querySelector('.js-tabs-affix'); const fixedTabs = document.querySelector('.js-tabs-affix');
var fixedNav = document.querySelector('.navbar-gitlab'); const fixedDiffStats = document.querySelector('.js-diff-files-changed.is-stuck');
const fixedNav = document.querySelector('.navbar-gitlab');
var adjustment = 0; var adjustment = 0;
if (fixedNav) adjustment -= fixedNav.offsetHeight; if (fixedNav) adjustment -= fixedNav.offsetHeight;
...@@ -104,6 +105,11 @@ ...@@ -104,6 +105,11 @@
if (fixedTabs) { if (fixedTabs) {
adjustment -= fixedTabs.offsetHeight; adjustment -= fixedTabs.offsetHeight;
} }
if (fixedDiffStats) {
adjustment -= fixedDiffStats.offsetHeight;
}
window.scrollBy(0, adjustment); window.scrollBy(0, adjustment);
} }
}; };
......
export const isSticky = (el, scrollY, stickyTop) => {
const top = el.offsetTop - scrollY;
if (top === stickyTop) {
el.classList.add('is-stuck');
} else {
el.classList.remove('is-stuck');
}
};
export default (el) => {
if (!el) return;
const computedStyle = window.getComputedStyle(el);
if (!/sticky/.test(computedStyle.position)) return;
const stickyTop = parseInt(computedStyle.top, 10);
document.addEventListener('scroll', () => isSticky(el, window.scrollY, stickyTop), {
passive: true,
});
};
...@@ -7,6 +7,7 @@ import Cookies from 'js-cookie'; ...@@ -7,6 +7,7 @@ import Cookies from 'js-cookie';
import './breakpoints'; import './breakpoints';
import './flash'; import './flash';
import BlobForkSuggestion from './blob/blob_fork_suggestion'; import BlobForkSuggestion from './blob/blob_fork_suggestion';
import stickyMonitor from './lib/utils/sticky';
/* eslint-disable max-len */ /* eslint-disable max-len */
// MergeRequestTabs // MergeRequestTabs
...@@ -266,6 +267,10 @@ import BlobForkSuggestion from './blob/blob_fork_suggestion'; ...@@ -266,6 +267,10 @@ import BlobForkSuggestion from './blob/blob_fork_suggestion';
const $container = $('#diffs'); const $container = $('#diffs');
$container.html(data.html); $container.html(data.html);
this.initChangesDropdown();
stickyMonitor(document.querySelector('.js-diff-files-changed'));
if (typeof gl.diffNotesCompileComponents !== 'undefined') { if (typeof gl.diffNotesCompileComponents !== 'undefined') {
gl.diffNotesCompileComponents(); gl.diffNotesCompileComponents();
} }
...@@ -314,6 +319,13 @@ import BlobForkSuggestion from './blob/blob_fork_suggestion'; ...@@ -314,6 +319,13 @@ import BlobForkSuggestion from './blob/blob_fork_suggestion';
}); });
} }
initChangesDropdown() {
$('.js-diff-stats-dropdown').glDropdown({
filterable: true,
remoteFilter: false,
});
}
// Show or hide the loading spinner // Show or hide the loading spinner
// //
// status - Boolean, true to show, false to hide // status - Boolean, true to show, false to hide
......
...@@ -574,6 +574,7 @@ ...@@ -574,6 +574,7 @@
.dropdown-input-field, .dropdown-input-field,
.default-dropdown-input { .default-dropdown-input {
display: block;
width: 100%; width: 100%;
min-height: 30px; min-height: 30px;
padding: 0 7px; padding: 0 7px;
......
...@@ -395,12 +395,11 @@ ...@@ -395,12 +395,11 @@
background-color: transparent; background-color: transparent;
border: 0; border: 0;
color: $gl-link-color; color: $gl-link-color;
transition: color 0.1s linear; font-weight: 600;
&:hover, &:hover,
&:focus { &:focus {
outline: none; outline: none;
text-decoration: underline;
color: $gl-link-hover-color; color: $gl-link-hover-color;
} }
} }
...@@ -559,3 +558,68 @@ ...@@ -559,3 +558,68 @@
outline: 0; outline: 0;
} }
} }
.diff-files-changed {
.commit-stat-summary {
@include new-style-dropdown;
z-index: -1;
@media (min-width: $screen-sm-min) {
margin-left: -$gl-padding;
padding-left: $gl-padding;
background-color: $white-light;
}
}
@media (min-width: $screen-sm-min) {
position: -webkit-sticky;
position: sticky;
top: 84px;
background-color: $white-light;
z-index: 190;
+ .files,
+ .alert {
margin-top: 1px;
}
&:not(.is-stuck) .diff-stats-additions-deletions-collapsed {
display: none;
}
&.is-stuck {
padding-top: 0;
padding-bottom: 0;
border-bottom: 1px solid $white-dark;
transform: translateY(16px);
.diff-stats-additions-deletions-expanded,
.inline-parallel-buttons {
display: none;
}
+ .files,
+ .alert {
margin-top: 30px;
}
}
}
}
.diff-file-changes {
width: 450px;
z-index: 150;
@media (min-width: $screen-sm-min) {
left: $gl-padding;
}
a {
padding-top: 8px;
padding-bottom: 8px;
}
}
.diff-file-changes-path {
@include str-truncated(78%);
}
...@@ -691,8 +691,10 @@ ...@@ -691,8 +691,10 @@
} }
.mr-version-controls { .mr-version-controls {
position: relative;
background: $gray-light; background: $gray-light;
color: $gl-text-color; color: $gl-text-color;
z-index: 199;
.mr-version-menus-container { .mr-version-menus-container {
display: -webkit-flex; display: -webkit-flex;
......
...@@ -148,6 +148,24 @@ module DiffHelper ...@@ -148,6 +148,24 @@ module DiffHelper
options options
end end
def diff_file_changed_icon(diff_file)
if diff_file.deleted_file? || diff_file.renamed_file?
"minus"
elsif diff_file.new_file?
"plus"
else
"adjust"
end
end
def diff_file_changed_icon_color(diff_file)
if diff_file.deleted_file?
"cred"
elsif diff_file.new_file?
"cgreen"
end
end
private private
def diff_btn(title, name, selected) def diff_btn(title, name, selected)
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
- can_create_note = !@diff_notes_disabled && can?(current_user, :create_note, diffs.project) - can_create_note = !@diff_notes_disabled && can?(current_user, :create_note, diffs.project)
- diff_files = diffs.diff_files - diff_files = diffs.diff_files
.content-block.oneline-block.files-changed .content-block.oneline-block.files-changed.diff-files-changed.js-diff-files-changed
.inline-parallel-buttons .inline-parallel-buttons
- if !diffs_expanded? && diff_files.any? { |diff_file| diff_file.collapsed? } - if !diffs_expanded? && diff_files.any? { |diff_file| diff_file.collapsed? }
= link_to 'Expand all', url_for(params.merge(expanded: 1, format: nil)), class: 'btn btn-default' = link_to 'Expand all', url_for(params.merge(expanded: 1, format: nil)), class: 'btn btn-default'
......
.js-toggle-container - sum_added_lines = diff_files.sum(&:added_lines)
.commit-stat-summary - sum_removed_lines = diff_files.sum(&:removed_lines)
.commit-stat-summary.dropdown
Showing Showing
%button.diff-stats-summary-toggler.js-toggle-button{ type: "button" } %button.diff-stats-summary-toggler.js-diff-stats-dropdown{ type: "button", data: { toggle: "dropdown" } }<
%strong= pluralize(diff_files.size, "changed file") = pluralize(diff_files.size, "changed file")
= icon("caret-down", class: "prepend-left-5")
%span.diff-stats-additions-deletions-expanded#diff-stats
with with
%strong.cgreen #{diff_files.sum(&:added_lines)} additions %strong.cgreen #{sum_added_lines} additions
and and
%strong.cred #{diff_files.sum(&:removed_lines)} deletions %strong.cred #{sum_removed_lines} deletions
.file-stats.js-toggle-content.hide .diff-stats-additions-deletions-collapsed.pull-right{ "aria-hidden": "true", "aria-describedby": "diff-stats" }
%strong.cgreen<
+#{sum_added_lines}
%strong.cred<
\-#{sum_removed_lines}
.dropdown-menu.diff-file-changes
= dropdown_filter("Search files")
.dropdown-content
%ul %ul
- diff_files.each do |diff_file| - diff_files.each do |diff_file|
- file_hash = hexdigest(diff_file.file_path)
%li %li
- if diff_file.deleted_file? %a{ href: "##{hexdigest(diff_file.file_path)}", title: diff_file.new_path }
%span.deleted-file = icon("#{diff_file_changed_icon(diff_file)} fw", class: "#{diff_file_changed_icon_color(diff_file)} append-right-5")
%a{ href: "##{file_hash}" } %span.diff-file-changes-path= diff_file.new_path
%i.fa.fa-minus .pull-right
= diff_file.old_path %span.cgreen<
- elsif diff_file.renamed_file? +#{diff_file.added_lines}
%span.renamed-file %span.cred<
%a{ href: "##{file_hash}" } \-#{diff_file.removed_lines}
%i.fa.fa-minus %li.dropdown-menu-empty-link.hidden
= diff_file.old_path %a{ href: "#" }
&rarr; No files found.
= diff_file.new_path
- elsif diff_file.new_file?
%span.new-file
%a{ href: "##{file_hash}" }
%i.fa.fa-plus
= diff_file.new_path
- else
%span.edit-file
%a{ href: "##{file_hash}" }
%i.fa.fa-adjust
= diff_file.new_path
---
title: Moved diff changed files into a dropdown
merge_request:
author:
import { isSticky } from '~/lib/utils/sticky';
describe('sticky', () => {
const el = {
offsetTop: 0,
classList: {},
};
beforeEach(() => {
el.offsetTop = 0;
el.classList.add = jasmine.createSpy('spy');
el.classList.remove = jasmine.createSpy('spy');
});
describe('classList.remove', () => {
it('does not call classList.remove when stuck', () => {
isSticky(el, 0, 0);
expect(
el.classList.remove,
).not.toHaveBeenCalled();
});
it('calls classList.remove when not stuck', () => {
el.offsetTop = 10;
isSticky(el, 0, 0);
expect(
el.classList.remove,
).toHaveBeenCalledWith('is-stuck');
});
});
describe('classList.add', () => {
it('calls classList.add when stuck', () => {
isSticky(el, 0, 0);
expect(
el.classList.add,
).toHaveBeenCalledWith('is-stuck');
});
it('does not call classList.add when not stuck', () => {
el.offsetTop = 10;
isSticky(el, 0, 0);
expect(
el.classList.add,
).not.toHaveBeenCalled();
});
});
});
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