summaryrefslogtreecommitdiffstats
path: root/web_src/js/components/DiffFileTree.vue
blob: 717ba70f7f6fd9c095fa44d45acca3521039238f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<template>
  <div
    v-if="fileTreeIsVisible"
    class="mr-3 mt-3 diff-detail-box"
  >
    <!-- only render the tree if we're visible. in many cases this is something that doesn't change very often -->
    <div class="ui list">
      <DiffFileTreeItem v-for="item in fileTree" :key="item.name" :item="item" />
    </div>
    <div v-if="isIncomplete" id="diff-too-many-files-stats" class="pt-2">
      <span>{{ tooManyFilesMessage }}</span><a :class="['ui', 'basic', 'tiny', 'button', isLoadingNewData === true ? 'disabled' : '']" id="diff-show-more-files-stats" @click.stop="loadMoreData">{{ showMoreMessage }}</a>
    </div>
  </div>
</template>

<script>
import DiffFileTreeItem from './DiffFileTreeItem.vue';
import {doLoadMoreFiles} from '../features/repo-diff.js';

const {pageData} = window.config;
const LOCAL_STORAGE_KEY = 'diff_file_tree_visible';

export default {
  name: 'DiffFileTree',
  components: {DiffFileTreeItem},

  data: () => {
    const fileTreeIsVisible = localStorage.getItem(LOCAL_STORAGE_KEY) === 'true';
    pageData.diffFileInfo.fileTreeIsVisible = fileTreeIsVisible;
    return pageData.diffFileInfo;
  },

  computed: {
    fileTree() {
      const result = [];
      for (const file of this.files) {
        // Split file into directories
        const splits = file.Name.split('/');
        let index = 0;
        let parent = null;
        let isFile = false;
        for (const split of splits) {
          index += 1;
          // reached the end
          if (index === splits.length) {
            isFile = true;
          }
          let newParent = {
            name: split,
            children: [],
            isFile
          };

          if (isFile === true) {
            newParent.file = file;
          }

          if (parent) {
            // check if the folder already exists
            const existingFolder = parent.children.find(
              (x) => x.name === split
            );
            if (existingFolder) {
              newParent = existingFolder;
            } else {
              parent.children.push(newParent);
            }
          } else {
            const existingFolder = result.find((x) => x.name === split);
            if (existingFolder) {
              newParent = existingFolder;
            } else {
              result.push(newParent);
            }
          }
          parent = newParent;
        }
      }
      const mergeChildIfOnlyOneDir = (entries) => {
        for (const entry of entries) {
          if (entry.children) {
            mergeChildIfOnlyOneDir(entry.children);
          }
          if (entry.children.length === 1 && entry.children[0].isFile === false) {
            // Merge it to the parent
            entry.name = `${entry.name}/${entry.children[0].name}`;
            entry.children = entry.children[0].children;
          }
        }
      };
      // Merge folders with just a folder as children in order to
      // reduce the depth of our tree.
      mergeChildIfOnlyOneDir(result);
      return result;
    }
  },

  mounted() {
    // ensure correct buttons when we are mounted to the dom
    this.adjustToggleButton(this.fileTreeIsVisible);
    document.querySelector('.diff-toggle-file-tree-button').addEventListener('click', this.toggleVisibility);
  },
  unmounted() {
    document.querySelector('.diff-toggle-file-tree-button').removeEventListener('click', this.toggleVisibility);
  },
  methods: {
    toggleVisibility() {
      this.updateVisibility(!this.fileTreeIsVisible);
    },
    updateVisibility(visible) {
      this.fileTreeIsVisible = visible;
      localStorage.setItem(LOCAL_STORAGE_KEY, this.fileTreeIsVisible);
      this.adjustToggleButton(this.fileTreeIsVisible);
    },
    adjustToggleButton(visible) {
      const [toShow, toHide] = document.querySelectorAll('.diff-toggle-file-tree-button .icon');
      toShow.classList.toggle('hide', visible);  // hide the toShow icon if the tree is visible
      toHide.classList.toggle('hide', !visible); // similarly

      const diffTree = document.getElementById('diff-file-tree');
      diffTree.classList.toggle('hide', !visible);
    },
    loadMoreData() {
      this.isLoadingNewData = true;
      doLoadMoreFiles(this.link, this.diffEnd, () => {
        this.isLoadingNewData = false;
      });
    }
  },
};
</script>