Commit c206d15b authored by Mike Greiling's avatar Mike Greiling

Merge branch 'tz-mr-incremental-rendering' into 'master'

MR Page incremental rendering

See merge request gitlab-org/gitlab-ce!21063
parents d47f17a2 baa1d40c
...@@ -114,9 +114,13 @@ export default { ...@@ -114,9 +114,13 @@ export default {
this.adjustView(); this.adjustView();
}, },
methods: { methods: {
...mapActions('diffs', ['setBaseConfig', 'fetchDiffFiles']), ...mapActions('diffs', ['setBaseConfig', 'fetchDiffFiles', 'startRenderDiffsQueue']),
fetchData() { fetchData() {
this.fetchDiffFiles().catch(() => { this.fetchDiffFiles()
.then(() => {
requestIdleCallback(this.startRenderDiffsQueue, { timeout: 1000 });
})
.catch(() => {
createFlash(__('Something went wrong on our end. Please try again!')); createFlash(__('Something went wrong on our end. Please try again!'));
}); });
......
...@@ -46,16 +46,25 @@ export default { ...@@ -46,16 +46,25 @@ export default {
showExpandMessage() { showExpandMessage() {
return this.isCollapsed && !this.isLoadingCollapsedDiff && !this.file.tooLarge; return this.isCollapsed && !this.isLoadingCollapsedDiff && !this.file.tooLarge;
}, },
showLoadingIcon() {
return this.isLoadingCollapsedDiff || (!this.file.renderIt && !this.isCollapsed);
},
}, },
methods: { methods: {
...mapActions('diffs', ['loadCollapsedDiff']), ...mapActions('diffs', ['loadCollapsedDiff']),
handleToggle() { handleToggle() {
const { collapsed, highlightedDiffLines, parallelDiffLines } = this.file; const { collapsed, highlightedDiffLines, parallelDiffLines } = this.file;
if (collapsed && !highlightedDiffLines && !parallelDiffLines.length) { if (
collapsed &&
!highlightedDiffLines &&
parallelDiffLines !== undefined &&
!parallelDiffLines.length
) {
this.handleLoadCollapsedDiff(); this.handleLoadCollapsedDiff();
} else { } else {
this.file.collapsed = !this.file.collapsed; this.file.collapsed = !this.file.collapsed;
this.file.renderIt = true;
} }
}, },
handleLoadCollapsedDiff() { handleLoadCollapsedDiff() {
...@@ -65,6 +74,7 @@ export default { ...@@ -65,6 +74,7 @@ export default {
.then(() => { .then(() => {
this.isLoadingCollapsedDiff = false; this.isLoadingCollapsedDiff = false;
this.file.collapsed = false; this.file.collapsed = false;
this.file.renderIt = true;
}) })
.catch(() => { .catch(() => {
this.isLoadingCollapsedDiff = false; this.isLoadingCollapsedDiff = false;
...@@ -121,12 +131,12 @@ export default { ...@@ -121,12 +131,12 @@ export default {
</div> </div>
<diff-content <diff-content
v-if="!isCollapsed" v-if="!isCollapsed && file.renderIt"
:class="{ hidden: isCollapsed || file.tooLarge }" :class="{ hidden: isCollapsed || file.tooLarge }"
:diff-file="file" :diff-file="file"
/> />
<loading-icon <loading-icon
v-if="isLoadingCollapsedDiff" v-else-if="showLoadingIcon"
class="diff-content loading" class="diff-content loading"
/> />
<div <div
......
...@@ -25,3 +25,6 @@ export const CONTEXT_LINE_CLASS_NAME = 'diff-expanded'; ...@@ -25,3 +25,6 @@ export const CONTEXT_LINE_CLASS_NAME = 'diff-expanded';
export const UNFOLD_COUNT = 20; export const UNFOLD_COUNT = 20;
export const COUNT_OF_AVATARS_IN_GUTTER = 3; export const COUNT_OF_AVATARS_IN_GUTTER = 3;
export const LENGTH_OF_AVATAR_TOOLTIP = 17; export const LENGTH_OF_AVATAR_TOOLTIP = 17;
export const LINES_TO_BE_RENDERED_DIRECTLY = 100;
export const MAX_LINES_TO_BE_RENDERED = 2000;
...@@ -29,6 +29,27 @@ export const fetchDiffFiles = ({ state, commit }) => { ...@@ -29,6 +29,27 @@ export const fetchDiffFiles = ({ state, commit }) => {
.then(handleLocationHash); .then(handleLocationHash);
}; };
export const startRenderDiffsQueue = ({ state, commit }) => {
const checkItem = () => {
const nextFile = state.diffFiles.find(
file => !file.renderIt && (!file.collapsed || !file.text),
);
if (nextFile) {
requestAnimationFrame(() => {
commit(types.RENDER_FILE, nextFile);
});
requestIdleCallback(
() => {
checkItem();
},
{ timeout: 1000 },
);
}
};
checkItem();
};
export const setInlineDiffViewType = ({ commit }) => { export const setInlineDiffViewType = ({ commit }) => {
commit(types.SET_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE); commit(types.SET_DIFF_VIEW_TYPE, INLINE_DIFF_VIEW_TYPE);
......
...@@ -8,3 +8,4 @@ export const REMOVE_COMMENT_FORM_LINE = 'REMOVE_COMMENT_FORM_LINE'; ...@@ -8,3 +8,4 @@ export const REMOVE_COMMENT_FORM_LINE = 'REMOVE_COMMENT_FORM_LINE';
export const ADD_CONTEXT_LINES = 'ADD_CONTEXT_LINES'; export const ADD_CONTEXT_LINES = 'ADD_CONTEXT_LINES';
export const ADD_COLLAPSED_DIFFS = 'ADD_COLLAPSED_DIFFS'; export const ADD_COLLAPSED_DIFFS = 'ADD_COLLAPSED_DIFFS';
export const EXPAND_ALL_FILES = 'EXPAND_ALL_FILES'; export const EXPAND_ALL_FILES = 'EXPAND_ALL_FILES';
export const RENDER_FILE = 'RENDER_FILE';
...@@ -2,6 +2,7 @@ import Vue from 'vue'; ...@@ -2,6 +2,7 @@ import Vue from 'vue';
import _ from 'underscore'; import _ from 'underscore';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { findDiffFile, addLineReferences, removeMatchLine, addContextLines } from './utils'; import { findDiffFile, addLineReferences, removeMatchLine, addContextLines } from './utils';
import { LINES_TO_BE_RENDERED_DIRECTLY, MAX_LINES_TO_BE_RENDERED } from '../constants';
import * as types from './mutation_types'; import * as types from './mutation_types';
export default { export default {
...@@ -15,8 +16,48 @@ export default { ...@@ -15,8 +16,48 @@ export default {
}, },
[types.SET_DIFF_DATA](state, data) { [types.SET_DIFF_DATA](state, data) {
const diffData = convertObjectPropsToCamelCase(data, { deep: true });
let showingLines = 0;
const filesLength = diffData.diffFiles.length;
let i;
for (i = 0; i < filesLength; i += 1) {
const file = diffData.diffFiles[i];
if (file.parallelDiffLines) {
const linesLength = file.parallelDiffLines.length;
let u = 0;
for (u = 0; u < linesLength; u += 1) {
const line = file.parallelDiffLines[u];
if (line.left) delete line.left.text;
if (line.right) delete line.right.text;
}
}
if (file.highlightedDiffLines) {
const linesLength = file.highlightedDiffLines.length;
let u;
for (u = 0; u < linesLength; u += 1) {
const line = file.highlightedDiffLines[u];
delete line.text;
}
}
if (file.highlightedDiffLines) {
showingLines += file.parallelDiffLines.length;
}
Object.assign(file, {
renderIt: showingLines < LINES_TO_BE_RENDERED_DIRECTLY,
collapsed: file.text && showingLines > MAX_LINES_TO_BE_RENDERED,
});
}
Object.assign(state, { Object.assign(state, {
...convertObjectPropsToCamelCase(data, { deep: true }), ...diffData,
});
},
[types.RENDER_FILE](state, file) {
Object.assign(file, {
renderIt: true,
}); });
}, },
......
title: Incremental rendering with Vue on merge request page
merge_request: 21063
author:
type: performance
...@@ -28,7 +28,7 @@ describe 'Merge request > User sees MR with deleted source branch', :js do ...@@ -28,7 +28,7 @@ describe 'Merge request > User sees MR with deleted source branch', :js do
click_on 'Changes' click_on 'Changes'
wait_for_requests wait_for_requests
expect(page).to have_selector('.diffs.tab-pane .nothing-here-block') expect(page).to have_selector('.diffs.tab-pane .file-holder')
expect(page).to have_content('Source branch does not exist.') expect(page).to have_content('Source branch does not exist.')
end end
end end
...@@ -22,18 +22,26 @@ describe('DiffFile', () => { ...@@ -22,18 +22,26 @@ describe('DiffFile', () => {
expect(el.id).toEqual(fileHash); expect(el.id).toEqual(fileHash);
expect(el.classList.contains('diff-file')).toEqual(true); expect(el.classList.contains('diff-file')).toEqual(true);
expect(el.querySelectorAll('.diff-content.hidden').length).toEqual(0); expect(el.querySelectorAll('.diff-content.hidden').length).toEqual(0);
expect(el.querySelector('.js-file-title')).toBeDefined(); expect(el.querySelector('.js-file-title')).toBeDefined();
expect(el.querySelector('.file-title-name').innerText.indexOf(filePath) > -1).toEqual(true); expect(el.querySelector('.file-title-name').innerText.indexOf(filePath) > -1).toEqual(true);
expect(el.querySelector('.js-syntax-highlight')).toBeDefined(); expect(el.querySelector('.js-syntax-highlight')).toBeDefined();
expect(vm.file.renderIt).toEqual(false);
vm.file.renderIt = true;
vm.$nextTick(() => {
expect(el.querySelectorAll('.line_content').length > 5).toEqual(true); expect(el.querySelectorAll('.line_content').length > 5).toEqual(true);
}); });
});
describe('collapsed', () => { describe('collapsed', () => {
it('should not have file content', done => { it('should not have file content', done => {
expect(vm.$el.querySelectorAll('.diff-content').length).toEqual(1); expect(vm.$el.querySelectorAll('.diff-content').length).toEqual(1);
expect(vm.file.collapsed).toEqual(false); expect(vm.file.collapsed).toEqual(false);
vm.file.collapsed = true; vm.file.collapsed = true;
vm.file.renderIt = true;
vm.$nextTick(() => { vm.$nextTick(() => {
expect(vm.$el.querySelectorAll('.diff-content').length).toEqual(0); expect(vm.$el.querySelectorAll('.diff-content').length).toEqual(0);
......
...@@ -39,6 +39,7 @@ export default { ...@@ -39,6 +39,7 @@ export default {
viewPath: '/gitlab-org/gitlab-test/blob/spooky-stuff/CHANGELOG', viewPath: '/gitlab-org/gitlab-test/blob/spooky-stuff/CHANGELOG',
replacedViewPath: null, replacedViewPath: null,
collapsed: false, collapsed: false,
renderIt: false,
tooLarge: false, tooLarge: false,
contextLinesPath: contextLinesPath:
'/gitlab-org/gitlab-test/blob/c48ee0d1bf3b30453f5b32250ce03134beaa6d13/CHANGELOG/diff', '/gitlab-org/gitlab-test/blob/c48ee0d1bf3b30453f5b32250ce03134beaa6d13/CHANGELOG/diff',
......
import mutations from '~/diffs/store/mutations'; import mutations from '~/diffs/store/mutations';
import * as types from '~/diffs/store/mutation_types'; import * as types from '~/diffs/store/mutation_types';
import { INLINE_DIFF_VIEW_TYPE } from '~/diffs/constants'; import { INLINE_DIFF_VIEW_TYPE } from '~/diffs/constants';
import diffFileMockData from '../mock_data/diff_file';
describe('DiffsStoreMutations', () => { describe('DiffsStoreMutations', () => {
describe('SET_BASE_CONFIG', () => { describe('SET_BASE_CONFIG', () => {
...@@ -24,6 +25,23 @@ describe('DiffsStoreMutations', () => { ...@@ -24,6 +25,23 @@ describe('DiffsStoreMutations', () => {
}); });
}); });
describe('SET_DIFF_DATA', () => {
it('should set diff data type properly', () => {
const state = {};
const diffMock = {
diff_files: [diffFileMockData],
};
mutations[types.SET_DIFF_DATA](state, diffMock);
const firstLine = state.diffFiles[0].parallelDiffLines[0];
expect(firstLine.right.text).toBeUndefined();
expect(state.diffFiles[0].renderIt).toEqual(true);
expect(state.diffFiles[0].collapsed).toEqual(false);
});
});
describe('SET_DIFF_VIEW_TYPE', () => { describe('SET_DIFF_VIEW_TYPE', () => {
it('should set diff view type properly', () => { it('should set diff view type properly', () => {
const state = {}; const state = {};
......
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