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() {
} else {
elements = this.options.elements();
if (search_text) {
return elements.each(function() {
elements.each(function() {
var $el, matches;
$el = $(this);
matches = fuzzaldrinPlus.match($el.text().trim(), search_text);
......@@ -128,8 +128,10 @@ GitLabDropdownFilter = (function() {
}
});
} 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() {
GitLabDropdown.prototype.focusTextInput = function(triggerFocus = false) {
if (this.options.filterable) {
this.dropdown.one('transitionend', () => {
const initialScrollTop = $(window).scrollTop();
if (this.dropdown.is('.open')) {
this.filterInput.focus();
}
if ($(window).scrollTop() < initialScrollTop) {
$(window).scrollTop(initialScrollTop);
}
});
if (triggerFocus) {
......
......@@ -86,8 +86,9 @@
// This is required to handle non-unicode characters in hash
hash = decodeURIComponent(hash);
var fixedTabs = document.querySelector('.js-tabs-affix');
var fixedNav = document.querySelector('.navbar-gitlab');
const fixedTabs = document.querySelector('.js-tabs-affix');
const fixedDiffStats = document.querySelector('.js-diff-files-changed.is-stuck');
const fixedNav = document.querySelector('.navbar-gitlab');
var adjustment = 0;
if (fixedNav) adjustment -= fixedNav.offsetHeight;
......@@ -104,6 +105,11 @@
if (fixedTabs) {
adjustment -= fixedTabs.offsetHeight;
}
if (fixedDiffStats) {
adjustment -= fixedDiffStats.offsetHeight;
}
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';
import './breakpoints';
import './flash';
import BlobForkSuggestion from './blob/blob_fork_suggestion';
import stickyMonitor from './lib/utils/sticky';
/* eslint-disable max-len */
// MergeRequestTabs
......@@ -266,6 +267,10 @@ import BlobForkSuggestion from './blob/blob_fork_suggestion';
const $container = $('#diffs');
$container.html(data.html);
this.initChangesDropdown();
stickyMonitor(document.querySelector('.js-diff-files-changed'));
if (typeof gl.diffNotesCompileComponents !== 'undefined') {
gl.diffNotesCompileComponents();
}
......@@ -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
//
// status - Boolean, true to show, false to hide
......
......@@ -574,6 +574,7 @@
.dropdown-input-field,
.default-dropdown-input {
display: block;
width: 100%;
min-height: 30px;
padding: 0 7px;
......
......@@ -395,12 +395,11 @@
background-color: transparent;
border: 0;
color: $gl-link-color;
transition: color 0.1s linear;
font-weight: 600;
&:hover,
&:focus {
outline: none;
text-decoration: underline;
color: $gl-link-hover-color;
}
}
......@@ -559,3 +558,68 @@
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 @@
}
.mr-version-controls {
position: relative;
background: $gray-light;
color: $gl-text-color;
z-index: 199;
.mr-version-menus-container {
display: -webkit-flex;
......
......@@ -148,6 +148,24 @@ module DiffHelper
options
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
def diff_btn(title, name, selected)
......
......@@ -3,7 +3,7 @@
- can_create_note = !@diff_notes_disabled && can?(current_user, :create_note, diffs.project)
- 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
- 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'
......
.js-toggle-container
.commit-stat-summary
Showing
%button.diff-stats-summary-toggler.js-toggle-button{ type: "button" }
%strong= pluralize(diff_files.size, "changed file")
- sum_added_lines = diff_files.sum(&:added_lines)
- sum_removed_lines = diff_files.sum(&:removed_lines)
.commit-stat-summary.dropdown
Showing
%button.diff-stats-summary-toggler.js-diff-stats-dropdown{ type: "button", data: { toggle: "dropdown" } }<
= pluralize(diff_files.size, "changed file")
= icon("caret-down", class: "prepend-left-5")
%span.diff-stats-additions-deletions-expanded#diff-stats
with
%strong.cgreen #{diff_files.sum(&:added_lines)} additions
%strong.cgreen #{sum_added_lines} additions
and
%strong.cred #{diff_files.sum(&:removed_lines)} deletions
.file-stats.js-toggle-content.hide
%ul
- diff_files.each do |diff_file|
- file_hash = hexdigest(diff_file.file_path)
%li
- if diff_file.deleted_file?
%span.deleted-file
%a{ href: "##{file_hash}" }
%i.fa.fa-minus
= diff_file.old_path
- elsif diff_file.renamed_file?
%span.renamed-file
%a{ href: "##{file_hash}" }
%i.fa.fa-minus
= diff_file.old_path
&rarr;
= 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
%strong.cred #{sum_removed_lines} deletions
.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
- diff_files.each do |diff_file|
%li
%a{ href: "##{hexdigest(diff_file.file_path)}", title: diff_file.new_path }
= icon("#{diff_file_changed_icon(diff_file)} fw", class: "#{diff_file_changed_icon_color(diff_file)} append-right-5")
%span.diff-file-changes-path= diff_file.new_path
.pull-right
%span.cgreen<
+#{diff_file.added_lines}
%span.cred<
\-#{diff_file.removed_lines}
%li.dropdown-menu-empty-link.hidden
%a{ href: "#" }
No files found.
---
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