diff --git a/app/assets/javascripts/merge_conflicts/components/diff_file_editor.vue b/app/assets/javascripts/merge_conflicts/components/diff_file_editor.vue
index 2c7c8038af5cdbf154324b183e591db44fef836c..7649c363daa5b1ec6c82fa5e4ea100116cffcf34 100644
--- a/app/assets/javascripts/merge_conflicts/components/diff_file_editor.vue
+++ b/app/assets/javascripts/merge_conflicts/components/diff_file_editor.vue
@@ -1,8 +1,10 @@
 <script>
 import { debounce } from 'lodash';
+import { mapActions } from 'vuex';
 import { deprecatedCreateFlash as flash } from '~/flash';
 import axios from '~/lib/utils/axios_utils';
 import { __ } from '~/locale';
+import { INTERACTIVE_RESOLVE_MODE } from '../constants';
 
 export default {
   props: {
@@ -10,14 +12,6 @@ export default {
       type: Object,
       required: true,
     },
-    onCancelDiscardConfirmation: {
-      type: Function,
-      required: true,
-    },
-    onAcceptDiscardConfirmation: {
-      type: Function,
-      required: true,
-    },
   },
   data() {
     return {
@@ -50,6 +44,7 @@ export default {
     }
   },
   methods: {
+    ...mapActions(['setFileResolveMode', 'setPromptConfirmationState', 'updateFile']),
     loadEditor() {
       const EditorPromise = import(/* webpackChunkName: 'EditorLite' */ '~/editor/editor_lite');
       const DataPromise = axios.get(this.file.content_path);
@@ -82,23 +77,24 @@ export default {
     saveDiffResolution() {
       this.saved = true;
 
-      // This probably be better placed in the data provider
-      /* eslint-disable vue/no-mutating-props */
-      this.file.content = this.editor.getValue();
-      this.file.resolveEditChanged = this.file.content !== this.originalContent;
-      this.file.promptDiscardConfirmation = false;
-      /* eslint-enable vue/no-mutating-props */
+      this.updateFile({
+        ...this.file,
+        content: this.editor.getValue(),
+        resolveEditChanged: this.file.content !== this.originalContent,
+        promptDiscardConfirmation: false,
+      });
     },
     resetEditorContent() {
       if (this.fileLoaded) {
         this.editor.setValue(this.originalContent);
       }
     },
-    cancelDiscardConfirmation(file) {
-      this.onCancelDiscardConfirmation(file);
-    },
     acceptDiscardConfirmation(file) {
-      this.onAcceptDiscardConfirmation(file);
+      this.setPromptConfirmationState({ file, promptDiscardConfirmation: false });
+      this.setFileResolveMode({ file, mode: INTERACTIVE_RESOLVE_MODE });
+    },
+    cancelDiscardConfirmation(file) {
+      this.setPromptConfirmationState({ file, promptDiscardConfirmation: false });
     },
   },
 };
diff --git a/app/assets/javascripts/merge_conflicts/components/inline_conflict_lines.vue b/app/assets/javascripts/merge_conflicts/components/inline_conflict_lines.vue
index 519fd53af1ea39f2ef23eae623769ba755406f05..9721481e6befb63f1d7f66f314c9ae2d867234e8 100644
--- a/app/assets/javascripts/merge_conflicts/components/inline_conflict_lines.vue
+++ b/app/assets/javascripts/merge_conflicts/components/inline_conflict_lines.vue
@@ -1,34 +1,41 @@
 <script>
 import { GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
-import actionsMixin from '../mixins/line_conflict_actions';
+import { mapActions } from 'vuex';
+import syntaxHighlight from '~/syntax_highlight';
+import { SYNTAX_HIGHLIGHT_CLASS } from '../constants';
 import utilsMixin from '../mixins/line_conflict_utils';
 
 export default {
   directives: {
     SafeHtml,
   },
-  mixins: [utilsMixin, actionsMixin],
+  mixins: [utilsMixin],
+  SYNTAX_HIGHLIGHT_CLASS,
   props: {
     file: {
       type: Object,
       required: true,
     },
   },
+  mounted() {
+    syntaxHighlight(document.querySelectorAll(`.${SYNTAX_HIGHLIGHT_CLASS}`));
+  },
+  methods: {
+    ...mapActions(['handleSelected']),
+  },
 };
 </script>
 <template>
-  <table class="diff-wrap-lines code code-commit js-syntax-highlight">
-    <tr
-      v-for="line in file.inlineLines"
-      :key="(line.isHeader ? line.id : line.new_line) + line.richText"
-      class="line_holder diff-inline"
-    >
+  <table :class="['diff-wrap-lines code code-commit', $options.SYNTAX_HIGHLIGHT_CLASS]">
+    <!-- Unfortunately there isn't a good key for these sections -->
+    <!-- eslint-disable vue/require-v-for-key -->
+    <tr v-for="line in file.inlineLines" class="line_holder diff-inline">
       <template v-if="line.isHeader">
         <td :class="lineCssClass(line)" class="diff-line-num header"></td>
         <td :class="lineCssClass(line)" class="diff-line-num header"></td>
         <td :class="lineCssClass(line)" class="line_content header">
           <strong>{{ line.richText }}</strong>
-          <button class="btn" @click="handleSelected(file, line.id, line.section)">
+          <button class="btn" @click="handleSelected({ file, line })">
             {{ line.buttonTitle }}
           </button>
         </td>
diff --git a/app/assets/javascripts/merge_conflicts/components/parallel_conflict_lines.vue b/app/assets/javascripts/merge_conflicts/components/parallel_conflict_lines.vue
index e66f641f70de4ea594edcff47da8dc7806288e5f..7b1d947ccff6dbd1f7f2b876e0b2a22755ac015f 100644
--- a/app/assets/javascripts/merge_conflicts/components/parallel_conflict_lines.vue
+++ b/app/assets/javascripts/merge_conflicts/components/parallel_conflict_lines.vue
@@ -1,32 +1,41 @@
 <script>
 import { GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
-import actionsMixin from '../mixins/line_conflict_actions';
+import { mapActions } from 'vuex';
+import syntaxHighlight from '~/syntax_highlight';
+import { SYNTAX_HIGHLIGHT_CLASS } from '../constants';
 import utilsMixin from '../mixins/line_conflict_utils';
 
 export default {
   directives: {
     SafeHtml,
   },
-  mixins: [utilsMixin, actionsMixin],
+  mixins: [utilsMixin],
+  SYNTAX_HIGHLIGHT_CLASS,
   props: {
     file: {
       type: Object,
       required: true,
     },
   },
+  mounted() {
+    syntaxHighlight(document.querySelectorAll(`.${SYNTAX_HIGHLIGHT_CLASS}`));
+  },
+  methods: {
+    ...mapActions(['handleSelected']),
+  },
 };
 </script>
 <template>
   <!-- Unfortunately there isn't a good key for these sections -->
   <!-- eslint-disable vue/require-v-for-key -->
-  <table class="diff-wrap-lines code js-syntax-highlight">
+  <table :class="['diff-wrap-lines code', $options.SYNTAX_HIGHLIGHT_CLASS]">
     <tr v-for="section in file.parallelLines" class="line_holder parallel">
       <template v-for="line in section">
         <template v-if="line.isHeader">
           <td class="diff-line-num header" :class="lineCssClass(line)"></td>
           <td class="line_content header" :class="lineCssClass(line)">
             <strong>{{ line.richText }}</strong>
-            <button class="btn" @click="handleSelected(file, line.id, line.section)">
+            <button class="btn" @click="handleSelected({ file, line })">
               {{ line.buttonTitle }}
             </button>
           </td>
diff --git a/app/assets/javascripts/merge_conflicts/constants.js b/app/assets/javascripts/merge_conflicts/constants.js
index 6f3ee339e363506067858b34492acebc8c294cdd..dddcc891e81595a0e2d85a096acb78c31489b704 100644
--- a/app/assets/javascripts/merge_conflicts/constants.js
+++ b/app/assets/javascripts/merge_conflicts/constants.js
@@ -13,6 +13,7 @@ export const VIEW_TYPES = {
 export const EDIT_RESOLVE_MODE = 'edit';
 export const INTERACTIVE_RESOLVE_MODE = 'interactive';
 export const DEFAULT_RESOLVE_MODE = INTERACTIVE_RESOLVE_MODE;
+export const SYNTAX_HIGHLIGHT_CLASS = 'js-syntax-highlight';
 
 export const HEAD_HEADER_TEXT = s__('MergeConflict|HEAD//our changes');
 export const ORIGIN_HEADER_TEXT = s__('MergeConflict|origin//their changes');
diff --git a/app/assets/javascripts/merge_conflicts/merge_conflict_resolver_app.vue b/app/assets/javascripts/merge_conflicts/merge_conflict_resolver_app.vue
index 16a7cfb2ba82554013bcfaa53ccf8364e1dcb599..0509cf0afa11face591297b375ebc58d45ebbb73 100644
--- a/app/assets/javascripts/merge_conflicts/merge_conflict_resolver_app.vue
+++ b/app/assets/javascripts/merge_conflicts/merge_conflict_resolver_app.vue
@@ -1,14 +1,15 @@
 <script>
 import { GlSprintf } from '@gitlab/ui';
+import { mapGetters, mapState, mapActions } from 'vuex';
 import { __ } from '~/locale';
 import FileIcon from '~/vue_shared/components/file_icon.vue';
 import DiffFileEditor from './components/diff_file_editor.vue';
 import InlineConflictLines from './components/inline_conflict_lines.vue';
 import ParallelConflictLines from './components/parallel_conflict_lines.vue';
+import { INTERACTIVE_RESOLVE_MODE } from './constants';
 
 /**
- * NOTE: Most of this component is directly using $root, rather than props or a better data store.
- * This is BAD and one shouldn't copy that behavior. Similarly a lot of the classes below should
+ * A lot of the classes below should
  * be replaced with GitLab UI components.
  *
  * We are just doing it temporarily in order to migrate the template from HAML => Vue in an iterative manner
@@ -25,60 +26,88 @@ export default {
     InlineConflictLines,
     ParallelConflictLines,
   },
-  inject: ['mergeRequestPath', 'sourceBranchPath'],
+  inject: ['mergeRequestPath', 'sourceBranchPath', 'resolveConflictsPath'],
   i18n: {
     commitStatSummary: __('Showing %{conflict} between %{sourceBranch} and %{targetBranch}'),
     resolveInfo: __(
       'You can resolve the merge conflict using either the Interactive mode, by choosing %{use_ours} or %{use_theirs} buttons, or by editing the files directly. Commit these changes into %{branch_name}',
     ),
   },
+  computed: {
+    ...mapGetters([
+      'getConflictsCountText',
+      'isReadyToCommit',
+      'getCommitButtonText',
+      'fileTextTypePresent',
+    ]),
+    ...mapState(['isLoading', 'hasError', 'isParallel', 'conflictsData']),
+    commitMessage: {
+      get() {
+        return this.conflictsData.commitMessage;
+      },
+      set(value) {
+        this.updateCommitMessage(value);
+      },
+    },
+  },
+  methods: {
+    ...mapActions([
+      'setViewType',
+      'submitResolvedConflicts',
+      'setFileResolveMode',
+      'setPromptConfirmationState',
+      'updateCommitMessage',
+    ]),
+    onClickResolveModeButton(file, mode) {
+      if (mode === INTERACTIVE_RESOLVE_MODE && file.resolveEditChanged) {
+        this.setPromptConfirmationState({ file, promptDiscardConfirmation: true });
+      } else {
+        this.setFileResolveMode({ file, mode });
+      }
+    },
+  },
 };
 </script>
 <template>
   <div id="conflicts">
-    <div v-if="$root.isLoading" class="loading">
+    <div v-if="isLoading" class="loading">
       <div class="spinner spinner-md"></div>
     </div>
-    <div v-if="$root.hasError" class="nothing-here-block">
-      {{ $root.conflictsData.errorMessage }}
+    <div v-if="hasError" class="nothing-here-block">
+      {{ conflictsData.errorMessage }}
     </div>
-    <template v-if="!$root.isLoading && !$root.hasError">
+    <template v-if="!isLoading && !hasError">
       <div class="content-block oneline-block files-changed">
-        <div v-if="$root.showDiffViewTypeSwitcher" class="inline-parallel-buttons">
+        <div v-if="fileTextTypePresent" class="inline-parallel-buttons">
           <div class="btn-group">
             <button
-              :class="{ active: !$root.isParallel }"
+              :class="{ active: !isParallel }"
               class="btn gl-button"
-              @click="$root.handleViewTypeChange('inline')"
+              @click="setViewType('inline')"
             >
               {{ __('Inline') }}
             </button>
             <button
-              :class="{ active: $root.isParallel }"
+              :class="{ active: isParallel }"
               class="btn gl-button"
-              @click="$root.handleViewTypeChange('parallel')"
+              data-testid="side-by-side"
+              @click="setViewType('parallel')"
             >
               {{ __('Side-by-side') }}
             </button>
           </div>
         </div>
         <div class="js-toggle-container">
-          <div class="commit-stat-summary">
+          <div class="commit-stat-summary" data-testid="conflicts-count">
             <gl-sprintf :message="$options.i18n.commitStatSummary">
               <template #conflict>
-                <strong class="cred">
-                  {{ $root.conflictsCountText }}
-                </strong>
+                <strong class="cred">{{ getConflictsCountText }}</strong>
               </template>
               <template #sourceBranch>
-                <strong class="ref-name">
-                  {{ $root.conflictsData.sourceBranch }}
-                </strong>
+                <strong class="ref-name">{{ conflictsData.sourceBranch }}</strong>
               </template>
               <template #targetBranch>
-                <strong class="ref-name">
-                  {{ $root.conflictsData.targetBranch }}
-                </strong>
+                <strong class="ref-name">{{ conflictsData.targetBranch }}</strong>
               </template>
             </gl-sprintf>
           </div>
@@ -87,12 +116,13 @@ export default {
       <div class="files-wrapper">
         <div class="files">
           <div
-            v-for="file in $root.conflictsData.files"
+            v-for="file in conflictsData.files"
             :key="file.blobPath"
             class="diff-file file-holder conflict"
+            data-testid="files"
           >
             <div class="js-file-title file-title file-title-flex-parent cursor-default">
-              <div class="file-header-content">
+              <div class="file-header-content" data-testid="file-name">
                 <file-icon :file-name="file.filePath" :size="18" css-classes="gl-mr-2" />
                 <strong class="file-title-name">{{ file.filePath }}</strong>
               </div>
@@ -102,7 +132,8 @@ export default {
                     :class="{ active: file.resolveMode === 'interactive' }"
                     class="btn gl-button"
                     type="button"
-                    @click="$root.onClickResolveModeButton(file, 'interactive')"
+                    data-testid="interactive-button"
+                    @click="onClickResolveModeButton(file, 'interactive')"
                   >
                     {{ __('Interactive mode') }}
                   </button>
@@ -110,7 +141,8 @@ export default {
                     :class="{ active: file.resolveMode === 'edit' }"
                     class="btn gl-button"
                     type="button"
-                    @click="$root.onClickResolveModeButton(file, 'edit')"
+                    data-testid="inline-button"
+                    @click="onClickResolveModeButton(file, 'edit')"
                   >
                     {{ __('Edit inline') }}
                   </button>
@@ -118,35 +150,23 @@ export default {
                 <a :href="file.blobPath" class="btn gl-button view-file">
                   <gl-sprintf :message="__('View file @ %{commitSha}')">
                     <template #commitSha>
-                      {{ $root.conflictsData.shortCommitSha }}
+                      {{ conflictsData.shortCommitSha }}
                     </template>
                   </gl-sprintf>
                 </a>
               </div>
             </div>
             <div class="diff-content diff-wrap-lines">
-              <div
-                v-show="
-                  !$root.isParallel && file.resolveMode === 'interactive' && file.type === 'text'
-                "
-                class="file-content"
-              >
-                <inline-conflict-lines :file="file" />
-              </div>
-              <div
-                v-show="
-                  $root.isParallel && file.resolveMode === 'interactive' && file.type === 'text'
-                "
-                class="file-content"
-              >
-                <parallel-conflict-lines :file="file" />
-              </div>
-              <div v-show="file.resolveMode === 'edit' || file.type === 'text-editor'">
-                <diff-file-editor
-                  :file="file"
-                  :on-accept-discard-confirmation="$root.acceptDiscardConfirmation"
-                  :on-cancel-discard-confirmation="$root.cancelDiscardConfirmation"
-                />
+              <template v-if="file.resolveMode === 'interactive' && file.type === 'text'">
+                <div v-if="!isParallel" class="file-content">
+                  <inline-conflict-lines :file="file" />
+                </div>
+                <div v-if="isParallel" class="file-content">
+                  <parallel-conflict-lines :file="file" />
+                </div>
+              </template>
+              <div v-if="file.resolveMode === 'edit' || file.type === 'text-editor'">
+                <diff-file-editor :file="file" />
               </div>
             </div>
           </div>
@@ -169,7 +189,7 @@ export default {
                 </template>
                 <template #branch_name>
                   <a class="ref-name" :href="sourceBranchPath">
-                    {{ $root.conflictsData.sourceBranch }}
+                    {{ conflictsData.sourceBranch }}
                   </a>
                 </template>
               </gl-sprintf>
@@ -183,7 +203,8 @@ export default {
               <div class="max-width-marker"></div>
               <textarea
                 id="commit-message"
-                v-model="$root.conflictsData.commitMessage"
+                v-model="commitMessage"
+                data-testid="commit-message"
                 class="form-control js-commit-message"
                 rows="5"
               ></textarea>
@@ -195,12 +216,12 @@ export default {
             <div class="row">
               <div class="col-6">
                 <button
-                  :disabled="!$root.readyToCommit"
+                  :disabled="!isReadyToCommit"
                   class="btn gl-button btn-success js-submit-button"
                   type="button"
-                  @click="$root.commit()"
+                  @click="submitResolvedConflicts(resolveConflictsPath)"
                 >
-                  <span>{{ $root.commitButtonText }}</span>
+                  <span>{{ getCommitButtonText }}</span>
                 </button>
               </div>
               <div class="col-6 text-right">
diff --git a/app/assets/javascripts/merge_conflicts/merge_conflict_service.js b/app/assets/javascripts/merge_conflicts/merge_conflict_service.js
deleted file mode 100644
index 64d691592225f27a0c840b4c1458c4e25a4c039d..0000000000000000000000000000000000000000
--- a/app/assets/javascripts/merge_conflicts/merge_conflict_service.js
+++ /dev/null
@@ -1,16 +0,0 @@
-import axios from '../lib/utils/axios_utils';
-
-export default class MergeConflictsService {
-  constructor(options) {
-    this.conflictsPath = options.conflictsPath;
-    this.resolveConflictsPath = options.resolveConflictsPath;
-  }
-
-  fetchConflictsData() {
-    return axios.get(this.conflictsPath);
-  }
-
-  submitResolveConflicts(data) {
-    return axios.post(this.resolveConflictsPath, data);
-  }
-}
diff --git a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js b/app/assets/javascripts/merge_conflicts/merge_conflict_store.js
deleted file mode 100644
index fb3444262eacd985db4f6b3062fda1992f659420..0000000000000000000000000000000000000000
--- a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js
+++ /dev/null
@@ -1,432 +0,0 @@
-/* eslint-disable no-param-reassign, babel/camelcase, no-nested-ternary, no-continue */
-
-import $ from 'jquery';
-import Cookies from 'js-cookie';
-import Vue from 'vue';
-import { s__ } from '~/locale';
-
-((global) => {
-  global.mergeConflicts = global.mergeConflicts || {};
-
-  const diffViewType = Cookies.get('diff_view');
-  const HEAD_HEADER_TEXT = s__('MergeConflict|HEAD//our changes');
-  const ORIGIN_HEADER_TEXT = s__('MergeConflict|origin//their changes');
-  const HEAD_BUTTON_TITLE = s__('MergeConflict|Use ours');
-  const ORIGIN_BUTTON_TITLE = s__('MergeConflict|Use theirs');
-  const INTERACTIVE_RESOLVE_MODE = 'interactive';
-  const EDIT_RESOLVE_MODE = 'edit';
-  const DEFAULT_RESOLVE_MODE = INTERACTIVE_RESOLVE_MODE;
-  const VIEW_TYPES = {
-    INLINE: 'inline',
-    PARALLEL: 'parallel',
-  };
-  const CONFLICT_TYPES = {
-    TEXT: 'text',
-    TEXT_EDITOR: 'text-editor',
-  };
-
-  global.mergeConflicts.mergeConflictsStore = {
-    state: {
-      isLoading: true,
-      hasError: false,
-      isSubmitting: false,
-      isParallel: diffViewType === VIEW_TYPES.PARALLEL,
-      diffViewType,
-      conflictsData: {},
-    },
-
-    setConflictsData(data) {
-      this.decorateFiles(data.files);
-
-      this.state.conflictsData = {
-        files: data.files,
-        commitMessage: data.commit_message,
-        sourceBranch: data.source_branch,
-        targetBranch: data.target_branch,
-        shortCommitSha: data.commit_sha.slice(0, 7),
-      };
-    },
-
-    decorateFiles(files) {
-      files.forEach((file) => {
-        file.content = '';
-        file.resolutionData = {};
-        file.promptDiscardConfirmation = false;
-        file.resolveMode = DEFAULT_RESOLVE_MODE;
-        file.filePath = this.getFilePath(file);
-        file.blobPath = file.blob_path;
-
-        if (file.type === CONFLICT_TYPES.TEXT) {
-          file.showEditor = false;
-          file.loadEditor = false;
-
-          this.setInlineLine(file);
-          this.setParallelLine(file);
-        } else if (file.type === CONFLICT_TYPES.TEXT_EDITOR) {
-          file.showEditor = true;
-          file.loadEditor = true;
-        }
-      });
-    },
-
-    setInlineLine(file) {
-      file.inlineLines = [];
-
-      file.sections.forEach((section) => {
-        let currentLineType = 'new';
-        const { conflict, lines, id } = section;
-
-        if (conflict) {
-          file.inlineLines.push(this.getHeadHeaderLine(id));
-        }
-
-        lines.forEach((line) => {
-          const { type } = line;
-
-          if ((type === 'new' || type === 'old') && currentLineType !== type) {
-            currentLineType = type;
-            file.inlineLines.push({ lineType: 'emptyLine', richText: '' });
-          }
-
-          this.decorateLineForInlineView(line, id, conflict);
-          file.inlineLines.push(line);
-        });
-
-        if (conflict) {
-          file.inlineLines.push(this.getOriginHeaderLine(id));
-        }
-      });
-    },
-
-    setParallelLine(file) {
-      file.parallelLines = [];
-      const linesObj = { left: [], right: [] };
-
-      file.sections.forEach((section) => {
-        const { conflict, lines, id } = section;
-
-        if (conflict) {
-          linesObj.left.push(this.getOriginHeaderLine(id));
-          linesObj.right.push(this.getHeadHeaderLine(id));
-        }
-
-        lines.forEach((line) => {
-          const { type } = line;
-
-          if (conflict) {
-            if (type === 'old') {
-              linesObj.left.push(this.getLineForParallelView(line, id, 'conflict'));
-            } else if (type === 'new') {
-              linesObj.right.push(this.getLineForParallelView(line, id, 'conflict', true));
-            }
-          } else {
-            const lineType = type || 'context';
-
-            linesObj.left.push(this.getLineForParallelView(line, id, lineType));
-            linesObj.right.push(this.getLineForParallelView(line, id, lineType, true));
-          }
-        });
-
-        this.checkLineLengths(linesObj);
-      });
-
-      for (let i = 0, len = linesObj.left.length; i < len; i += 1) {
-        file.parallelLines.push([linesObj.right[i], linesObj.left[i]]);
-      }
-    },
-
-    setLoadingState(state) {
-      this.state.isLoading = state;
-    },
-
-    setErrorState(state) {
-      this.state.hasError = state;
-    },
-
-    setFailedRequest(message) {
-      this.state.hasError = true;
-      this.state.conflictsData.errorMessage = message;
-    },
-
-    getConflictsCount() {
-      if (!this.state.conflictsData.files.length) {
-        return 0;
-      }
-
-      const { files } = this.state.conflictsData;
-      let count = 0;
-
-      files.forEach((file) => {
-        if (file.type === CONFLICT_TYPES.TEXT) {
-          file.sections.forEach((section) => {
-            if (section.conflict) {
-              count += 1;
-            }
-          });
-        } else {
-          count += 1;
-        }
-      });
-
-      return count;
-    },
-
-    getConflictsCountText() {
-      const count = this.getConflictsCount();
-      const text = count > 1 ? s__('MergeConflict|conflicts') : s__('MergeConflict|conflict');
-
-      return `${count} ${text}`;
-    },
-
-    setViewType(viewType) {
-      this.state.diffView = viewType;
-      this.state.isParallel = viewType === VIEW_TYPES.PARALLEL;
-
-      Cookies.set('diff_view', viewType);
-    },
-
-    getHeadHeaderLine(id) {
-      return {
-        id,
-        richText: HEAD_HEADER_TEXT,
-        buttonTitle: HEAD_BUTTON_TITLE,
-        type: 'new',
-        section: 'head',
-        isHeader: true,
-        isHead: true,
-        isSelected: false,
-        isUnselected: false,
-      };
-    },
-
-    decorateLineForInlineView(line, id, conflict) {
-      const { type } = line;
-      line.id = id;
-      line.hasConflict = conflict;
-      line.isHead = type === 'new';
-      line.isOrigin = type === 'old';
-      line.hasMatch = type === 'match';
-      line.richText = line.rich_text;
-      line.isSelected = false;
-      line.isUnselected = false;
-    },
-
-    getLineForParallelView(line, id, lineType, isHead) {
-      const { old_line, new_line, rich_text } = line;
-      const hasConflict = lineType === 'conflict';
-
-      return {
-        id,
-        lineType,
-        hasConflict,
-        isHead: hasConflict && isHead,
-        isOrigin: hasConflict && !isHead,
-        hasMatch: lineType === 'match',
-        lineNumber: isHead ? new_line : old_line,
-        section: isHead ? 'head' : 'origin',
-        richText: rich_text,
-        isSelected: false,
-        isUnselected: false,
-      };
-    },
-
-    getOriginHeaderLine(id) {
-      return {
-        id,
-        richText: ORIGIN_HEADER_TEXT,
-        buttonTitle: ORIGIN_BUTTON_TITLE,
-        type: 'old',
-        section: 'origin',
-        isHeader: true,
-        isOrigin: true,
-        isSelected: false,
-        isUnselected: false,
-      };
-    },
-
-    getFilePath(file) {
-      const { old_path, new_path } = file;
-      return old_path === new_path ? new_path : `${old_path} → ${new_path}`;
-    },
-
-    checkLineLengths(linesObj) {
-      const { left, right } = linesObj;
-
-      if (left.length !== right.length) {
-        if (left.length > right.length) {
-          const diff = left.length - right.length;
-          for (let i = 0; i < diff; i += 1) {
-            right.push({ lineType: 'emptyLine', richText: '' });
-          }
-        } else {
-          const diff = right.length - left.length;
-          for (let i = 0; i < diff; i += 1) {
-            left.push({ lineType: 'emptyLine', richText: '' });
-          }
-        }
-      }
-    },
-
-    setPromptConfirmationState(file, state) {
-      file.promptDiscardConfirmation = state;
-    },
-
-    setFileResolveMode(file, mode) {
-      if (mode === INTERACTIVE_RESOLVE_MODE) {
-        file.showEditor = false;
-      } else if (mode === EDIT_RESOLVE_MODE) {
-        // Restore Interactive mode when switching to Edit mode
-        file.showEditor = true;
-        file.loadEditor = true;
-        file.resolutionData = {};
-
-        this.restoreFileLinesState(file);
-      }
-
-      file.resolveMode = mode;
-    },
-
-    restoreFileLinesState(file) {
-      file.inlineLines.forEach((line) => {
-        if (line.hasConflict || line.isHeader) {
-          line.isSelected = false;
-          line.isUnselected = false;
-        }
-      });
-
-      file.parallelLines.forEach((lines) => {
-        const left = lines[0];
-        const right = lines[1];
-        const isLeftMatch = left.hasConflict || left.isHeader;
-        const isRightMatch = right.hasConflict || right.isHeader;
-
-        if (isLeftMatch || isRightMatch) {
-          left.isSelected = false;
-          left.isUnselected = false;
-          right.isSelected = false;
-          right.isUnselected = false;
-        }
-      });
-    },
-
-    isReadyToCommit() {
-      const { files } = this.state.conflictsData;
-      const hasCommitMessage = $.trim(this.state.conflictsData.commitMessage).length;
-      let unresolved = 0;
-
-      for (let i = 0, l = files.length; i < l; i += 1) {
-        const file = files[i];
-
-        if (file.resolveMode === INTERACTIVE_RESOLVE_MODE) {
-          let numberConflicts = 0;
-          const resolvedConflicts = Object.keys(file.resolutionData).length;
-
-          // We only check for conflicts type 'text'
-          // since conflicts `text_editor` can´t be resolved in interactive mode
-          if (file.type === CONFLICT_TYPES.TEXT) {
-            for (let j = 0, k = file.sections.length; j < k; j += 1) {
-              if (file.sections[j].conflict) {
-                numberConflicts += 1;
-              }
-            }
-
-            if (resolvedConflicts !== numberConflicts) {
-              unresolved += 1;
-            }
-          }
-        } else if (file.resolveMode === EDIT_RESOLVE_MODE) {
-          // Unlikely to happen since switching to Edit mode saves content automatically.
-          // Checking anyway in case the save strategy changes in the future
-          if (!file.content) {
-            unresolved += 1;
-            continue;
-          }
-        }
-      }
-
-      return !this.state.isSubmitting && hasCommitMessage && !unresolved;
-    },
-
-    getCommitButtonText() {
-      const initial = s__('MergeConflict|Commit to source branch');
-      const inProgress = s__('MergeConflict|Committing...');
-
-      return this.state ? (this.state.isSubmitting ? inProgress : initial) : initial;
-    },
-
-    getCommitData() {
-      let commitData = {};
-
-      commitData = {
-        commit_message: this.state.conflictsData.commitMessage,
-        files: [],
-      };
-
-      this.state.conflictsData.files.forEach((file) => {
-        const addFile = {
-          old_path: file.old_path,
-          new_path: file.new_path,
-        };
-
-        if (file.type === CONFLICT_TYPES.TEXT) {
-          // Submit only one data for type of editing
-          if (file.resolveMode === INTERACTIVE_RESOLVE_MODE) {
-            addFile.sections = file.resolutionData;
-          } else if (file.resolveMode === EDIT_RESOLVE_MODE) {
-            addFile.content = file.content;
-          }
-        } else if (file.type === CONFLICT_TYPES.TEXT_EDITOR) {
-          addFile.content = file.content;
-        }
-
-        commitData.files.push(addFile);
-      });
-
-      return commitData;
-    },
-
-    handleSelected(file, sectionId, selection) {
-      Vue.set(file.resolutionData, sectionId, selection);
-
-      file.inlineLines.forEach((line) => {
-        if (line.id === sectionId && (line.hasConflict || line.isHeader)) {
-          this.markLine(line, selection);
-        }
-      });
-
-      file.parallelLines.forEach((lines) => {
-        const left = lines[0];
-        const right = lines[1];
-        const hasSameId = right.id === sectionId || left.id === sectionId;
-        const isLeftMatch = left.hasConflict || left.isHeader;
-        const isRightMatch = right.hasConflict || right.isHeader;
-
-        if (hasSameId && (isLeftMatch || isRightMatch)) {
-          this.markLine(left, selection);
-          this.markLine(right, selection);
-        }
-      });
-    },
-
-    markLine(line, selection) {
-      if (selection === 'head' && line.isHead) {
-        line.isSelected = true;
-        line.isUnselected = false;
-      } else if (selection === 'origin' && line.isOrigin) {
-        line.isSelected = true;
-        line.isUnselected = false;
-      } else {
-        line.isSelected = false;
-        line.isUnselected = true;
-      }
-    },
-
-    setSubmitState(state) {
-      this.state.isSubmitting = state;
-    },
-
-    fileTextTypePresent() {
-      return this.state.conflictsData.files.some((f) => f.type === CONFLICT_TYPES.TEXT);
-    },
-  };
-})(window.gl || (window.gl = {}));
diff --git a/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js b/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js
index 4b73dd317cd1e2918c676c3319f57232497ef64f..cf02c6fbd6b03a71703d5890ef6f062c000b2779 100644
--- a/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js
+++ b/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js
@@ -1,100 +1,32 @@
-import $ from 'jquery';
 import Vue from 'vue';
-import { __ } from '~/locale';
-import { deprecatedCreateFlash as createFlash } from '../flash';
 import initIssuableSidebar from '../init_issuable_sidebar';
-import './merge_conflict_store';
-import syntaxHighlight from '../syntax_highlight';
 import MergeConflictsResolverApp from './merge_conflict_resolver_app.vue';
-import MergeConflictsService from './merge_conflict_service';
+import { createStore } from './store';
 
 export default function initMergeConflicts() {
-  const INTERACTIVE_RESOLVE_MODE = 'interactive';
   const conflictsEl = document.querySelector('#conflicts');
-  const { mergeConflictsStore } = gl.mergeConflicts;
-  const mergeConflictsService = new MergeConflictsService({
-    conflictsPath: conflictsEl.dataset.conflictsPath,
-    resolveConflictsPath: conflictsEl.dataset.resolveConflictsPath,
-  });
 
-  const { sourceBranchPath, mergeRequestPath } = conflictsEl.dataset;
+  const {
+    sourceBranchPath,
+    mergeRequestPath,
+    conflictsPath,
+    resolveConflictsPath,
+  } = conflictsEl.dataset;
 
   initIssuableSidebar();
 
+  const store = createStore();
+
   return new Vue({
     el: conflictsEl,
+    store,
     provide: {
       sourceBranchPath,
       mergeRequestPath,
-    },
-    data: mergeConflictsStore.state,
-    computed: {
-      conflictsCountText() {
-        return mergeConflictsStore.getConflictsCountText();
-      },
-      readyToCommit() {
-        return mergeConflictsStore.isReadyToCommit();
-      },
-      commitButtonText() {
-        return mergeConflictsStore.getCommitButtonText();
-      },
-      showDiffViewTypeSwitcher() {
-        return mergeConflictsStore.fileTextTypePresent();
-      },
+      resolveConflictsPath,
     },
     created() {
-      mergeConflictsService
-        .fetchConflictsData()
-        .then(({ data }) => {
-          if (data.type === 'error') {
-            mergeConflictsStore.setFailedRequest(data.message);
-          } else {
-            mergeConflictsStore.setConflictsData(data);
-          }
-
-          mergeConflictsStore.setLoadingState(false);
-
-          this.$nextTick(() => {
-            syntaxHighlight($('.js-syntax-highlight'));
-          });
-        })
-        .catch(() => {
-          mergeConflictsStore.setLoadingState(false);
-          mergeConflictsStore.setFailedRequest();
-        });
-    },
-    methods: {
-      handleViewTypeChange(viewType) {
-        mergeConflictsStore.setViewType(viewType);
-      },
-      onClickResolveModeButton(file, mode) {
-        if (mode === INTERACTIVE_RESOLVE_MODE && file.resolveEditChanged) {
-          mergeConflictsStore.setPromptConfirmationState(file, true);
-          return;
-        }
-
-        mergeConflictsStore.setFileResolveMode(file, mode);
-      },
-      acceptDiscardConfirmation(file) {
-        mergeConflictsStore.setPromptConfirmationState(file, false);
-        mergeConflictsStore.setFileResolveMode(file, INTERACTIVE_RESOLVE_MODE);
-      },
-      cancelDiscardConfirmation(file) {
-        mergeConflictsStore.setPromptConfirmationState(file, false);
-      },
-      commit() {
-        mergeConflictsStore.setSubmitState(true);
-
-        mergeConflictsService
-          .submitResolveConflicts(mergeConflictsStore.getCommitData())
-          .then(({ data }) => {
-            window.location.href = data.redirect_to;
-          })
-          .catch(() => {
-            mergeConflictsStore.setSubmitState(false);
-            createFlash(__('Failed to save merge conflicts resolutions. Please try again!'));
-          });
-      },
+      store.dispatch('fetchConflictsData', conflictsPath);
     },
     render(createElement) {
       return createElement(MergeConflictsResolverApp);
diff --git a/app/assets/javascripts/merge_conflicts/mixins/line_conflict_actions.js b/app/assets/javascripts/merge_conflicts/mixins/line_conflict_actions.js
deleted file mode 100644
index 364ae2b268891c44b86d47a14e0db4779aaaf2d8..0000000000000000000000000000000000000000
--- a/app/assets/javascripts/merge_conflicts/mixins/line_conflict_actions.js
+++ /dev/null
@@ -1,7 +0,0 @@
-export default {
-  methods: {
-    handleSelected(file, sectionId, selection) {
-      gl.mergeConflicts.mergeConflictsStore.handleSelected(file, sectionId, selection);
-    },
-  },
-};
diff --git a/app/assets/javascripts/merge_conflicts/store/actions.js b/app/assets/javascripts/merge_conflicts/store/actions.js
index 8036e90c58c31e04207addac392009858e11e438..df515c4ac1a245f5b52a9843f6fb8c413dd5b343 100644
--- a/app/assets/javascripts/merge_conflicts/store/actions.js
+++ b/app/assets/javascripts/merge_conflicts/store/actions.js
@@ -118,3 +118,8 @@ export const handleSelected = ({ commit, state, getters }, { file, line: { id, s
 
   commit(types.UPDATE_FILE, { file: updated, index });
 };
+
+export const updateFile = ({ commit, getters }, file) => {
+  const index = getters.getFileIndex(file);
+  commit(types.UPDATE_FILE, { file, index });
+};
diff --git a/spec/frontend/merge_conflicts/components/merge_conflict_resolver_app_spec.js b/spec/frontend/merge_conflicts/components/merge_conflict_resolver_app_spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..eaa3b1c5d53279fcc6aaf89de7b26e0d9b586454
--- /dev/null
+++ b/spec/frontend/merge_conflicts/components/merge_conflict_resolver_app_spec.js
@@ -0,0 +1,131 @@
+import { GlSprintf } from '@gitlab/ui';
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import Vuex from 'vuex';
+import InlineConflictLines from '~/merge_conflicts/components/inline_conflict_lines.vue';
+import ParallelConflictLines from '~/merge_conflicts/components/parallel_conflict_lines.vue';
+import component from '~/merge_conflicts/merge_conflict_resolver_app.vue';
+import { createStore } from '~/merge_conflicts/store';
+import { decorateFiles } from '~/merge_conflicts/utils';
+import { conflictsMock } from '../mock_data';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('Merge Conflict Resolver App', () => {
+  let wrapper;
+  let store;
+
+  const decoratedMockFiles = decorateFiles(conflictsMock.files);
+
+  const mountComponent = () => {
+    wrapper = shallowMount(component, {
+      store,
+      stubs: { GlSprintf },
+      provide() {
+        return {
+          mergeRequestPath: 'foo',
+          sourceBranchPath: 'foo',
+          resolveConflictsPath: 'bar',
+        };
+      },
+    });
+  };
+
+  beforeEach(() => {
+    store = createStore();
+    store.commit('SET_LOADING_STATE', false);
+    store.dispatch('setConflictsData', conflictsMock);
+  });
+
+  afterEach(() => {
+    wrapper.destroy();
+  });
+
+  const findConflictsCount = () => wrapper.find('[data-testid="conflicts-count"]');
+  const findFiles = () => wrapper.findAll('[data-testid="files"]');
+  const findFileHeader = (w = wrapper) => w.find('[data-testid="file-name"]');
+  const findFileInteractiveButton = (w = wrapper) => w.find('[data-testid="interactive-button"]');
+  const findFileInlineButton = (w = wrapper) => w.find('[data-testid="inline-button"]');
+  const findSideBySideButton = () => wrapper.find('[data-testid="side-by-side"]');
+  const findInlineConflictLines = (w = wrapper) => w.find(InlineConflictLines);
+  const findParallelConflictLines = (w = wrapper) => w.find(ParallelConflictLines);
+  const findCommitMessageTextarea = () => wrapper.find('[data-testid="commit-message"]');
+
+  it('shows the amount of conflicts', () => {
+    mountComponent();
+
+    const title = findConflictsCount();
+
+    expect(title.exists()).toBe(true);
+    expect(title.text().trim()).toBe('Showing 3 conflicts between test-conflicts and master');
+  });
+
+  describe('files', () => {
+    it('shows one file area for each file', () => {
+      mountComponent();
+
+      expect(findFiles()).toHaveLength(conflictsMock.files.length);
+    });
+
+    it('has the appropriate file header', () => {
+      mountComponent();
+
+      const fileHeader = findFileHeader(findFiles().at(0));
+
+      expect(fileHeader.text()).toBe(decoratedMockFiles[0].filePath);
+    });
+
+    describe('editing', () => {
+      it('interactive mode is the default', () => {
+        mountComponent();
+
+        const interactiveButton = findFileInteractiveButton(findFiles().at(0));
+        const inlineButton = findFileInlineButton(findFiles().at(0));
+
+        expect(interactiveButton.classes('active')).toBe(true);
+        expect(inlineButton.classes('active')).toBe(false);
+      });
+
+      it('clicking inline set inline as default', async () => {
+        mountComponent();
+
+        const inlineButton = findFileInlineButton(findFiles().at(0));
+        expect(inlineButton.classes('active')).toBe(false);
+
+        inlineButton.trigger('click');
+        await wrapper.vm.$nextTick();
+
+        expect(inlineButton.classes('active')).toBe(true);
+      });
+
+      it('inline mode shows a inline-conflict-lines', () => {
+        mountComponent();
+
+        const inlineConflictLinesComponent = findInlineConflictLines(findFiles().at(0));
+
+        expect(inlineConflictLinesComponent.exists()).toBe(true);
+        expect(inlineConflictLinesComponent.props('file')).toEqual(decoratedMockFiles[0]);
+      });
+
+      it('parallel mode shows a parallel-conflict-lines', async () => {
+        mountComponent();
+
+        findSideBySideButton().trigger('click');
+        await wrapper.vm.$nextTick();
+
+        const parallelConflictLinesComponent = findParallelConflictLines(findFiles().at(0));
+
+        expect(parallelConflictLinesComponent.exists()).toBe(true);
+        expect(parallelConflictLinesComponent.props('file')).toEqual(decoratedMockFiles[0]);
+      });
+    });
+  });
+
+  describe('submit form', () => {
+    it('contains a commit message textarea', () => {
+      mountComponent();
+
+      expect(findCommitMessageTextarea().exists()).toBe(true);
+    });
+  });
+});
diff --git a/spec/frontend/merge_conflicts/mock_data.js b/spec/frontend/merge_conflicts/mock_data.js
new file mode 100644
index 0000000000000000000000000000000000000000..8948f2a3c1e5b2c322e6f6602f413ed193c730ba
--- /dev/null
+++ b/spec/frontend/merge_conflicts/mock_data.js
@@ -0,0 +1,340 @@
+export const conflictsMock = {
+  target_branch: 'master',
+  source_branch: 'test-conflicts',
+  commit_sha: '6dbf385a3c7bf01e09b5d2d9e5d72f8fb8c590a3',
+  commit_message:
+    "Merge branch 'master' into 'test-conflicts'\n\n# Conflicts:\n#   .gitlab-ci.yml\n#   README.md",
+  files: [
+    {
+      old_path: '.gitlab-ci.yml',
+      new_path: '.gitlab-ci.yml',
+      blob_icon: 'doc-text',
+      blob_path:
+        '/gitlab-org/gitlab-test/-/blob/6dbf385a3c7bf01e09b5d2d9e5d72f8fb8c590a3/.gitlab-ci.yml',
+      sections: [
+        {
+          conflict: false,
+          lines: [
+            {
+              line_code: null,
+              type: 'match',
+              old_line: null,
+              new_line: null,
+              text: '@@ -7,10 +7,11 @@ upload:',
+              meta_data: { old_pos: 7, new_pos: 7 },
+              rich_text: '@@ -7,10 +7,11 @@ upload:',
+              can_receive_suggestion: true,
+            },
+            {
+              line_code: '587d266bb27a4dc3022bbed44dfa19849df3044c_7_7',
+              type: null,
+              old_line: 7,
+              new_line: 7,
+              text: '  stage: upload',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC7" class="line" lang="yaml"\u003e  \u003cspan class="na"\u003estage\u003c/span\u003e\u003cspan class="pi"\u003e:\u003c/span\u003e \u003cspan class="s"\u003eupload\u003c/span\u003e\u003c/span\u003e\n',
+              can_receive_suggestion: true,
+            },
+            {
+              line_code: '587d266bb27a4dc3022bbed44dfa19849df3044c_8_8',
+              type: null,
+              old_line: 8,
+              new_line: 8,
+              text: '  script:',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC8" class="line" lang="yaml"\u003e  \u003cspan class="na"\u003escript\u003c/span\u003e\u003cspan class="pi"\u003e:\u003c/span\u003e\u003c/span\u003e\n',
+              can_receive_suggestion: true,
+            },
+            {
+              line_code: '587d266bb27a4dc3022bbed44dfa19849df3044c_9_9',
+              type: null,
+              old_line: 9,
+              new_line: 9,
+              text:
+                // eslint-disable-next-line no-template-curly-in-string
+                '    - \'curl --header "JOB-TOKEN: $CI_JOB_TOKEN" --upload-file README.md ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/my_package/0.0.1/file.txt\'',
+              meta_data: null,
+              rich_text:
+                // eslint-disable-next-line no-template-curly-in-string
+                '\u003cspan id="LC9" class="line" lang="yaml"\u003e    \u003cspan class="pi"\u003e-\u003c/span\u003e \u003cspan class="s1"\u003e\'\u003c/span\u003e\u003cspan class="s"\u003ecurl\u003c/span\u003e\u003cspan class="nv"\u003e \u003c/span\u003e\u003cspan class="s"\u003e--header\u003c/span\u003e\u003cspan class="nv"\u003e \u003c/span\u003e\u003cspan class="s"\u003e"JOB-TOKEN:\u003c/span\u003e\u003cspan class="nv"\u003e \u003c/span\u003e\u003cspan class="s"\u003e$CI_JOB_TOKEN"\u003c/span\u003e\u003cspan class="nv"\u003e \u003c/span\u003e\u003cspan class="s"\u003e--upload-file\u003c/span\u003e\u003cspan class="nv"\u003e \u003c/span\u003e\u003cspan class="s"\u003eREADME.md\u003c/span\u003e\u003cspan class="nv"\u003e \u003c/span\u003e\u003cspan class="s"\u003e${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/my_package/0.0.1/file.txt\'\u003c/span\u003e\u003c/span\u003e\n',
+              can_receive_suggestion: true,
+            },
+          ],
+        },
+        {
+          conflict: true,
+          lines: [
+            {
+              line_code: '587d266bb27a4dc3022bbed44dfa19849df3044c_10_10',
+              type: 'new',
+              old_line: null,
+              new_line: 10,
+              text: '# some new comments',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC10" class="line" lang="yaml"\u003e\u003cspan class="c1"\u003e# some new comments\u003c/span\u003e\u003c/span\u003e',
+              can_receive_suggestion: true,
+            },
+            {
+              line_code: '587d266bb27a4dc3022bbed44dfa19849df3044c_10_11',
+              type: 'old',
+              old_line: 10,
+              new_line: null,
+              text: '# a different comment',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC10" class="line" lang="yaml"\u003e\u003cspan class="c1"\u003e# a different comment\u003c/span\u003e\u003c/span\u003e',
+              can_receive_suggestion: false,
+            },
+          ],
+          id: '587d266bb27a4dc3022bbed44dfa19849df3044c_10_10',
+        },
+      ],
+      type: 'text',
+      content_path:
+        '/gitlab-org/gitlab-test/-/merge_requests/2/conflict_for_path?new_path=.gitlab-ci.yml\u0026old_path=.gitlab-ci.yml',
+    },
+    {
+      old_path: 'README.md',
+      new_path: 'README.md',
+      blob_icon: 'doc-text',
+      blob_path:
+        '/gitlab-org/gitlab-test/-/blob/6dbf385a3c7bf01e09b5d2d9e5d72f8fb8c590a3/README.md',
+      sections: [
+        {
+          conflict: false,
+          lines: [
+            {
+              line_code: '8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_1_1',
+              type: null,
+              old_line: 1,
+              new_line: 1,
+              text: '- 1',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC1" class="line" lang="markdown"\u003e\u003cspan class="p"\u003e-\u003c/span\u003e 1\u003c/span\u003e\n',
+              can_receive_suggestion: true,
+            },
+            {
+              line_code: '8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_2_2',
+              type: null,
+              old_line: 2,
+              new_line: 2,
+              text: '- 2',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC2" class="line" lang="markdown"\u003e\u003cspan class="p"\u003e-\u003c/span\u003e 2\u003c/span\u003e\n',
+              can_receive_suggestion: true,
+            },
+            {
+              line_code: '8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_3_3',
+              type: null,
+              old_line: 3,
+              new_line: 3,
+              text: '- 3',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC3" class="line" lang="markdown"\u003e\u003cspan class="p"\u003e-\u003c/span\u003e 3\u003c/span\u003e\n',
+              can_receive_suggestion: true,
+            },
+          ],
+        },
+        {
+          conflict: true,
+          lines: [
+            {
+              line_code: '8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_4_4',
+              type: 'new',
+              old_line: null,
+              new_line: 4,
+              text: '- 4c',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC4" class="line" lang="markdown"\u003e\u003cspan class="p"\u003e-\u003c/span\u003e 4c\u003c/span\u003e\n',
+              can_receive_suggestion: true,
+            },
+            {
+              line_code: '8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_4_5',
+              type: 'old',
+              old_line: 4,
+              new_line: null,
+              text: '- 4b',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC4" class="line" lang="markdown"\u003e\u003cspan class="p"\u003e-\u003c/span\u003e 4b\u003c/span\u003e\n',
+              can_receive_suggestion: false,
+            },
+          ],
+          id: '8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_4_4',
+        },
+        {
+          conflict: false,
+          lines: [
+            {
+              line_code: '8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_5_5',
+              type: null,
+              old_line: 5,
+              new_line: 5,
+              text: '- 5',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC5" class="line" lang="markdown"\u003e\u003cspan class="p"\u003e-\u003c/span\u003e 5\u003c/span\u003e\n',
+              can_receive_suggestion: true,
+            },
+            {
+              line_code: '8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_6_6',
+              type: null,
+              old_line: 6,
+              new_line: 6,
+              text: '- 6',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC6" class="line" lang="markdown"\u003e\u003cspan class="p"\u003e-\u003c/span\u003e 6\u003c/span\u003e\n',
+              can_receive_suggestion: true,
+            },
+            {
+              line_code: '8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_7_7',
+              type: null,
+              old_line: 7,
+              new_line: 7,
+              text: '- 7',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC7" class="line" lang="markdown"\u003e\u003cspan class="p"\u003e-\u003c/span\u003e 7\u003c/span\u003e\n',
+              can_receive_suggestion: true,
+            },
+          ],
+        },
+        {
+          conflict: false,
+          lines: [
+            {
+              line_code: null,
+              type: 'match',
+              old_line: null,
+              new_line: null,
+              text: '@@ -9,15 +9,15 @@',
+              meta_data: { old_pos: 9, new_pos: 9 },
+              rich_text: '@@ -9,15 +9,15 @@',
+              can_receive_suggestion: true,
+            },
+            {
+              line_code: '8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_9_9',
+              type: null,
+              old_line: 9,
+              new_line: 9,
+              text: '- 9',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC9" class="line" lang="markdown"\u003e\u003cspan class="p"\u003e-\u003c/span\u003e 9\u003c/span\u003e\n',
+              can_receive_suggestion: true,
+            },
+            {
+              line_code: '8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_10_10',
+              type: null,
+              old_line: 10,
+              new_line: 10,
+              text: '- 10',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC10" class="line" lang="markdown"\u003e\u003cspan class="p"\u003e-\u003c/span\u003e 10\u003c/span\u003e\n',
+              can_receive_suggestion: true,
+            },
+            {
+              line_code: '8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_11_11',
+              type: null,
+              old_line: 11,
+              new_line: 11,
+              text: '- 11',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC11" class="line" lang="markdown"\u003e\u003cspan class="p"\u003e-\u003c/span\u003e 11\u003c/span\u003e\n',
+              can_receive_suggestion: true,
+            },
+          ],
+        },
+        {
+          conflict: true,
+          lines: [
+            {
+              line_code: '8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_12_12',
+              type: 'new',
+              old_line: null,
+              new_line: 12,
+              text: '- 12c',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC12" class="line" lang="markdown"\u003e\u003cspan class="p"\u003e-\u003c/span\u003e 12c\u003c/span\u003e\n',
+              can_receive_suggestion: true,
+            },
+            {
+              line_code: '8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_12_13',
+              type: 'old',
+              old_line: 12,
+              new_line: null,
+              text: '- 12b',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC12" class="line" lang="markdown"\u003e\u003cspan class="p"\u003e-\u003c/span\u003e 12b\u003c/span\u003e\n',
+              can_receive_suggestion: false,
+            },
+          ],
+          id: '8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_12_12',
+        },
+        {
+          conflict: false,
+          lines: [
+            {
+              line_code: '8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_13_13',
+              type: null,
+              old_line: 13,
+              new_line: 13,
+              text: '- 13',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC13" class="line" lang="markdown"\u003e\u003cspan class="p"\u003e-\u003c/span\u003e 13\u003c/span\u003e\n',
+              can_receive_suggestion: true,
+            },
+            {
+              line_code: '8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_14_14',
+              type: null,
+              old_line: 14,
+              new_line: 14,
+              text: '- 14 ',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC14" class="line" lang="markdown"\u003e\u003cspan class="p"\u003e-\u003c/span\u003e 14 \u003c/span\u003e\n',
+              can_receive_suggestion: true,
+            },
+            {
+              line_code: '8ec9a00bfd09b3190ac6b22251dbb1aa95a0579d_15_15',
+              type: null,
+              old_line: 15,
+              new_line: 15,
+              text: '- 15',
+              meta_data: null,
+              rich_text:
+                '\u003cspan id="LC15" class="line" lang="markdown"\u003e\u003cspan class="p"\u003e-\u003c/span\u003e 15\u003c/span\u003e\n',
+              can_receive_suggestion: true,
+            },
+            {
+              line_code: null,
+              type: 'match',
+              old_line: null,
+              new_line: null,
+              text: '',
+              meta_data: { old_pos: 15, new_pos: 15 },
+              rich_text: '',
+              can_receive_suggestion: true,
+            },
+          ],
+        },
+      ],
+      type: 'text',
+      content_path:
+        '/gitlab-org/gitlab-test/-/merge_requests/2/conflict_for_path?new_path=README.md\u0026old_path=README.md',
+    },
+  ],
+};