summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Zallmann <tzallmann@gitlab.com>2018-03-26 14:17:26 +0000
committerTim Zallmann <tzallmann@gitlab.com>2018-03-26 14:17:26 +0000
commite3d1f9574db72d6119b4270eae6b43e7a58c9488 (patch)
tree0e3a5279f3216e6c5a8309b77cb736a798d7f182
parent5d6728e57af9ee7465ed4c5178fcdffe4a4ce286 (diff)
parentae9862355941847fa2fd30fc97763a4745f7dae8 (diff)
downloadgitlab-ce-e3d1f9574db72d6119b4270eae6b43e7a58c9488.tar.gz
Merge branch '_mr-refactor-part-12' into '_mr-refector-review-target'
MR Diffs Refactor Part 12: Diffs static components. See merge request gitlab-org/gitlab-ce!17856
-rw-r--r--app/assets/javascripts/diffs/components/changed_files.vue259
-rw-r--r--app/assets/javascripts/diffs/components/compare_versions.vue38
-rw-r--r--spec/javascripts/diffs/components/changed_files_spec.js69
3 files changed, 366 insertions, 0 deletions
diff --git a/app/assets/javascripts/diffs/components/changed_files.vue b/app/assets/javascripts/diffs/components/changed_files.vue
new file mode 100644
index 00000000000..4bab49bfca5
--- /dev/null
+++ b/app/assets/javascripts/diffs/components/changed_files.vue
@@ -0,0 +1,259 @@
+<script>
+import { mapGetters, mapActions } from 'vuex';
+import Icon from '~/vue_shared/components/icon.vue';
+
+export default {
+ components: {
+ Icon,
+ },
+ props: {
+ diffFiles: {
+ type: Array,
+ required: true,
+ },
+ activeFile: {
+ type: String,
+ required: false,
+ default: '',
+ },
+ },
+ data() {
+ return {
+ searchText: '',
+ isStuck: false,
+ showCurrentDiffTitle: false,
+ };
+ },
+ computed: {
+ ...mapGetters(['isInlineView', 'isParallelView']),
+ sumAddedLines() {
+ return this.sumValues('addedLines');
+ },
+ sumRemovedLines() {
+ return this.sumValues('removedLines');
+ },
+ filteredDiffFiles() {
+ return this.diffFiles.filter(file =>
+ file.filePath.toLowerCase().includes(this.searchText.toLowerCase()),
+ );
+ },
+ stickyClass() {
+ return this.isStuck ? 'is-stuck' : '';
+ },
+ },
+ mounted() {
+ if (
+ typeof CSS === 'undefined' ||
+ !CSS.supports('(position: -webkit-sticky) or (position: sticky)')
+ )
+ return;
+
+ document.addEventListener('scroll', this.handleScroll.bind(this), {
+ passive: true,
+ });
+ },
+ methods: {
+ ...mapActions(['setDiffViewType']),
+ handleScroll() {
+ if (!this.$refs.stickyBar) return;
+
+ const barPosition = this.$refs.stickyBar.offsetTop;
+ const scrollPosition = window.scrollY;
+
+ const top = Math.floor(barPosition - scrollPosition);
+
+ this.isStuck = top < 112;
+ this.showCurrentDiffTitle = top < 0;
+ },
+ sumValues(key) {
+ return this.diffFiles.reduce((total, file) => total + file[key], 0);
+ },
+ fileChangedIcon(diffFile) {
+ if (diffFile.deletedFile) {
+ return 'file-deletion';
+ } else if (diffFile.newFile) {
+ return 'file-addition';
+ }
+ return 'file-modified';
+ },
+ fileChangedClass(diffFile) {
+ if (diffFile.deletedFile) {
+ return 'cred';
+ } else if (diffFile.newFile) {
+ return 'cgreen';
+ }
+
+ return '';
+ },
+ truncatedDiffPath(path) {
+ const maxLength = 60;
+
+ return path.length > maxLength ? `...${path.slice(0, maxLength)}` : path;
+ },
+ },
+};
+</script>
+
+<template>
+ <div
+ v-if="diffFiles.length > 0"
+ ref="stickyBar"
+ class="content-block oneline-block diff-files-changed diff-files-changed-merge-request
+ files-changed js-diff-files-changed"
+ :class="stickyClass"
+ >
+ <div class="files-changed-inner">
+ <div
+ v-show="!showCurrentDiffTitle"
+ class="inline-parallel-buttons hidden-xs hidden-sm"
+ >
+ <a
+ class="hidden-xs btn btn-default"
+ href="/fatihacet/test/merge_requests/5/diffs?w=1&TODO"
+ >
+ {{ __('Hide whitespace changes') }}
+ </a>
+ <div class="btn-group">
+ <a
+ @click.prevent="setDiffViewType()"
+ :class="{ active: isInlineView }"
+ id="inline-diff-btn"
+ class="btn"
+ data-view-type="inline"
+ href="#"
+ >
+ {{ __('Inline') }}
+ </a>
+ <a
+ @click.prevent="setDiffViewType(true)"
+ :class="{ active: isParallelView }"
+ id="parallel-diff-btn"
+ class="btn"
+ data-view-type="parallel"
+ href="#"
+ >
+ {{ __('Side-by-side') }}
+ </a>
+ </div>
+ </div>
+
+ <div class="commit-stat-summary dropdown">
+ Showing
+ <button
+ class="diff-stats-summary-toggler js-diff-stats-dropdown"
+ data-toggle="dropdown"
+ type="button"
+ aria-expanded="false"
+ >
+ <span>
+ {{ n__('%d changed file', '%d changed files', diffFiles.length) }}
+ </span>
+ <icon
+ name="chevron-down"
+ :size="8"
+ />
+ </button>
+ <div class="dropdown-menu diff-file-changes">
+ <div class="dropdown-input">
+ <input
+ v-model="searchText"
+ type="search"
+ class="dropdown-input-field"
+ placeholder="Search files"
+ autocomplete="off"
+ />
+ <i
+ v-if="searchText.length === 0"
+ aria-hidden="true"
+ data-hidden="true"
+ class="fa fa-search dropdown-input-search">
+ </i>
+ <i
+ v-else
+ role="button"
+ aria-hidden="true"
+ data-hidden="true"
+ class="fa fa-times dropdown-input-search"
+ @click="searchText = ''"
+ ></i>
+ </div>
+ <ul>
+ <li
+ v-for="diffFile in filteredDiffFiles"
+ :key="diffFile.name"
+ >
+ <a
+ class="diff-changed-file"
+ :href="`#${diffFile.fileHash}`"
+ :title="diffFile.newPath"
+ >
+ <icon
+ :name="fileChangedIcon(diffFile)"
+ :size="16"
+ :class="fileChangedClass(diffFile)"
+ class="diff-file-changed-icon append-right-8"
+ />
+ <span class="diff-changed-file-content append-right-8">
+ <strong
+ v-if="diffFile.blobName"
+ class="diff-changed-file-name"
+ >
+ {{ diffFile.blobName }}
+ </strong>
+ <strong
+ v-else
+ class="diff-changed-blank-file-name"
+ >
+ {{ s__('Diffs|No file name available') }}
+ </strong>
+ <span class="diff-changed-file-path prepend-top-5">
+ {{ truncatedDiffPath(diffFile.blobPath) }}
+ </span>
+ </span>
+ <span class="diff-changed-stats">
+ <span class="cgreen">
+ +{{ diffFile.addedLines }}
+ </span>
+ <span class="cred">
+ -{{ diffFile.removedLines }}
+ </span>
+ </span>
+ </a>
+ </li>
+
+ <li
+ v-show="filteredDiffFiles.length === 0"
+ class="dropdown-menu-empty-item"
+ >
+ <a href="javascript:void(0)">
+ No files found
+ </a>
+ </li>
+ </ul>
+ </div>
+
+ <span
+ v-show="!isStuck"
+ class="diff-stats-additions-deletions-expanded"
+ id="diff-stats"
+ >
+ with
+ <strong class="cgreen">
+ {{ n__('%d addition', '%d additions', sumAddedLines) }}
+ </strong>
+ and
+ <strong class="cred">
+ {{ n__('%d deletion', '%d deletions', sumRemovedLines) }}
+ </strong>
+ </span>
+
+ <span
+ v-show="activeFile"
+ class="prepend-left-5"
+ >
+ {{ truncatedDiffPath(activeFile) }}
+ </span>
+ </div>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/diffs/components/compare_versions.vue b/app/assets/javascripts/diffs/components/compare_versions.vue
new file mode 100644
index 00000000000..3a1a1251add
--- /dev/null
+++ b/app/assets/javascripts/diffs/components/compare_versions.vue
@@ -0,0 +1,38 @@
+<template>
+ <div class="mr-version-controls">
+ <div class="mr-version-menus-container content-block">
+ Changes between
+ <span class="dropdown inline mr-version-dropdown">
+ <a
+ class="dropdown-toggle btn btn-default"
+ data-toggle="dropdown"
+ aria-expanded="false"
+ >
+ <span>
+ latest version
+ </span>
+ <i
+ aria-hidden="true"
+ data-hidden="true"
+ class="fa fa-caret-down"
+ ></i>
+ </a>
+ </span>
+ and
+ <span class="dropdown inline mr-version-compare-dropdown">
+ <a
+ class="btn btn-default dropdown-toggle"
+ data-toggle="dropdown"
+ aria-expanded="false"
+ >
+ <span class="ref-name">master</span>
+ <i
+ aria-hidden="true"
+ data-hidden="true"
+ class="fa fa-caret-down"
+ ></i>
+ </a>
+ </span>
+ </div>
+ </div>
+</template>
diff --git a/spec/javascripts/diffs/components/changed_files_spec.js b/spec/javascripts/diffs/components/changed_files_spec.js
new file mode 100644
index 00000000000..2510b123886
--- /dev/null
+++ b/spec/javascripts/diffs/components/changed_files_spec.js
@@ -0,0 +1,69 @@
+import Vue from 'vue';
+import { mountComponent } from 'spec/helpers';
+import ChangedFiles from '~/diffs/components/changed_files.vue';
+
+const vueMatchers = {
+ toContainText() {
+ return {
+ compare(vm, text) {
+ const result = {
+ pass: vm.$el.innerText.includes(text),
+ };
+ return result;
+ },
+ };
+ },
+ toRender() {
+ return {
+ compare(vm) {
+ const result = {
+ pass: vm.$el.nodeType !== Node.COMMENT_NODE,
+ };
+ return result;
+ },
+ };
+ },
+};
+
+describe('ChangedFiles', () => {
+ const Component = Vue.extend(ChangedFiles);
+
+ beforeEach(() => {
+ jasmine.addMatchers(vueMatchers);
+ });
+
+ describe('with no changed files', () => {
+ const props = {
+ diffFiles: [],
+ };
+
+ it('does not render', () => {
+ const vm = mountComponent(Component, props);
+
+ expect(vm).not.toRender();
+ });
+ });
+
+ describe('with single file added', () => {
+ let vm;
+ const props = {
+ diffFiles: [{
+ addedLines: 10,
+ removedLines: 20,
+ }],
+ };
+
+ beforeEach(() => {
+ vm = mountComponent(Component, props);
+ });
+
+ it('shows files changes', () => {
+ expect(vm).toContainText('1 changed file');
+ });
+
+ it('shows file additions and deletions', () => {
+ expect(vm).toContainText('10 additions');
+ expect(vm).toContainText('20 deletions');
+ });
+ });
+});