Commit e57093ff authored by Fatih Acet's avatar Fatih Acet

IssueNotesRefactor: Implement main note form.

parent 998299e2
<script>
/* global Flash */
import UserAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
import MarkdownField from '../../vue_shared/components/markdown/field.vue';
export default {
props: {},
data() {
return {
note: '',
markdownPreviewUrl: '',
markdownDocsUrl: '',
// FIXME: @fatihacet - Fix the mock data below.
noteType: 'comment',
issueState: 'open',
endpoint: '/gitlab-org/gitlab-ce/notes',
author: {
avatar_url: 'http://www.gravatar.com/avatar/e64c7d89f26bd1972efa854d13d7dd61?s=80&d=identicon',
id: 1,
name: 'Administrator',
path: '/root',
state: 'active',
username: 'root',
},
};
},
components: {
UserAvatarLink,
MarkdownField,
},
computed: {
commentButtonTitle() {
return this.noteType === 'comment' ? 'Comment' : 'Start discussion';
},
issueActionButtonTitle() {
if (this.note.length) {
const actionText = this.issueState === 'open' ? 'close' : 'reopen';
return this.noteType === 'comment' ? `Comment & ${actionText} issue` : `Start discussion & ${actionText} issue`;
}
return this.issueState === 'open' ? 'Close issue' : 'Reopen issue';
},
},
methods: {
handleSave() {
const data = {
endpoint: `${this.endpoint}?full_data=1`,
noteData: {
target_type: 'issue',
target_id: '89',
note: {
noteable_type: 'Issue',
noteable_id: 89,
note: this.note,
}
},
};
if (this.noteType === 'discussion') {
data.noteData.note.type = 'DiscussionNote';
}
this.$store.dispatch('createNewNote', data)
.then(() => {
this.discard();
})
.catch(() => {
new Flash('Something went wrong while adding your comment. Please try again.'); // eslint-disable-line
});
},
discard() {
this.note = '';
this.$refs.textarea.focus();
},
setNoteType(type) {
this.noteType = type;
},
},
mounted() {
const issuableDataEl = document.getElementById('js-issuable-app-initial-data');
const issueData = JSON.parse(issuableDataEl.innerHTML.replace(/&quot;/g, '"'));
const { markdownDocs, markdownPreviewUrl } = issueData;
this.markdownDocsUrl = markdownDocs;
this.markdownPreviewUrl = markdownPreviewUrl;
},
};
</script>
<template>
<ul class="notes notes-form timeline new-note">
<li class="timeline-entry">
<div class="timeline-icon hidden-xs hidden-sm">
<user-avatar-link
:linkHref="author.path"
:imgSrc="author.avatar_url"
:imgAlt="author.name"
:imgSize="40" />
</div>
<div class="timeline-content timeline-content-form common-note-form">
<markdown-field
:markdown-preview-url="markdownPreviewUrl"
:markdown-docs="markdownDocsUrl"
:addSpacingClasses="false">
<textarea
id="note-body"
class="note-textarea js-gfm-input js-autosize markdown-area"
data-supports-slash-commands="true"
data-supports-quick-actions="true"
aria-label="Description"
v-model="note"
ref="textarea"
slot="textarea"
placeholder="Write a comment or drag your files here..."
@keydown.meta.enter="handleSave">
</textarea>
</markdown-field>
<div class="note-form-actions clearfix">
<div class="pull-left btn-group append-right-10 comment-type-dropdown js-comment-type-dropdown">
<input
@click="handleSave"
:disabled="!note.length"
:value="commentButtonTitle"
class="btn btn-nr btn-create comment-btn js-comment-button js-comment-submit-button"
type="submit" />
<button
:disabled="!note.length"
name="button"
type="button"
class="btn btn-nr comment-btn note-type-toggle js-note-new-discussion"
data-toggle="dropdown"
aria-label="Open comment type dropdown">
<i
aria-hidden="true"
class="fa fa-caret-down toggle-icon"></i>
</button>
<ul
class="dropdown-menu note-type-dropdown dropdown-open-top">
<li
:class="{ 'item-selected': noteType === 'comment' }"
@click.prevent="setNoteType('comment')">
<a href="#">
<i
aria-hidden="true"
class="fa fa-check"></i>
<div class="description">
<strong>Comment</strong>
<p>
Add a general comment to this issue.
</p>
</div>
</a>
</li>
<li class="divider"></li>
<li
:class="{ 'item-selected': noteType === 'discussion' }"
@click.prevent="setNoteType('discussion')">
<a href="#">
<i
aria-hidden="true"
class="fa fa-check"></i>
<div class="description">
<strong>Start discussion</strong>
<p>
Discuss a specific suggestion or question.
</p>
</div>
</a>
</li>
</ul>
</div>
<a
:class="{'btn-reopen': issueState === 'closed', 'btn-close': issueState === 'open'}"
class="btn btn-nr btn-comment">
{{issueActionButtonTitle}}
</a>
<a
v-if="note.length"
@click="discard"
class="btn btn-cancel js-note-discard"
role="button">
Discard draft
</a>
</div>
</div>
</li>
</ul>
</template>
...@@ -49,8 +49,9 @@ export default { ...@@ -49,8 +49,9 @@ export default {
this.signInLink = signInLink.getAttribute('href'); this.signInLink = signInLink.getAttribute('href');
} }
const newNotePath = document.querySelector('.js-main-target-form').getAttribute('action'); // TODO: @fatihacet - Reimplement this when we have data for it.
this.newNotePath = `${newNotePath}?full_data=1`; // const newNotePath = document.querySelector('.js-main-target-form').getAttribute('action');
// this.newNotePath = `${newNotePath}?full_data=1`;
}, },
methods: { methods: {
toggleDiscussion() { toggleDiscussion() {
......
...@@ -61,7 +61,8 @@ export default { ...@@ -61,7 +61,8 @@ export default {
<textarea <textarea
id="note-body" id="note-body"
class="note-textarea js-gfm-input js-autosize markdown-area" class="note-textarea js-gfm-input js-autosize markdown-area"
data-supports-slash-commands="false" data-supports-slash-commands="true"
data-supports-quick-actions="true"
aria-label="Description" aria-label="Description"
v-model="note" v-model="note"
ref="textarea" ref="textarea"
......
...@@ -7,6 +7,7 @@ import storeOptions from '../stores/issue_notes_store'; ...@@ -7,6 +7,7 @@ import storeOptions from '../stores/issue_notes_store';
import IssueNote from './issue_note.vue'; import IssueNote from './issue_note.vue';
import IssueDiscussion from './issue_discussion.vue'; import IssueDiscussion from './issue_discussion.vue';
import IssueSystemNote from './issue_system_note.vue'; import IssueSystemNote from './issue_system_note.vue';
import IssueCommentForm from './issue_comment_form.vue';
Vue.use(Vuex); Vue.use(Vuex);
const store = new Vuex.Store(storeOptions); const store = new Vuex.Store(storeOptions);
...@@ -23,6 +24,7 @@ export default { ...@@ -23,6 +24,7 @@ export default {
IssueNote, IssueNote,
IssueDiscussion, IssueDiscussion,
IssueSystemNote, IssueSystemNote,
IssueCommentForm,
}, },
methods: { methods: {
component(note) { component(note) {
...@@ -55,17 +57,19 @@ export default { ...@@ -55,17 +57,19 @@ export default {
v-if="isLoading" v-if="isLoading"
class="loading"> class="loading">
<i <i
aria-hidden="true" class="fa fa-spinner fa-spin"
class="fa fa-spinner fa-spin"></i> aria-hidden="true"></i>
</div> </div>
<ul <ul
class="notes main-notes-list timeline" v-if="!isLoading"
id="notes-list"> id="notes-list"
class="notes main-notes-list timeline">
<component <component
v-for="note in $store.getters.notes" v-for="note in $store.getters.notes"
:is="component(note)" :is="component(note)"
:note="componentData(note)" :note="componentData(note)"
:key="note.id" /> :key="note.id" />
</ul> </ul>
<issue-comment-form v-if="!isLoading" />
</div> </div>
</template> </template>
...@@ -16,4 +16,7 @@ export default { ...@@ -16,4 +16,7 @@ export default {
updateNote(endpoint, data) { updateNote(endpoint, data) {
return Vue.http.put(endpoint, data, { emulateJSON: true }); return Vue.http.put(endpoint, data, { emulateJSON: true });
}, },
createNewNote(endpoint, data) {
return Vue.http.post(endpoint, data, { emulateJSON: true });
}
}; };
...@@ -52,6 +52,10 @@ const mutations = { ...@@ -52,6 +52,10 @@ const mutations = {
noteObj.notes.splice(noteObj.notes.indexOf(comment), 1, note); noteObj.notes.splice(noteObj.notes.indexOf(comment), 1, note);
} }
}, },
addNewNote(storeState, note) {
// TODO: @fatihacet - When we get the correct data from server update the store
// storeState.notes.push(note);
},
}; };
const actions = { const actions = {
...@@ -90,6 +94,15 @@ const actions = { ...@@ -90,6 +94,15 @@ const actions = {
context.commit('updateNote', res); context.commit('updateNote', res);
}); });
}, },
createNewNote(context, data) {
const { endpoint, noteData } = data;
return service
.createNewNote(endpoint, noteData)
.then(res => res.json())
.then((res) => {
context.commit('addNewNote', res);
});
},
}; };
export default { export default {
......
...@@ -369,6 +369,10 @@ ...@@ -369,6 +369,10 @@
transform: translateY(0); transform: translateY(0);
} }
.comment-type-dropdown.open .dropdown-menu {
display: block;
}
.filtered-search-box-input-container { .filtered-search-box-input-container {
.dropdown-menu, .dropdown-menu,
.dropdown-menu-nav { .dropdown-menu-nav {
......
...@@ -10,5 +10,5 @@ ...@@ -10,5 +10,5 @@
= webpack_bundle_tag 'notes' = webpack_bundle_tag 'notes'
#notes{style: "margin-top: 150px"} / #notes{style: "margin-top: 150px"}
= render 'shared/notes/notes_with_form', :autocomplete => true / = render 'shared/notes/notes_with_form', :autocomplete => true
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment