summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFatih Acet <acetfatih@gmail.com>2018-03-19 15:46:33 +0300
committerFatih Acet <acetfatih@gmail.com>2018-03-19 15:46:33 +0300
commite0c1a173921b775c467448da5e5dade8a6f9f166 (patch)
tree0e61cdad34c78469fbf4ea319e4afc78d330b75b
parente1739e47c5664c93c66dd58ded59f9d79cd8a426 (diff)
downloadgitlab-ce-_mr-refactor-part-11.tar.gz
MR Diffs Refactor Part 11: Diffs app index and app components._mr-refactor-part-11
-rw-r--r--app/assets/javascripts/diffs/components/app.vue83
-rw-r--r--app/assets/javascripts/diffs/constants.js13
-rw-r--r--app/assets/javascripts/diffs/index.js27
-rw-r--r--app/assets/javascripts/diffs/mixins/diff_content.js76
4 files changed, 199 insertions, 0 deletions
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
new file mode 100644
index 00000000000..fde261a4aa7
--- /dev/null
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -0,0 +1,83 @@
+<script>
+import { mapState, mapActions } from 'vuex';
+import loadingIcon from '../../vue_shared/components/loading_icon.vue';
+import compareVersions from './compare_versions.vue';
+import changedFiles from './changed_files.vue';
+import diffFile from './diff_file.vue';
+
+export default {
+ name: 'DiffsApp',
+ components: {
+ loadingIcon,
+ compareVersions,
+ changedFiles,
+ diffFile,
+ },
+ props: {
+ endpoint: {
+ type: String,
+ required: true,
+ },
+ shouldShow: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ data() {
+ return {
+ activeFile: '',
+ };
+ },
+ computed: {
+ ...mapState({
+ isLoading: state => state.diffs.isLoading,
+ diffFiles: state => state.diffs.diffFiles,
+ }),
+ },
+ mounted() {
+ this.setEndpoint(this.endpoint);
+ this.fetchDiffFiles(); // TODO: @fatihacet Error handling
+ },
+ methods: {
+ ...mapActions(['setEndpoint', 'fetchDiffFiles']),
+ setActive(filePath) {
+ this.activeFile = filePath;
+ },
+ unsetActive(filePath) {
+ if (this.activeFile === filePath) {
+ this.activeFile = '';
+ }
+ },
+ },
+};
+</script>
+
+<template>
+ <div v-if="shouldShow">
+ <loading-icon
+ v-if="isLoading"
+ size="3"
+ />
+ <div
+ v-else
+ id="diffs"
+ class="diffs tab-pane"
+ >
+ <compare-versions />
+ <changed-files
+ :diff-files="diffFiles"
+ :active-file="activeFile"
+ />
+ <div class="files">
+ <diff-file
+ @setActive="setActive(file.filePath)"
+ @unsetActive="unsetActive(file.filePath)"
+ v-for="file in diffFiles"
+ :key="file.newPath"
+ :file="file"
+ />
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/diffs/constants.js b/app/assets/javascripts/diffs/constants.js
new file mode 100644
index 00000000000..fa8cccbc46c
--- /dev/null
+++ b/app/assets/javascripts/diffs/constants.js
@@ -0,0 +1,13 @@
+export const INLINE_DIFF_VIEW_TYPE = 'inline';
+export const PARALLEL_DIFF_VIEW_TYPE = 'parallel';
+export const MATCH_LINE_TYPE = 'match';
+export const DIFF_VIEW_COOKIE_NAME = 'diff_view';
+export const EMPTY_CELL_TYPE = 'empty-cell';
+export const LINE_HOVER_CLASS_NAME = 'is-over';
+export const COMMENT_FORM_TYPE = 'commentForm';
+export const LINE_POSITION_LEFT = 'left';
+export const LINE_POSITION_RIGHT = 'right';
+export const TEXT_DIFF_POSITION_TYPE = 'text';
+export const DIFF_NOTE_TYPE = 'DiffNote';
+export const NEW_LINE_TYPE = 'new';
+export const OLD_LINE_TYPE = 'old';
diff --git a/app/assets/javascripts/diffs/index.js b/app/assets/javascripts/diffs/index.js
new file mode 100644
index 00000000000..f0038091aa5
--- /dev/null
+++ b/app/assets/javascripts/diffs/index.js
@@ -0,0 +1,27 @@
+import Vue from 'vue';
+import diffsApp from './components/app.vue';
+
+document.addEventListener(
+ 'DOMContentLoaded',
+ () =>
+ new Vue({
+ el: '#js-diffs-app',
+ components: {
+ diffsApp,
+ },
+ data() {
+ const dataset = document.querySelector(this.$options.el).dataset;
+
+ return {
+ endpoint: dataset.path,
+ };
+ },
+ render(createElement) {
+ return createElement('diffs-app', {
+ props: {
+ endpoint: this.endpoint,
+ },
+ });
+ },
+ }),
+);
diff --git a/app/assets/javascripts/diffs/mixins/diff_content.js b/app/assets/javascripts/diffs/mixins/diff_content.js
new file mode 100644
index 00000000000..11db6a10a3e
--- /dev/null
+++ b/app/assets/javascripts/diffs/mixins/diff_content.js
@@ -0,0 +1,76 @@
+import { mapGetters, mapActions } from 'vuex';
+import diffDiscussions from '../components/diff_discussions.vue';
+import diffLineGutterContent from '../components/diff_line_gutter_content.vue';
+import diffLineNoteForm from '../components/diff_line_note_form.vue';
+
+export default {
+ props: {
+ diffFile: {
+ type: Object,
+ required: true,
+ },
+ diffLines: {
+ type: Array,
+ required: true,
+ },
+ },
+ data() {
+ return {
+ hoveredLineCode: undefined,
+ hoveredSection: undefined,
+ };
+ },
+ components: {
+ diffDiscussions,
+ diffLineNoteForm,
+ diffLineGutterContent,
+ },
+ computed: {
+ ...mapGetters(['discussionsByLineCode']),
+ userColorScheme() {
+ return window.gon.user_color_scheme;
+ },
+ normalizedDiffLines() {
+ return this.diffLines.map(line => {
+ if (line.richText) {
+ return this.trimFirstChar(line);
+ }
+
+ if (line.left) {
+ Object.assign(line, { left: this.trimFirstChar(line.left) });
+ }
+
+ if (line.right) {
+ Object.assign(line, { right: this.trimFirstChar(line.right) });
+ }
+
+ return line;
+ });
+ },
+ },
+ methods: {
+ ...mapActions(['showCommentForm', 'cancelCommentForm']),
+ trimFirstChar(line) {
+ if (!line.richText) {
+ return line;
+ }
+
+ const firstChar = line.richText.charAt(0);
+
+ if (firstChar === ' ' || firstChar === '+' || firstChar === '-') {
+ Object.assign(line, {
+ richText: line.richText.substring(1),
+ });
+ }
+
+ return line;
+ },
+ handleShowCommentForm({ lineCode, linePosition }) {
+ this.showCommentForm({
+ diffLines: this.diffLines,
+ lineCode,
+ linePosition,
+ });
+ },
+ },
+};