debian-mirror-gitlab/app/assets/javascripts/diffs/components/app.vue

428 lines
12 KiB
Vue
Raw Normal View History

2018-11-08 19:23:39 +05:30
<script>
import { mapState, mapGetters, mapActions } from 'vuex';
2020-01-01 13:55:28 +05:30
import { GlLoadingIcon } from '@gitlab/ui';
import Mousetrap from 'mousetrap';
2018-11-08 19:23:39 +05:30
import { __ } from '~/locale';
import createFlash from '~/flash';
2019-07-07 11:18:12 +05:30
import PanelResizer from '~/vue_shared/components/panel_resizer.vue';
2020-01-01 13:55:28 +05:30
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
2020-03-09 13:42:32 +05:30
import { isSingleViewStyle } from '~/helpers/diffs_helper';
2018-11-08 19:23:39 +05:30
import eventHub from '../../notes/event_hub';
import CompareVersions from './compare_versions.vue';
import DiffFile from './diff_file.vue';
import NoChanges from './no_changes.vue';
import HiddenFilesWarning from './hidden_files_warning.vue';
2018-12-05 23:21:45 +05:30
import CommitWidget from './commit_widget.vue';
import TreeList from './tree_list.vue';
2019-07-07 11:18:12 +05:30
import {
TREE_LIST_WIDTH_STORAGE_KEY,
INITIAL_TREE_WIDTH,
MIN_TREE_WIDTH,
MAX_TREE_WIDTH,
TREE_HIDE_STATS_WIDTH,
MR_TREE_SHOW_KEY,
CENTERED_LIMITED_CONTAINER_CLASSES,
} from '../constants';
2018-11-08 19:23:39 +05:30
export default {
name: 'DiffsApp',
components: {
CompareVersions,
DiffFile,
NoChanges,
HiddenFilesWarning,
2018-12-05 23:21:45 +05:30
CommitWidget,
TreeList,
2018-12-13 13:39:08 +05:30
GlLoadingIcon,
2019-07-07 11:18:12 +05:30
PanelResizer,
2018-11-08 19:23:39 +05:30
},
2020-01-01 13:55:28 +05:30
mixins: [glFeatureFlagsMixin()],
2018-11-08 19:23:39 +05:30
props: {
endpoint: {
type: String,
required: true,
},
2020-01-01 13:55:28 +05:30
endpointMetadata: {
type: String,
required: true,
},
endpointBatch: {
type: String,
required: true,
},
2020-04-08 14:13:33 +05:30
endpointCoverage: {
type: String,
required: false,
default: '',
},
2018-11-08 19:23:39 +05:30
projectPath: {
type: String,
required: true,
},
shouldShow: {
type: Boolean,
required: false,
default: false,
},
currentUser: {
type: Object,
required: true,
},
2019-02-15 15:39:39 +05:30
helpPagePath: {
type: String,
required: false,
default: '',
},
changesEmptyStateIllustration: {
type: String,
required: false,
default: '',
},
2019-07-07 11:18:12 +05:30
isFluidLayout: {
type: Boolean,
required: false,
default: false,
},
2019-09-04 21:01:54 +05:30
dismissEndpoint: {
type: String,
required: false,
default: '',
},
showSuggestPopover: {
type: Boolean,
required: false,
default: false,
},
2018-11-08 19:23:39 +05:30
},
2018-12-13 13:39:08 +05:30
data() {
2019-07-07 11:18:12 +05:30
const treeWidth =
parseInt(localStorage.getItem(TREE_LIST_WIDTH_STORAGE_KEY), 10) || INITIAL_TREE_WIDTH;
2018-12-13 13:39:08 +05:30
return {
2019-07-07 11:18:12 +05:30
treeWidth,
2020-03-09 13:42:32 +05:30
diffFilesLength: 0,
2018-12-13 13:39:08 +05:30
};
},
2018-11-08 19:23:39 +05:30
computed: {
...mapState({
isLoading: state => state.diffs.isLoading,
2020-01-01 13:55:28 +05:30
isBatchLoading: state => state.diffs.isBatchLoading,
2018-11-08 19:23:39 +05:30
diffFiles: state => state.diffs.diffFiles,
diffViewType: state => state.diffs.diffViewType,
mergeRequestDiffs: state => state.diffs.mergeRequestDiffs,
mergeRequestDiff: state => state.diffs.mergeRequestDiff,
commit: state => state.diffs.commit,
targetBranchName: state => state.diffs.targetBranchName,
renderOverflowWarning: state => state.diffs.renderOverflowWarning,
numTotalFiles: state => state.diffs.realSize,
numVisibleFiles: state => state.diffs.size,
plainDiffPath: state => state.diffs.plainDiffPath,
emailPatchPath: state => state.diffs.emailPatchPath,
2020-03-09 13:42:32 +05:30
retrievingBatches: state => state.diffs.retrievingBatches,
2018-11-08 19:23:39 +05:30
}),
2019-02-15 15:39:39 +05:30
...mapState('diffs', ['showTreeList', 'isLoading', 'startVersion']),
2019-07-07 11:18:12 +05:30
...mapGetters('diffs', ['isParallelView', 'currentDiffIndex']),
2018-12-13 13:39:08 +05:30
...mapGetters(['isNotesFetched', 'getNoteableData']),
2018-11-08 19:23:39 +05:30
targetBranch() {
return {
branchName: this.targetBranchName,
versionIndex: -1,
path: '',
};
},
canCurrentUserFork() {
2019-02-15 15:39:39 +05:30
return this.currentUser.can_fork === true && this.currentUser.can_create_merge_request;
2018-11-08 19:23:39 +05:30
},
2018-12-05 23:21:45 +05:30
showCompareVersions() {
return this.mergeRequestDiffs && this.mergeRequestDiff;
},
2019-02-15 15:39:39 +05:30
renderDiffFiles() {
return (
this.diffFiles.length > 0 ||
(this.startVersion &&
this.startVersion.version_index === this.mergeRequestDiff.version_index)
);
},
2019-07-07 11:18:12 +05:30
hideFileStats() {
return this.treeWidth <= TREE_HIDE_STATS_WIDTH;
},
isLimitedContainer() {
return !this.showTreeList && !this.isParallelView && !this.isFluidLayout;
},
2018-11-08 19:23:39 +05:30
},
watch: {
diffViewType() {
2020-03-09 13:42:32 +05:30
if (this.needsReload() || this.needsFirstLoad()) {
this.refetchDiffData();
}
2018-11-08 19:23:39 +05:30
this.adjustView();
},
shouldShow() {
// When the shouldShow property changed to true, the route is rendered for the first time
// and if we have the isLoading as true this means we didn't fetch the data
if (this.isLoading) {
this.fetchData();
}
this.adjustView();
},
2018-12-05 23:21:45 +05:30
isLoading: 'adjustView',
showTreeList: 'adjustView',
2018-11-08 19:23:39 +05:30
},
mounted() {
2019-09-04 21:01:54 +05:30
this.setBaseConfig({
endpoint: this.endpoint,
2020-01-01 13:55:28 +05:30
endpointMetadata: this.endpointMetadata,
endpointBatch: this.endpointBatch,
2020-04-08 14:13:33 +05:30
endpointCoverage: this.endpointCoverage,
2019-09-04 21:01:54 +05:30
projectPath: this.projectPath,
dismissEndpoint: this.dismissEndpoint,
showSuggestPopover: this.showSuggestPopover,
2020-01-01 13:55:28 +05:30
useSingleDiffStyle: this.glFeatures.singleMrDiffView,
2019-09-04 21:01:54 +05:30
});
2018-11-08 19:23:39 +05:30
if (this.shouldShow) {
this.fetchData();
}
2019-02-15 15:39:39 +05:30
const id = window && window.location && window.location.hash;
if (id) {
this.setHighlightedRow(id.slice(1));
}
2018-11-08 19:23:39 +05:30
},
created() {
this.adjustView();
2019-03-02 22:35:43 +05:30
eventHub.$once('fetchDiffData', this.fetchData);
2019-09-04 21:01:54 +05:30
eventHub.$on('refetchDiffData', this.refetchDiffData);
2019-07-07 11:18:12 +05:30
this.CENTERED_LIMITED_CONTAINER_CLASSES = CENTERED_LIMITED_CONTAINER_CLASSES;
2020-03-09 13:42:32 +05:30
this.unwatchDiscussions = this.$watch(
() => `${this.diffFiles.length}:${this.$store.state.notes.discussions.length}`,
() => this.setDiscussions(),
);
this.unwatchRetrievingBatches = this.$watch(
() => `${this.retrievingBatches}:${this.$store.state.notes.discussions.length}`,
() => {
if (!this.retrievingBatches && this.$store.state.notes.discussions.length) {
this.unwatchDiscussions();
this.unwatchRetrievingBatches();
}
},
);
2019-03-02 22:35:43 +05:30
},
beforeDestroy() {
eventHub.$off('fetchDiffData', this.fetchData);
2019-09-04 21:01:54 +05:30
eventHub.$off('refetchDiffData', this.refetchDiffData);
2019-07-07 11:18:12 +05:30
this.removeEventListeners();
2018-11-08 19:23:39 +05:30
},
methods: {
2019-02-15 15:39:39 +05:30
...mapActions(['startTaskList']),
2018-11-20 20:47:30 +05:30
...mapActions('diffs', [
'setBaseConfig',
'fetchDiffFiles',
2020-01-01 13:55:28 +05:30
'fetchDiffFilesMeta',
'fetchDiffFilesBatch',
2020-04-08 14:13:33 +05:30
'fetchCoverageFiles',
2018-11-20 20:47:30 +05:30
'startRenderDiffsQueue',
'assignDiscussionsToDiff',
2019-02-15 15:39:39 +05:30
'setHighlightedRow',
2019-07-07 11:18:12 +05:30
'cacheTreeListWidth',
'scrollToFile',
'toggleShowTreeList',
2018-11-20 20:47:30 +05:30
]),
2019-09-04 21:01:54 +05:30
refetchDiffData() {
this.fetchData(false);
},
2020-01-01 13:55:28 +05:30
startDiffRendering() {
requestIdleCallback(
() => {
this.startRenderDiffsQueue();
},
{ timeout: 1000 },
);
},
2020-03-09 13:42:32 +05:30
needsReload() {
return (
this.glFeatures.singleMrDiffView &&
this.diffFiles.length &&
isSingleViewStyle(this.diffFiles[0])
);
},
needsFirstLoad() {
return this.glFeatures.singleMrDiffView && !this.diffFiles.length;
},
2019-09-04 21:01:54 +05:30
fetchData(toggleTree = true) {
2020-01-01 13:55:28 +05:30
if (this.glFeatures.diffsBatchLoad) {
this.fetchDiffFilesMeta()
2020-03-09 13:42:32 +05:30
.then(({ real_size }) => {
this.diffFilesLength = parseInt(real_size, 10);
2020-01-01 13:55:28 +05:30
if (toggleTree) this.hideTreeListIfJustOneFile();
2019-07-07 11:18:12 +05:30
2020-01-01 13:55:28 +05:30
this.startDiffRendering();
})
.catch(() => {
createFlash(__('Something went wrong on our end. Please try again!'));
});
this.fetchDiffFilesBatch()
2020-03-09 13:42:32 +05:30
.then(() => {
// Guarantee the discussions are assigned after the batch finishes.
// Just watching the length of the discussions or the diff files
// isn't enough, because with split diff loading, neither will
// change when loading the other half of the diff files.
this.setDiscussions();
})
2020-01-01 13:55:28 +05:30
.then(() => this.startDiffRendering())
.catch(() => {
createFlash(__('Something went wrong on our end. Please try again!'));
});
} else {
this.fetchDiffFiles()
2020-03-09 13:42:32 +05:30
.then(({ real_size }) => {
this.diffFilesLength = parseInt(real_size, 10);
2020-01-01 13:55:28 +05:30
if (toggleTree) {
this.hideTreeListIfJustOneFile();
}
requestIdleCallback(
() => {
2020-03-09 13:42:32 +05:30
this.setDiscussions();
2020-01-01 13:55:28 +05:30
this.startRenderDiffsQueue();
},
{ timeout: 1000 },
);
})
.catch(() => {
createFlash(__('Something went wrong on our end. Please try again!'));
});
}
2018-11-08 19:23:39 +05:30
2020-04-08 14:13:33 +05:30
if (this.endpointCoverage) {
this.fetchCoverageFiles();
}
2018-11-08 19:23:39 +05:30
if (!this.isNotesFetched) {
eventHub.$emit('fetchNotesData');
}
},
2018-11-20 20:47:30 +05:30
setDiscussions() {
2020-03-09 13:42:32 +05:30
requestIdleCallback(
() =>
this.assignDiscussionsToDiff()
.then(this.$nextTick)
.then(this.startTaskList),
{ timeout: 1000 },
);
2018-11-20 20:47:30 +05:30
},
2018-11-08 19:23:39 +05:30
adjustView() {
2018-12-05 23:21:45 +05:30
if (this.shouldShow) {
this.$nextTick(() => {
2019-07-07 11:18:12 +05:30
this.setEventListeners();
2018-12-05 23:21:45 +05:30
});
2019-07-07 11:18:12 +05:30
} else {
this.removeEventListeners();
}
},
setEventListeners() {
Mousetrap.bind(['[', 'k', ']', 'j'], (e, combo) => {
switch (combo) {
case '[':
case 'k':
this.jumpToFile(-1);
break;
case ']':
case 'j':
this.jumpToFile(+1);
break;
default:
break;
}
});
},
removeEventListeners() {
Mousetrap.unbind(['[', 'k', ']', 'j']);
},
jumpToFile(step) {
const targetIndex = this.currentDiffIndex + step;
if (targetIndex >= 0 && targetIndex < this.diffFiles.length) {
this.scrollToFile(this.diffFiles[targetIndex].file_path);
}
},
hideTreeListIfJustOneFile() {
const storedTreeShow = localStorage.getItem(MR_TREE_SHOW_KEY);
if ((storedTreeShow === null && this.diffFiles.length <= 1) || storedTreeShow === 'false') {
this.toggleShowTreeList(false);
2018-11-08 19:23:39 +05:30
}
},
},
2019-07-07 11:18:12 +05:30
minTreeWidth: MIN_TREE_WIDTH,
maxTreeWidth: MAX_TREE_WIDTH,
2018-11-08 19:23:39 +05:30
};
</script>
<template>
<div v-show="shouldShow">
2020-03-09 13:42:32 +05:30
<div v-if="isLoading" class="loading"><gl-loading-icon size="lg" /></div>
2019-02-15 15:39:39 +05:30
<div v-else id="diffs" :class="{ active: shouldShow }" class="diffs tab-pane">
2018-11-08 19:23:39 +05:30
<compare-versions
:merge-request-diffs="mergeRequestDiffs"
:merge-request-diff="mergeRequestDiff"
:target-branch="targetBranch"
2019-07-07 11:18:12 +05:30
:is-limited-container="isLimitedContainer"
2020-03-09 13:42:32 +05:30
:diff-files-length="diffFilesLength"
2018-11-08 19:23:39 +05:30
/>
<hidden-files-warning
v-if="renderOverflowWarning"
:visible="numVisibleFiles"
:total="numTotalFiles"
:plain-diff-path="plainDiffPath"
:email-patch-path="emailPatchPath"
/>
2018-12-13 13:39:08 +05:30
<div
:data-can-create-note="getNoteableData.current_user.can_create_note"
2020-03-09 13:42:32 +05:30
class="files d-flex"
2018-12-13 13:39:08 +05:30
>
2019-07-07 11:18:12 +05:30
<div
v-show="showTreeList"
:style="{ width: `${treeWidth}px` }"
2019-12-04 20:38:33 +05:30
class="diff-tree-list js-diff-tree-list mr-3"
2019-07-07 11:18:12 +05:30
>
<panel-resizer
:size.sync="treeWidth"
:start-size="treeWidth"
:min-size="$options.minTreeWidth"
:max-size="$options.maxTreeWidth"
side="right"
@resize-end="cacheTreeListWidth"
/>
<tree-list :hide-file-stats="hideFileStats" />
</div>
<div
class="diff-files-holder"
:class="{
[CENTERED_LIMITED_CONTAINER_CLASSES]: isLimitedContainer,
}"
>
2019-02-15 15:39:39 +05:30
<commit-widget v-if="commit" :commit="commit" />
2020-04-08 14:13:33 +05:30
<div v-if="isBatchLoading" class="loading"><gl-loading-icon size="lg" /></div>
2020-01-01 13:55:28 +05:30
<template v-else-if="renderDiffFiles">
2019-02-15 15:39:39 +05:30
<diff-file
v-for="file in diffFiles"
:key="file.newPath"
:file="file"
:help-page-path="helpPagePath"
:can-current-user-fork="canCurrentUserFork"
/>
</template>
<no-changes v-else :changes-empty-state-illustration="changesEmptyStateIllustration" />
2018-12-05 23:21:45 +05:30
</div>
2018-11-08 19:23:39 +05:30
</div>
</div>
</div>
</template>