summaryrefslogtreecommitdiff
path: root/app/assets/javascripts/vue_shared/components/markdown/suggestion.vue
blob: 18cba8aab390ff676ee5575beef39f885cd2d484 (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
<script>
import Vue from 'vue';
import { mapGetters, mapActions } from 'vuex';
import suggestionDiff from './suggestion_diff.vue';

// TODO - Add unit tests
export default {
  components: { suggestionDiff },
  props: {
    note: {
      type: Object,
      required: false,
      default: null,
    },
    line: {
      type: Object,
      required: false,
      default: null,
    },
    suggestionHtml: {
      type: String,
      required: true
    },
  },
  computed: {
    ...mapGetters(['getNoteableData']),
    canApply() {
      return Boolean(this.note && this.note.position);
    },
    lineNumber() {
      let lineNumber = '';

      if(this.note && this.note.position) {
        lineNumber =  this.note.position.new_line || this.note.position.old_line;
      } else if(this.line) {
        lineNumber = this.line.new_line || this.line.old_line;;
      }
      return lineNumber;
    }
  },
  mounted() {
    this.renderSuggestions();
  },
  methods: {
    renderSuggestions() {
      const { container } = this.$refs;
      const suggestions = container.getElementsByClassName('suggestion');

      [...suggestions].forEach(suggestionEl => {
         const newLine = this.extractNewLine(suggestionEl);
         container.insertBefore(this.generateDiff(newLine), suggestionEl);
         container.removeChild(suggestionEl);
      });
    },
    extractNewLine(suggestionEl) {
      const newLine = suggestionEl.getElementsByClassName('line');
      const content = (newLine && newLine[0]) ? newLine[0].innerHTML : '';
      const number = this.lineNumber;
      return { content, number };
    },
    generateDiff(newLine) {
      const { canApply } = this;

      return new Vue({
        components: { suggestionDiff },
        data: { newLine, canApply },
        methods: {
          applySuggestion: content => this.applySuggestion(content)
        },
        template: `
          <suggestion-diff
            :new-line="newLine"
            :can-apply="canApply"
            @apply="applySuggestion"/>`,
      }).$mount().$el;
    },
    applySuggestion(content) {
      // see https://docs.gitlab.com/ce/api/repository_files.html
      const position = (this.note && this.note.position) ? this.note.position : {};
      const fileName = position.new_path || position.old_path;
      const commitPayload = this.createCommitPayload(content, fileName);
      console.log('applying suggestion > ', commitPayload, fileName);

      // TODO - Dispatch > Apply suggestion
    },
    createCommitPayload(content, fileName) {
      const { lineNumber } = this;

      return {
        content,
        branch: this.getNoteableData.source_branch,
        commit_message: `Apply suggestion to ${fileName}`, // TODO - make this user-defined?
        from_line: lineNumber,
        to_line: lineNumber,
      };
    },
  },
};
</script>

<template>
  <div>
    <div
      ref="container"
      v-html="suggestionHtml"
    ></div>
  </div>
</template>