Merge branch '57669-fix-bug-clicking-file-header-refreshes-page' into 'master'
Fix bug where clicking file header in diff refreshes page Closes #57669 See merge request gitlab-org/gitlab-ce!26422
This commit is contained in:
commit
f87ff7af53
|
@ -170,6 +170,7 @@ export default {
|
||||||
</div>
|
</div>
|
||||||
<gl-loading-icon v-if="showLoadingIcon" class="diff-content loading" />
|
<gl-loading-icon v-if="showLoadingIcon" class="diff-content loading" />
|
||||||
<template v-else>
|
<template v-else>
|
||||||
|
<div :id="`diff-content-${file.file_hash}`">
|
||||||
<div v-if="errorMessage" class="diff-viewer">
|
<div v-if="errorMessage" class="diff-viewer">
|
||||||
<div class="nothing-here-block" v-html="errorMessage"></div>
|
<div class="nothing-here-block" v-html="errorMessage"></div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -185,6 +186,7 @@ export default {
|
||||||
:diff-file="file"
|
:diff-file="file"
|
||||||
:help-page-path="helpPagePath"
|
:help-page-path="helpPagePath"
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<div v-if="isFileTooLarge" class="nothing-here-block diff-collapsed js-too-large-diff">
|
<div v-if="isFileTooLarge" class="nothing-here-block diff-collapsed js-too-large-diff">
|
||||||
{{ __('This source diff could not be displayed because it is too large.') }}
|
{{ __('This source diff could not be displayed because it is too large.') }}
|
||||||
|
|
|
@ -11,6 +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';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
|
@ -66,6 +67,9 @@ export default {
|
||||||
hasExpandedDiscussions() {
|
hasExpandedDiscussions() {
|
||||||
return this.diffHasExpandedDiscussions(this.diffFile);
|
return this.diffHasExpandedDiscussions(this.diffFile);
|
||||||
},
|
},
|
||||||
|
diffContentIDSelector() {
|
||||||
|
return `#diff-content-${this.diffFile.file_hash}`;
|
||||||
|
},
|
||||||
icon() {
|
icon() {
|
||||||
if (this.diffFile.submodule) {
|
if (this.diffFile.submodule) {
|
||||||
return 'archive';
|
return 'archive';
|
||||||
|
@ -77,6 +81,11 @@ export default {
|
||||||
if (this.diffFile.submodule) {
|
if (this.diffFile.submodule) {
|
||||||
return this.diffFile.submodule_tree_url || this.diffFile.submodule_link;
|
return this.diffFile.submodule_tree_url || this.diffFile.submodule_link;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!this.discussionPath) {
|
||||||
|
return this.diffContentIDSelector;
|
||||||
|
}
|
||||||
|
|
||||||
return this.discussionPath;
|
return this.discussionPath;
|
||||||
},
|
},
|
||||||
filePath() {
|
filePath() {
|
||||||
|
@ -149,6 +158,18 @@ export default {
|
||||||
handleToggleDiscussions() {
|
handleToggleDiscussions() {
|
||||||
this.toggleFileDiscussions(this.diffFile);
|
this.toggleFileDiscussions(this.diffFile);
|
||||||
},
|
},
|
||||||
|
handleFileNameClick(e) {
|
||||||
|
const isLinkToOtherPage =
|
||||||
|
this.diffFile.submodule_tree_url || this.diffFile.submodule_link || this.discussionPath;
|
||||||
|
|
||||||
|
if (!isLinkToOtherPage) {
|
||||||
|
e.preventDefault();
|
||||||
|
const selector = this.diffContentIDSelector;
|
||||||
|
|
||||||
|
scrollToElement(document.querySelector(selector));
|
||||||
|
window.location.hash = selector;
|
||||||
|
}
|
||||||
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
@ -168,7 +189,14 @@ export default {
|
||||||
class="diff-toggle-caret append-right-5"
|
class="diff-toggle-caret append-right-5"
|
||||||
@click.stop="handleToggle"
|
@click.stop="handleToggle"
|
||||||
/>
|
/>
|
||||||
<a v-once ref="titleWrapper" :href="titleLink" class="append-right-4 js-title-wrapper">
|
<a
|
||||||
|
v-once
|
||||||
|
id="diffFile.file_path"
|
||||||
|
ref="titleWrapper"
|
||||||
|
class="append-right-4 js-title-wrapper"
|
||||||
|
:href="titleLink"
|
||||||
|
@click="handleFileNameClick"
|
||||||
|
>
|
||||||
<file-icon
|
<file-icon
|
||||||
:file-name="filePath"
|
:file-name="filePath"
|
||||||
:size="18"
|
:size="18"
|
||||||
|
|
|
@ -7,6 +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';
|
||||||
|
|
||||||
export const getPagePath = (index = 0) => {
|
export const getPagePath = (index = 0) => {
|
||||||
const page = $('body').attr('data-page') || '';
|
const page = $('body').attr('data-page') || '';
|
||||||
|
@ -193,16 +194,24 @@ export const isMetaKey = e => e.metaKey || e.ctrlKey || e.altKey || e.shiftKey;
|
||||||
export const isMetaClick = e => e.metaKey || e.ctrlKey || e.which === 2;
|
export const isMetaClick = e => e.metaKey || e.ctrlKey || e.which === 2;
|
||||||
|
|
||||||
export const contentTop = () => {
|
export const contentTop = () => {
|
||||||
const perfBar = $('#js-peek').height() || 0;
|
const perfBar = $('#js-peek').outerHeight() || 0;
|
||||||
const mrTabsHeight = $('.merge-request-tabs').height() || 0;
|
const mrTabsHeight = $('.merge-request-tabs').outerHeight() || 0;
|
||||||
const headerHeight = $('.navbar-gitlab').height() || 0;
|
const headerHeight = $('.navbar-gitlab').outerHeight() || 0;
|
||||||
const diffFilesChanged = $('.js-diff-files-changed').height() || 0;
|
const diffFilesChanged = $('.js-diff-files-changed').outerHeight() || 0;
|
||||||
const diffFileLargeEnoughScreen =
|
const mdScreenOrBigger = ['lg', 'md'].includes(BreakpointInstance.getBreakpointSize());
|
||||||
'matchMedia' in window ? window.matchMedia('min-width: 768') : true;
|
|
||||||
const diffFileTitleBar =
|
const diffFileTitleBar =
|
||||||
(diffFileLargeEnoughScreen && $('.diff-file .file-title-flex-parent:visible').height()) || 0;
|
(mdScreenOrBigger && $('.diff-file .file-title-flex-parent:visible').outerHeight()) || 0;
|
||||||
|
const compareVersionsHeaderHeight =
|
||||||
|
(mdScreenOrBigger && $('.mr-version-controls').outerHeight()) || 0;
|
||||||
|
|
||||||
return perfBar + mrTabsHeight + headerHeight + diffFilesChanged + diffFileTitleBar;
|
return (
|
||||||
|
perfBar +
|
||||||
|
mrTabsHeight +
|
||||||
|
headerHeight +
|
||||||
|
diffFilesChanged +
|
||||||
|
diffFileTitleBar +
|
||||||
|
compareVersionsHeaderHeight
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export const scrollToElement = element => {
|
export const scrollToElement = element => {
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
title: Scroll to diff file content when clicking on file header name and it is not
|
||||||
|
a link to other page
|
||||||
|
merge_request: !26422
|
||||||
|
author:
|
||||||
|
type: fixed
|
|
@ -3,7 +3,7 @@ import Vuex from 'vuex';
|
||||||
import diffsModule from '~/diffs/store/modules';
|
import diffsModule from '~/diffs/store/modules';
|
||||||
import notesModule from '~/notes/stores/modules';
|
import notesModule from '~/notes/stores/modules';
|
||||||
import DiffFileHeader from '~/diffs/components/diff_file_header.vue';
|
import DiffFileHeader from '~/diffs/components/diff_file_header.vue';
|
||||||
import { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
|
import mountComponent, { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
|
||||||
import diffDiscussionsMockData from '../mock_data/diff_discussions';
|
import diffDiscussionsMockData from '../mock_data/diff_discussions';
|
||||||
import { diffViewerModes } from '~/ide/constants';
|
import { diffViewerModes } from '~/ide/constants';
|
||||||
|
|
||||||
|
@ -249,6 +249,75 @@ describe('diff_file_header', () => {
|
||||||
expect(vm.$emit).not.toHaveBeenCalled();
|
expect(vm.$emit).not.toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('handleFileNameClick', () => {
|
||||||
|
let e;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
e = { preventDefault: () => {} };
|
||||||
|
spyOn(e, 'preventDefault');
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when file name links to other page', () => {
|
||||||
|
it('does not call preventDefault if submodule tree url exists', () => {
|
||||||
|
vm = mountComponent(Component, {
|
||||||
|
...props,
|
||||||
|
diffFile: { ...props.diffFile, submodule_tree_url: 'foobar.com' },
|
||||||
|
});
|
||||||
|
|
||||||
|
vm.handleFileNameClick(e);
|
||||||
|
|
||||||
|
expect(e.preventDefault).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not call preventDefault if submodule_link exists', () => {
|
||||||
|
vm = mountComponent(Component, {
|
||||||
|
...props,
|
||||||
|
diffFile: { ...props.diffFile, submodule_link: 'foobar.com' },
|
||||||
|
});
|
||||||
|
vm.handleFileNameClick(e);
|
||||||
|
|
||||||
|
expect(e.preventDefault).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not call preventDefault if discussionPath exists', () => {
|
||||||
|
vm = mountComponent(Component, {
|
||||||
|
...props,
|
||||||
|
discussionPath: 'Foo bar',
|
||||||
|
});
|
||||||
|
|
||||||
|
vm.handleFileNameClick(e);
|
||||||
|
|
||||||
|
expect(e.preventDefault).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('scrolling to diff', () => {
|
||||||
|
let scrollToElement;
|
||||||
|
let el;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
el = document.createElement('div');
|
||||||
|
spyOn(document, 'querySelector').and.returnValue(el);
|
||||||
|
scrollToElement = spyOnDependency(DiffFileHeader, 'scrollToElement');
|
||||||
|
vm = mountComponent(Component, props);
|
||||||
|
|
||||||
|
vm.handleFileNameClick(e);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls scrollToElement with file content', () => {
|
||||||
|
expect(scrollToElement).toHaveBeenCalledWith(el);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('element adds the content id to the window location', () => {
|
||||||
|
expect(window.location.hash).toContain(props.diffFile.file_hash);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls preventDefault when button does not link to other page', () => {
|
||||||
|
expect(e.preventDefault).toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('template', () => {
|
describe('template', () => {
|
||||||
|
|
|
@ -2,6 +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';
|
||||||
|
|
||||||
const PIXEL_TOLERANCE = 0.2;
|
const PIXEL_TOLERANCE = 0.2;
|
||||||
|
|
||||||
|
@ -380,6 +381,38 @@ describe('common_utils', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('contentTop', () => {
|
||||||
|
it('does not add height for fileTitle or compareVersionsHeader if screen is too small', () => {
|
||||||
|
spyOn(BreakpointInstance, 'getBreakpointSize').and.returnValue('sm');
|
||||||
|
|
||||||
|
setFixtures(`
|
||||||
|
<div class="diff-file file-title-flex-parent">
|
||||||
|
blah blah blah
|
||||||
|
</div>
|
||||||
|
<div class="mr-version-controls">
|
||||||
|
more blah blah blah
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
|
||||||
|
expect(commonUtils.contentTop()).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('adds height for fileTitle and compareVersionsHeader screen is large enough', () => {
|
||||||
|
spyOn(BreakpointInstance, 'getBreakpointSize').and.returnValue('lg');
|
||||||
|
|
||||||
|
setFixtures(`
|
||||||
|
<div class="diff-file file-title-flex-parent">
|
||||||
|
blah blah blah
|
||||||
|
</div>
|
||||||
|
<div class="mr-version-controls">
|
||||||
|
more blah blah blah
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
|
||||||
|
expect(commonUtils.contentTop()).toBe(18);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('parseBoolean', () => {
|
describe('parseBoolean', () => {
|
||||||
const { parseBoolean } = commonUtils;
|
const { parseBoolean } = commonUtils;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue