diff --git a/app/assets/javascripts/issue_show/actions/tasks.js b/app/assets/javascripts/issue_show/actions/tasks.js
deleted file mode 100644
index 0740a9f559c..00000000000
--- a/app/assets/javascripts/issue_show/actions/tasks.js
+++ /dev/null
@@ -1,27 +0,0 @@
-export default (newStateData, tasks) => {
- const $tasks = $('#task_status');
- const $tasksShort = $('#task_status_short');
- const $issueableHeader = $('.issuable-header');
- const tasksStates = { newState: null, currentState: null };
-
- if ($tasks.length === 0) {
- if (!(newStateData.task_status.indexOf('0 of 0') === 0)) {
- $issueableHeader.append(`${newStateData.task_status}`);
- } else {
- $issueableHeader.append('');
- }
- } else {
- tasksStates.newState = newStateData.task_status.indexOf('0 of 0') === 0;
- tasksStates.currentState = tasks.indexOf('0 of 0') === 0;
- }
-
- if ($tasks.length !== 0 && !tasksStates.newState) {
- $tasks.text(newStateData.task_status);
- $tasksShort.text(newStateData.task_status);
- } else if (tasksStates.currentState) {
- $issueableHeader.append(`${newStateData.task_status}`);
- } else if (tasksStates.newState) {
- $tasks.remove();
- $tasksShort.remove();
- }
-};
diff --git a/app/assets/javascripts/issue_show/components/app.vue b/app/assets/javascripts/issue_show/components/app.vue
new file mode 100644
index 00000000000..752d07f7ef0
--- /dev/null
+++ b/app/assets/javascripts/issue_show/components/app.vue
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
diff --git a/app/assets/javascripts/issue_show/components/description.vue b/app/assets/javascripts/issue_show/components/description.vue
new file mode 100644
index 00000000000..298f87b6d22
--- /dev/null
+++ b/app/assets/javascripts/issue_show/components/description.vue
@@ -0,0 +1,100 @@
+
+
+
+
+
diff --git a/app/assets/javascripts/issue_show/components/title.vue b/app/assets/javascripts/issue_show/components/title.vue
new file mode 100644
index 00000000000..a9dabd4cff1
--- /dev/null
+++ b/app/assets/javascripts/issue_show/components/title.vue
@@ -0,0 +1,53 @@
+
+
+
+
+
+
diff --git a/app/assets/javascripts/issue_show/index.js b/app/assets/javascripts/issue_show/index.js
index eb20a597bb5..af11ae4c533 100644
--- a/app/assets/javascripts/issue_show/index.js
+++ b/app/assets/javascripts/issue_show/index.js
@@ -1,20 +1,32 @@
import Vue from 'vue';
-import IssueTitle from './issue_title_description.vue';
+import issuableApp from './components/app.vue';
import '../vue_shared/vue_resource_interceptor';
-(() => {
- const issueTitleData = document.querySelector('.issue-title-data').dataset;
- const { canUpdateTasksClass, endpoint } = issueTitleData;
+document.addEventListener('DOMContentLoaded', () => {
+ const issuableElement = document.getElementById('js-issuable-app');
+ const issuableTitleElement = issuableElement.querySelector('.title');
+ const issuableDescriptionElement = issuableElement.querySelector('.wiki');
+ const issuableDescriptionTextarea = issuableElement.querySelector('.js-task-list-field');
+ const {
+ canUpdate,
+ endpoint,
+ issuableRef,
+ } = issuableElement.dataset;
- const vm = new Vue({
- el: '.issue-title-entrypoint',
- render: createElement => createElement(IssueTitle, {
+ return new Vue({
+ el: issuableElement,
+ components: {
+ issuableApp,
+ },
+ render: createElement => createElement('issuable-app', {
props: {
- canUpdateTasksClass,
+ canUpdate: gl.utils.convertPermissionToBoolean(canUpdate),
endpoint,
+ issuableRef,
+ initialTitle: issuableTitleElement.innerHTML,
+ initialDescriptionHtml: issuableDescriptionElement ? issuableDescriptionElement.innerHTML : '',
+ initialDescriptionText: issuableDescriptionTextarea ? issuableDescriptionTextarea.textContent : '',
},
}),
});
-
- return vm;
-})();
+});
diff --git a/app/assets/javascripts/issue_show/issue_title_description.vue b/app/assets/javascripts/issue_show/issue_title_description.vue
deleted file mode 100644
index dc3ba2550c5..00000000000
--- a/app/assets/javascripts/issue_show/issue_title_description.vue
+++ /dev/null
@@ -1,180 +0,0 @@
-
-
-
-
-
diff --git a/app/assets/javascripts/issue_show/mixins/animate.js b/app/assets/javascripts/issue_show/mixins/animate.js
new file mode 100644
index 00000000000..eda6302aa8b
--- /dev/null
+++ b/app/assets/javascripts/issue_show/mixins/animate.js
@@ -0,0 +1,13 @@
+export default {
+ methods: {
+ animateChange() {
+ this.preAnimation = true;
+ this.pulseAnimation = false;
+
+ this.$nextTick(() => {
+ this.preAnimation = false;
+ this.pulseAnimation = true;
+ });
+ },
+ },
+};
diff --git a/app/assets/javascripts/issue_show/services/index.js b/app/assets/javascripts/issue_show/services/index.js
index c4ab0b1e07a..348ad8d6813 100644
--- a/app/assets/javascripts/issue_show/services/index.js
+++ b/app/assets/javascripts/issue_show/services/index.js
@@ -1,10 +1,16 @@
+import Vue from 'vue';
+import VueResource from 'vue-resource';
+
+Vue.use(VueResource);
+
export default class Service {
- constructor(resource, endpoint) {
- this.resource = resource;
+ constructor(endpoint) {
this.endpoint = endpoint;
+
+ this.resource = Vue.resource(this.endpoint);
}
- getTitle() {
- return this.resource.get(this.endpoint);
+ getData() {
+ return this.resource.get();
}
}
diff --git a/app/assets/javascripts/issue_show/stores/index.js b/app/assets/javascripts/issue_show/stores/index.js
new file mode 100644
index 00000000000..9c759dc53cb
--- /dev/null
+++ b/app/assets/javascripts/issue_show/stores/index.js
@@ -0,0 +1,25 @@
+export default class Store {
+ constructor({
+ title,
+ descriptionHtml,
+ descriptionText,
+ }) {
+ this.state = {
+ titleHtml: title,
+ titleText: '',
+ descriptionHtml,
+ descriptionText,
+ taskStatus: '',
+ updatedAt: '',
+ };
+ }
+
+ updateState(data) {
+ this.state.titleHtml = data.title;
+ this.state.titleText = data.title_text;
+ this.state.descriptionHtml = data.description;
+ this.state.descriptionText = data.description_text;
+ this.state.taskStatus = data.task_status;
+ this.state.updatedAt = data.updated_at;
+ }
+}
diff --git a/app/views/projects/issues/show.html.haml b/app/views/projects/issues/show.html.haml
index 9084883eb3e..bd03593eb98 100644
--- a/app/views/projects/issues/show.html.haml
+++ b/app/views/projects/issues/show.html.haml
@@ -51,10 +51,15 @@
.issue-details.issuable-details
.detail-page-description.content-block
- .issue-title-data.hidden{ "data" => { "endpoint" => rendered_title_namespace_project_issue_path(@project.namespace, @project, @issue),
- "can-update-tasks-class" => can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : '',
+ #js-issuable-app{ "data" => { "endpoint" => rendered_title_namespace_project_issue_path(@project.namespace, @project, @issue),
+ "can-update" => can?(current_user, :update_issue, @issue).to_s,
+ "issuable-ref" => @issue.to_reference,
} }
- .issue-title-entrypoint
+ %h2.title= markdown_field(@issue, :title)
+ - if @issue.description.present?
+ .description{ class: can?(current_user, :update_issue, @issue) ? 'js-task-list-container' : '' }
+ .wiki= markdown_field(@issue, :description)
+ %textarea.hidden.js-task-list-field= @issue.description
= edited_time_ago_with_tooltip(@issue, placement: 'bottom', html_class: 'issue_edited_ago')