Commit e3fedd68 authored by Fatih Acet's avatar Fatih Acet

Merge branch '57364-improve-diff-nav-header' into 'master'

Resolve "Improve diff nav header"

See merge request gitlab-org/gitlab-ce!26557
parents 361c7ca6 bf47270e
...@@ -14,6 +14,9 @@ const BreakpointInstance = { ...@@ -14,6 +14,9 @@ const BreakpointInstance = {
return breakpoint; return breakpoint;
}, },
isDesktop() {
return ['lg', 'md'].includes(this.getBreakpointSize);
},
}; };
export default BreakpointInstance; export default BreakpointInstance;
...@@ -20,6 +20,7 @@ import { ...@@ -20,6 +20,7 @@ import {
MAX_TREE_WIDTH, MAX_TREE_WIDTH,
TREE_HIDE_STATS_WIDTH, TREE_HIDE_STATS_WIDTH,
MR_TREE_SHOW_KEY, MR_TREE_SHOW_KEY,
CENTERED_LIMITED_CONTAINER_CLASSES,
} from '../constants'; } from '../constants';
export default { export default {
...@@ -114,6 +115,9 @@ export default { ...@@ -114,6 +115,9 @@ export default {
hideFileStats() { hideFileStats() {
return this.treeWidth <= TREE_HIDE_STATS_WIDTH; return this.treeWidth <= TREE_HIDE_STATS_WIDTH;
}, },
isLimitedContainer() {
return !this.showTreeList && !this.isParallelView;
},
}, },
watch: { watch: {
diffViewType() { diffViewType() {
...@@ -148,6 +152,7 @@ export default { ...@@ -148,6 +152,7 @@ export default {
this.adjustView(); this.adjustView();
eventHub.$once('fetchedNotesData', this.setDiscussions); eventHub.$once('fetchedNotesData', this.setDiscussions);
eventHub.$once('fetchDiffData', this.fetchData); eventHub.$once('fetchDiffData', this.fetchData);
this.CENTERED_LIMITED_CONTAINER_CLASSES = CENTERED_LIMITED_CONTAINER_CLASSES;
}, },
beforeDestroy() { beforeDestroy() {
eventHub.$off('fetchDiffData', this.fetchData); eventHub.$off('fetchDiffData', this.fetchData);
...@@ -202,8 +207,6 @@ export default { ...@@ -202,8 +207,6 @@ export default {
adjustView() { adjustView() {
if (this.shouldShow) { if (this.shouldShow) {
this.$nextTick(() => { this.$nextTick(() => {
window.mrTabs.resetViewContainer();
window.mrTabs.expandViewContainer(this.showTreeList);
this.setEventListeners(); this.setEventListeners();
}); });
} else { } else {
...@@ -256,6 +259,7 @@ export default { ...@@ -256,6 +259,7 @@ export default {
:merge-request-diffs="mergeRequestDiffs" :merge-request-diffs="mergeRequestDiffs"
:merge-request-diff="mergeRequestDiff" :merge-request-diff="mergeRequestDiff"
:target-branch="targetBranch" :target-branch="targetBranch"
:is-limited-container="isLimitedContainer"
/> />
<hidden-files-warning <hidden-files-warning
...@@ -285,7 +289,12 @@ export default { ...@@ -285,7 +289,12 @@ export default {
/> />
<tree-list :hide-file-stats="hideFileStats" /> <tree-list :hide-file-stats="hideFileStats" />
</div> </div>
<div class="diff-files-holder"> <div
class="diff-files-holder"
:class="{
[CENTERED_LIMITED_CONTAINER_CLASSES]: isLimitedContainer,
}"
>
<commit-widget v-if="commit" :commit="commit" /> <commit-widget v-if="commit" :commit="commit" />
<template v-if="renderDiffFiles"> <template v-if="renderDiffFiles">
<diff-file <diff-file
......
...@@ -7,6 +7,7 @@ import Icon from '~/vue_shared/components/icon.vue'; ...@@ -7,6 +7,7 @@ import Icon from '~/vue_shared/components/icon.vue';
import CompareVersionsDropdown from './compare_versions_dropdown.vue'; import CompareVersionsDropdown from './compare_versions_dropdown.vue';
import SettingsDropdown from './settings_dropdown.vue'; import SettingsDropdown from './settings_dropdown.vue';
import DiffStats from './diff_stats.vue'; import DiffStats from './diff_stats.vue';
import { CENTERED_LIMITED_CONTAINER_CLASSES } from '../constants';
export default { export default {
components: { components: {
...@@ -35,6 +36,11 @@ export default { ...@@ -35,6 +36,11 @@ export default {
required: false, required: false,
default: null, default: null,
}, },
isLimitedContainer: {
type: Boolean,
required: false,
default: false,
},
}, },
computed: { computed: {
...mapGetters('diffs', ['hasCollapsedFile', 'diffFilesLength']), ...mapGetters('diffs', ['hasCollapsedFile', 'diffFilesLength']),
...@@ -62,6 +68,9 @@ export default { ...@@ -62,6 +68,9 @@ export default {
return this.mergeRequestDiff.base_version_path; return this.mergeRequestDiff.base_version_path;
}, },
}, },
created() {
this.CENTERED_LIMITED_CONTAINER_CLASSES = CENTERED_LIMITED_CONTAINER_CLASSES;
},
mounted() { mounted() {
polyfillSticky(this.$el); polyfillSticky(this.$el);
}, },
...@@ -77,8 +86,13 @@ export default { ...@@ -77,8 +86,13 @@ export default {
</script> </script>
<template> <template>
<div class="mr-version-controls" :class="{ 'is-fileTreeOpen': showTreeList }"> <div class="mr-version-controls border-top border-bottom">
<div class="mr-version-menus-container content-block"> <div
class="mr-version-menus-container content-block"
:class="{
[CENTERED_LIMITED_CONTAINER_CLASSES]: isLimitedContainer,
}"
>
<button <button
v-gl-tooltip.hover v-gl-tooltip.hover
type="button" type="button"
......
<script> <script>
import _ from 'underscore'; import _ from 'underscore';
import { mapActions, mapGetters } from 'vuex'; import { mapActions, mapGetters } from 'vuex';
import { polyfillSticky } from '~/lib/utils/sticky'; import { polyfillSticky, stickyMonitor } from '~/lib/utils/sticky';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue'; import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import FileIcon from '~/vue_shared/components/file_icon.vue'; import FileIcon from '~/vue_shared/components/file_icon.vue';
...@@ -11,7 +11,7 @@ import { __, s__, sprintf } from '~/locale'; ...@@ -11,7 +11,7 @@ import { __, s__, sprintf } from '~/locale';
import { diffViewerModes } from '~/ide/constants'; import { diffViewerModes } from '~/ide/constants';
import EditButton from './edit_button.vue'; import EditButton from './edit_button.vue';
import DiffStats from './diff_stats.vue'; import DiffStats from './diff_stats.vue';
import { scrollToElement } from '~/lib/utils/common_utils'; import { scrollToElement, contentTop } from '~/lib/utils/common_utils';
export default { export default {
components: { components: {
...@@ -137,9 +137,20 @@ export default { ...@@ -137,9 +137,20 @@ export default {
isModeChanged() { isModeChanged() {
return this.diffFile.viewer.name === diffViewerModes.mode_changed; return this.diffFile.viewer.name === diffViewerModes.mode_changed;
}, },
showExpandDiffToFullFileEnabled() {
return gon.features.expandDiffFullFile && !this.diffFile.is_fully_expanded;
},
expandDiffToFullFileTitle() {
if (this.diffFile.isShowingFullFile) {
return s__('MRDiff|Show changes only');
}
return s__('MRDiff|Show full file');
},
}, },
mounted() { mounted() {
polyfillSticky(this.$refs.header); polyfillSticky(this.$refs.header);
const fileHeaderHeight = this.$refs.header.clientHeight;
stickyMonitor(this.$refs.header, contentTop() - fileHeaderHeight - 1, false);
}, },
methods: { methods: {
...mapActions('diffs', ['toggleFileDiscussions', 'toggleFullDiff']), ...mapActions('diffs', ['toggleFileDiscussions', 'toggleFullDiff']),
...@@ -243,70 +254,70 @@ export default { ...@@ -243,70 +254,70 @@ export default {
class="file-actions d-none d-sm-block" class="file-actions d-none d-sm-block"
> >
<diff-stats :added-lines="diffFile.added_lines" :removed-lines="diffFile.removed_lines" /> <diff-stats :added-lines="diffFile.added_lines" :removed-lines="diffFile.removed_lines" />
<template v-if="diffFile.blob && diffFile.blob.readable_text"> <div class="btn-group" role="group">
<button <template v-if="diffFile.blob && diffFile.blob.readable_text">
:disabled="!diffHasDiscussions(diffFile)" <button
:class="{ active: hasExpandedDiscussions }" :disabled="!diffHasDiscussions(diffFile)"
:title="s__('MergeRequests|Toggle comments for this file')" :class="{ active: hasExpandedDiscussions }"
class="js-btn-vue-toggle-comments btn" :title="s__('MergeRequests|Toggle comments for this file')"
type="button" class="js-btn-vue-toggle-comments btn"
@click="handleToggleDiscussions" type="button"
> @click="handleToggleDiscussions"
<icon name="comment" /> >
</button> <icon name="comment" />
</button>
<edit-button
v-if="!diffFile.deleted_file"
:can-current-user-fork="canCurrentUserFork"
:edit-path="diffFile.edit_path"
:can-modify-blob="diffFile.can_modify_blob"
@showForkMessage="showForkMessage"
/>
</template>
<a <edit-button
v-if="diffFile.replaced_view_path" v-if="!diffFile.deleted_file"
:href="diffFile.replaced_view_path" :can-current-user-fork="canCurrentUserFork"
class="btn view-file js-view-replaced-file" :edit-path="diffFile.edit_path"
v-html="viewReplacedFileButtonText" :can-modify-blob="diffFile.can_modify_blob"
> @showForkMessage="showForkMessage"
</a> />
<gl-tooltip :target="() => $refs.viewButton" placement="bottom">
<span v-html="viewFileButtonText"></span>
</gl-tooltip>
<gl-button
ref="viewButton"
:href="diffFile.view_path"
target="blank"
class="view-file js-view-file-button"
>
<icon name="external-link" />
</gl-button>
<gl-button
v-if="!diffFile.is_fully_expanded"
class="expand-file js-expand-file"
@click="toggleFullDiff(diffFile.file_path)"
>
<template v-if="diffFile.isShowingFullFile">
{{ s__('MRDiff|Show changes only') }}
</template>
<template v-else>
{{ s__('MRDiff|Show full file') }}
</template> </template>
<gl-loading-icon v-if="diffFile.isLoadingFullFile" inline />
</gl-button>
<a <a
v-if="diffFile.external_url" v-if="diffFile.replaced_view_path"
v-gl-tooltip.hover :href="diffFile.replaced_view_path"
:href="diffFile.external_url" class="btn view-file js-view-replaced-file"
:title="`View on ${diffFile.formatted_external_url}`" v-html="viewReplacedFileButtonText"
target="_blank" >
rel="noopener noreferrer" </a>
class="btn btn-file-option js-external-url" <gl-button
> v-if="!diffFile.is_fully_expanded"
<icon name="external-link" /> ref="expandDiffToFullFileButton"
</a> v-gl-tooltip.hover
:title="expandDiffToFullFileTitle"
class="expand-file js-expand-file"
@click="toggleFullDiff(diffFile.file_path)"
>
<gl-loading-icon v-if="diffFile.isLoadingFullFile" color="dark" inline />
<icon v-else-if="diffFile.isShowingFullFile" name="doc-changes" />
<icon v-else name="doc-expand" />
</gl-button>
<gl-button
ref="viewButton"
v-gl-tooltip.hover
:href="diffFile.view_path"
target="blank"
class="view-file js-view-file-button"
:title="viewFileButtonText"
>
<icon name="external-link" />
</gl-button>
<a
v-if="diffFile.external_url"
v-gl-tooltip.hover
:href="diffFile.external_url"
:title="`View on ${diffFile.formatted_external_url}`"
target="_blank"
rel="noopener noreferrer"
class="btn btn-file-option js-external-url"
>
<icon name="external-link" />
</a>
</div>
</div> </div>
</div> </div>
</template> </template>
...@@ -47,3 +47,6 @@ export const OLD_LINE_KEY = 'old_line'; ...@@ -47,3 +47,6 @@ export const OLD_LINE_KEY = 'old_line';
export const NEW_LINE_KEY = 'new_line'; export const NEW_LINE_KEY = 'new_line';
export const TYPE_KEY = 'type'; export const TYPE_KEY = 'type';
export const LEFT_LINE_KEY = 'left'; export const LEFT_LINE_KEY = 'left';
export const CENTERED_LIMITED_CONTAINER_CLASSES =
'container-limited limit-container-width mx-auto px-3';
...@@ -7,7 +7,7 @@ import axios from './axios_utils'; ...@@ -7,7 +7,7 @@ import axios from './axios_utils';
import { getLocationHash } from './url_utility'; import { getLocationHash } from './url_utility';
import { convertToCamelCase } from './text_utility'; import { convertToCamelCase } from './text_utility';
import { isObject } from './type_utility'; import { isObject } from './type_utility';
import BreakpointInstance from '../../breakpoints'; import breakpointInstance from '../../breakpoints';
export const getPagePath = (index = 0) => { export const getPagePath = (index = 0) => {
const page = $('body').attr('data-page') || ''; const page = $('body').attr('data-page') || '';
...@@ -198,11 +198,10 @@ export const contentTop = () => { ...@@ -198,11 +198,10 @@ export const contentTop = () => {
const mrTabsHeight = $('.merge-request-tabs').outerHeight() || 0; const mrTabsHeight = $('.merge-request-tabs').outerHeight() || 0;
const headerHeight = $('.navbar-gitlab').outerHeight() || 0; const headerHeight = $('.navbar-gitlab').outerHeight() || 0;
const diffFilesChanged = $('.js-diff-files-changed').outerHeight() || 0; const diffFilesChanged = $('.js-diff-files-changed').outerHeight() || 0;
const mdScreenOrBigger = ['lg', 'md'].includes(BreakpointInstance.getBreakpointSize()); const isDesktop = breakpointInstance.isDesktop();
const diffFileTitleBar = const diffFileTitleBar =
(mdScreenOrBigger && $('.diff-file .file-title-flex-parent:visible').outerHeight()) || 0; (isDesktop && $('.diff-file .file-title-flex-parent:visible').outerHeight()) || 0;
const compareVersionsHeaderHeight = const compareVersionsHeaderHeight = (isDesktop && $('.mr-version-controls').outerHeight()) || 0;
(mdScreenOrBigger && $('.mr-version-controls').outerHeight()) || 0;
return ( return (
perfBar + perfBar +
......
...@@ -331,6 +331,10 @@ span.idiff { ...@@ -331,6 +331,10 @@ span.idiff {
padding: 5px $gl-padding; padding: 5px $gl-padding;
margin: 0; margin: 0;
border-radius: $border-radius-default $border-radius-default 0 0; border-radius: $border-radius-default $border-radius-default 0 0;
&.is-stuck {
border-radius: 0;
}
} }
.file-header-content { .file-header-content {
......
...@@ -7,12 +7,15 @@ ...@@ -7,12 +7,15 @@
cursor: pointer; cursor: pointer;
@media (min-width: map-get($grid-breakpoints, md)) { @media (min-width: map-get($grid-breakpoints, md)) {
$mr-file-header-top: $mr-version-controls-height + $header-height + $mr-tabs-height; // The `-1` below is to prevent two borders from clashing up against eachother -
// the bottom of the compare-versions header and the top of the file header
$mr-file-header-top: $mr-version-controls-height + $header-height + $mr-tabs-height - 1;
position: -webkit-sticky; position: -webkit-sticky;
position: sticky; position: sticky;
top: $mr-file-header-top; top: $mr-file-header-top;
z-index: 102; z-index: 102;
height: $mr-version-controls-height;
&::before { &::before {
content: ''; content: '';
...@@ -54,7 +57,8 @@ ...@@ -54,7 +57,8 @@
background-color: $gray-normal; background-color: $gray-normal;
} }
a { a,
button {
color: $gray-700; color: $gray-700;
} }
......
...@@ -736,7 +736,6 @@ ...@@ -736,7 +736,6 @@
background: $gray-light; background: $gray-light;
color: $gl-text-color; color: $gl-text-color;
margin-top: -1px; margin-top: -1px;
border-top: 1px solid $border-color;
.mr-version-menus-container { .mr-version-menus-container {
display: flex; display: flex;
...@@ -759,6 +758,7 @@ ...@@ -759,6 +758,7 @@
.content-block { .content-block {
padding: $gl-padding-top $gl-padding; padding: $gl-padding-top $gl-padding;
border-bottom: 0;
} }
.comments-disabled-notif { .comments-disabled-notif {
...@@ -783,16 +783,18 @@ ...@@ -783,16 +783,18 @@
padding-right: 5px; padding-right: 5px;
} }
// Shortening button height by 1px to make compare-versions
// header 56px and fit into our 8px design grid
button {
height: 34px;
}
@include media-breakpoint-up(md) { @include media-breakpoint-up(md) {
position: -webkit-sticky; position: -webkit-sticky;
position: sticky; position: sticky;
top: $header-height + $mr-tabs-height; top: $header-height + $mr-tabs-height;
width: 100%; margin-left: -16px;
width: calc(100% + 32px);
&.is-fileTreeOpen {
margin-left: -16px;
width: calc(100% + 32px);
}
.mr-version-menus-container { .mr-version-menus-container {
flex-wrap: nowrap; flex-wrap: nowrap;
......
---
title: Make stylistic improvements to diff nav header
merge_request: 26557
author:
type: fixed
...@@ -57,6 +57,24 @@ describe('diffs/components/app', () => { ...@@ -57,6 +57,24 @@ describe('diffs/components/app', () => {
wrapper.destroy(); wrapper.destroy();
}); });
it('adds container-limiting classes when showFileTree is false with inline diffs', () => {
createComponent({}, ({ state }) => {
state.diffs.showTreeList = false;
state.diffs.isParallelView = false;
});
expect(wrapper.contains('.container-limited.limit-container-width')).toBe(true);
});
it('does not add container-limiting classes when showFileTree is false with inline diffs', () => {
createComponent({}, ({ state }) => {
state.diffs.showTreeList = true;
state.diffs.isParallelView = false;
});
expect(wrapper.contains('.container-limited.limit-container-width')).toBe(false);
});
it('displays loading icon on loading', () => { it('displays loading icon on loading', () => {
createComponent({}, ({ state }) => { createComponent({}, ({ state }) => {
state.diffs.isLoading = true; state.diffs.isLoading = true;
......
...@@ -66,6 +66,26 @@ describe('CompareVersions', () => { ...@@ -66,6 +66,26 @@ describe('CompareVersions', () => {
expect(inlineBtn.innerHTML).toContain('Inline'); expect(inlineBtn.innerHTML).toContain('Inline');
expect(parallelBtn.innerHTML).toContain('Side-by-side'); expect(parallelBtn.innerHTML).toContain('Side-by-side');
}); });
it('adds container-limiting classes when showFileTree is false with inline diffs', () => {
vm.isLimitedContainer = true;
vm.$nextTick(() => {
const limitedContainer = vm.$el.querySelector('.container-limited.limit-container-width');
expect(limitedContainer).not.toBeNull();
});
});
it('does not add container-limiting classes when showFileTree is false with inline diffs', () => {
vm.isLimitedContainer = false;
vm.$nextTick(() => {
const limitedContainer = vm.$el.querySelector('.container-limited.limit-container-width');
expect(limitedContainer).toBeNull();
});
});
}); });
describe('setInlineDiffViewType', () => { describe('setInlineDiffViewType', () => {
......
...@@ -672,7 +672,7 @@ describe('diff_file_header', () => { ...@@ -672,7 +672,7 @@ describe('diff_file_header', () => {
vm = mountComponentWithStore(Component, { props, store }); vm = mountComponentWithStore(Component, { props, store });
expect(vm.$el.querySelector('.js-expand-file').textContent).toContain('Show changes only'); expect(vm.$el.querySelector('.ic-doc-changes')).not.toBeNull();
}); });
it('shows expand text', () => { it('shows expand text', () => {
...@@ -680,7 +680,7 @@ describe('diff_file_header', () => { ...@@ -680,7 +680,7 @@ describe('diff_file_header', () => {
vm = mountComponentWithStore(Component, { props, store }); vm = mountComponentWithStore(Component, { props, store });
expect(vm.$el.querySelector('.js-expand-file').textContent).toContain('Show full file'); expect(vm.$el.querySelector('.ic-doc-expand')).not.toBeNull();
}); });
it('renders loading icon', () => { it('renders loading icon', () => {
......
...@@ -2,7 +2,7 @@ import axios from '~/lib/utils/axios_utils'; ...@@ -2,7 +2,7 @@ import axios from '~/lib/utils/axios_utils';
import * as commonUtils from '~/lib/utils/common_utils'; import * as commonUtils from '~/lib/utils/common_utils';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import { faviconDataUrl, overlayDataUrl, faviconWithOverlayDataUrl } from './mock_data'; import { faviconDataUrl, overlayDataUrl, faviconWithOverlayDataUrl } from './mock_data';
import BreakpointInstance from '~/breakpoints'; import breakpointInstance from '~/breakpoints';
const PIXEL_TOLERANCE = 0.2; const PIXEL_TOLERANCE = 0.2;
...@@ -383,7 +383,7 @@ describe('common_utils', () => { ...@@ -383,7 +383,7 @@ describe('common_utils', () => {
describe('contentTop', () => { describe('contentTop', () => {
it('does not add height for fileTitle or compareVersionsHeader if screen is too small', () => { it('does not add height for fileTitle or compareVersionsHeader if screen is too small', () => {
spyOn(BreakpointInstance, 'getBreakpointSize').and.returnValue('sm'); spyOn(breakpointInstance, 'isDesktop').and.returnValue(false);
setFixtures(` setFixtures(`
<div class="diff-file file-title-flex-parent"> <div class="diff-file file-title-flex-parent">
...@@ -398,7 +398,7 @@ describe('common_utils', () => { ...@@ -398,7 +398,7 @@ describe('common_utils', () => {
}); });
it('adds height for fileTitle and compareVersionsHeader screen is large enough', () => { it('adds height for fileTitle and compareVersionsHeader screen is large enough', () => {
spyOn(BreakpointInstance, 'getBreakpointSize').and.returnValue('lg'); spyOn(breakpointInstance, 'isDesktop').and.returnValue(true);
setFixtures(` setFixtures(`
<div class="diff-file file-title-flex-parent"> <div class="diff-file file-title-flex-parent">
......
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