[ci skip] Fix shortcuts for preview
This commit is contained in:
parent
9b87e680ca
commit
f5a21c596b
8 changed files with 175 additions and 177 deletions
|
@ -89,10 +89,10 @@
|
||||||
if (res.errors.commands_only) {
|
if (res.errors.commands_only) {
|
||||||
this.discard();
|
this.discard();
|
||||||
} else {
|
} else {
|
||||||
this.handleError();
|
return Flash('Something went wrong while adding your comment. Please try again.');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Flash('Something went wrong while adding your comment. Please try again.');
|
this.discard();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(() => {
|
.catch(() => {
|
||||||
|
@ -132,7 +132,7 @@
|
||||||
editCurrentUserLastNote() {
|
editCurrentUserLastNote() {
|
||||||
if (this.note === '') {
|
if (this.note === '') {
|
||||||
const lastNote = this.getCurrentUserLastNote(window.gon.current_user_id);
|
const lastNote = this.getCurrentUserLastNote(window.gon.current_user_id);
|
||||||
console.log(lastNote)
|
|
||||||
if (lastNote) {
|
if (lastNote) {
|
||||||
eventHub.$emit('enterEditMode', {
|
eventHub.$emit('enterEditMode', {
|
||||||
noteId: lastNote.id,
|
noteId: lastNote.id,
|
||||||
|
@ -172,102 +172,104 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div class="js-main-target-form timeline-content timeline-content-form common-note-form">
|
<div class="js-main-target-form timeline-content timeline-content-form common-note-form">
|
||||||
<markdown-field
|
<form>
|
||||||
:markdown-preview-url="markdownPreviewUrl"
|
<markdown-field
|
||||||
:markdown-docs="markdownDocsUrl"
|
:markdown-preview-url="markdownPreviewUrl"
|
||||||
:quick-actions-docs="quickActionsDocsUrl"
|
:markdown-docs="markdownDocsUrl"
|
||||||
:add-spacing-classes="false">
|
:quick-actions-docs="quickActionsDocsUrl"
|
||||||
<textarea
|
:add-spacing-classes="false">
|
||||||
id="note-body"
|
<textarea
|
||||||
name="note[note]"
|
id="note-body"
|
||||||
class="note-textarea js-gfm-input js-autosize markdown-area js-note-text"
|
name="note[note]"
|
||||||
data-supports-slash-commands="true"
|
class="note-textarea js-gfm-input js-autosize markdown-area js-note-text"
|
||||||
data-supports-quick-actions="true"
|
data-supports-slash-commands="true"
|
||||||
aria-label="Description"
|
data-supports-quick-actions="true"
|
||||||
v-model="note"
|
aria-label="Description"
|
||||||
ref="textarea"
|
v-model="note"
|
||||||
slot="textarea"
|
ref="textarea"
|
||||||
placeholder="Write a comment or drag your files here..."
|
slot="textarea"
|
||||||
@keydown.up="editCurrentUserLastNote()"
|
placeholder="Write a comment or drag your files here..."
|
||||||
@keydown.meta.enter="handleSave()">
|
@keydown.up="editCurrentUserLastNote()"
|
||||||
</textarea>
|
@keydown.meta.enter="handleSave()">
|
||||||
</markdown-field>
|
</textarea>
|
||||||
<div class="note-form-actions">
|
</markdown-field>
|
||||||
<div class="pull-left btn-group append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown">
|
<div class="note-form-actions">
|
||||||
<button
|
<div class="pull-left btn-group append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown">
|
||||||
@click="handleSave"
|
<button
|
||||||
:disabled="!note.length"
|
@click="handleSave()"
|
||||||
class="btn btn-nr btn-create comment-btn js-comment-button js-comment-submit-button"
|
:disabled="!note.length"
|
||||||
type="button">
|
class="btn btn-nr btn-create comment-btn js-comment-button js-comment-submit-button"
|
||||||
{{commentButtonTitle}}
|
type="button">
|
||||||
</button>
|
{{commentButtonTitle}}
|
||||||
<button
|
</button>
|
||||||
:disabled="!note.length"
|
<button
|
||||||
name="button"
|
:disabled="!note.length"
|
||||||
type="button"
|
name="button"
|
||||||
class="btn btn-nr comment-btn note-type-toggle js-note-new-discussion dropdown-toggle"
|
type="button"
|
||||||
data-toggle="dropdown"
|
class="btn btn-nr comment-btn note-type-toggle js-note-new-discussion dropdown-toggle"
|
||||||
aria-label="Open comment type dropdown">
|
data-toggle="dropdown"
|
||||||
<i
|
aria-label="Open comment type dropdown">
|
||||||
aria-hidden="true"
|
<i
|
||||||
class="fa fa-caret-down toggle-icon">
|
aria-hidden="true"
|
||||||
</i>
|
class="fa fa-caret-down toggle-icon">
|
||||||
</button>
|
</i>
|
||||||
|
</button>
|
||||||
|
|
||||||
<ul class="note-type-dropdown dropdown-open-top dropdown-menu">
|
<ul class="note-type-dropdown dropdown-open-top dropdown-menu">
|
||||||
<li :class="{ 'droplab-item-selected': noteType === 'comment' }">
|
<li :class="{ 'droplab-item-selected': noteType === 'comment' }">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
class="btn btn-transparent"
|
class="btn btn-transparent"
|
||||||
@click.prevent="setNoteType('comment')">
|
@click.prevent="setNoteType('comment')">
|
||||||
<i
|
<i
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
class="fa fa-check icon">
|
class="fa fa-check icon">
|
||||||
</i>
|
|
||||||
<div class="description">
|
|
||||||
<strong>Comment</strong>
|
|
||||||
<p>
|
|
||||||
Add a general comment to this issue.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</button>
|
|
||||||
</li>
|
|
||||||
<li class="divider droplab-item-ignore"></li>
|
|
||||||
<li :class="{ 'droplab-item-selected': noteType === 'discussion' }">
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
class="btn btn-transparent"
|
|
||||||
@click.prevent="setNoteType('discussion')">
|
|
||||||
<i
|
|
||||||
aria-hidden="true"
|
|
||||||
class="fa fa-check icon">
|
|
||||||
</i>
|
</i>
|
||||||
<div class="description">
|
<div class="description">
|
||||||
<strong>Start discussion</strong>
|
<strong>Comment</strong>
|
||||||
<p>
|
<p>
|
||||||
Discuss a specific suggestion or question.
|
Add a general comment to this issue.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
<li class="divider droplab-item-ignore"></li>
|
||||||
|
<li :class="{ 'droplab-item-selected': noteType === 'discussion' }">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-transparent"
|
||||||
|
@click.prevent="setNoteType('discussion')">
|
||||||
|
<i
|
||||||
|
aria-hidden="true"
|
||||||
|
class="fa fa-check icon">
|
||||||
|
</i>
|
||||||
|
<div class="description">
|
||||||
|
<strong>Start discussion</strong>
|
||||||
|
<p>
|
||||||
|
Discuss a specific suggestion or question.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
@click="handleSave(true)"
|
||||||
|
v-if="canUpdateIssue"
|
||||||
|
:class="actionButtonClassNames"
|
||||||
|
class="btn btn-nr btn-comment btn-comment-and-close">
|
||||||
|
{{issueActionButtonTitle}}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
v-if="note.length"
|
||||||
|
@click="discard"
|
||||||
|
class="btn btn-cancel js-note-discard">
|
||||||
|
Discard draft
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<button
|
</form>
|
||||||
type="button"
|
|
||||||
@click="handleSave(true)"
|
|
||||||
v-if="canUpdateIssue"
|
|
||||||
:class="actionButtonClassNames"
|
|
||||||
class="btn btn-nr btn-comment btn-comment-and-close">
|
|
||||||
{{issueActionButtonTitle}}
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
v-if="note.length"
|
|
||||||
@click="discard"
|
|
||||||
class="btn btn-cancel js-note-discard">
|
|
||||||
Discard draft
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -94,7 +94,6 @@
|
||||||
to ensure information is not lost.
|
to ensure information is not lost.
|
||||||
</div>
|
</div>
|
||||||
<form
|
<form
|
||||||
@submit="handleUpdate"
|
|
||||||
class="edit-note common-note-form">
|
class="edit-note common-note-form">
|
||||||
<markdown-field
|
<markdown-field
|
||||||
:markdown-preview-url="markdownPreviewUrl"
|
:markdown-preview-url="markdownPreviewUrl"
|
||||||
|
@ -103,7 +102,7 @@
|
||||||
<textarea
|
<textarea
|
||||||
id="note-body"
|
id="note-body"
|
||||||
name="note[note]"
|
name="note[note]"
|
||||||
class="note-textarea js-gfm-input js-autosize markdown-area js-note-text"
|
class="note-textarea js-gfm-input js-autosize markdown-area"
|
||||||
data-supports-slash-commands="true"
|
data-supports-slash-commands="true"
|
||||||
data-supports-quick-actions="true"
|
data-supports-quick-actions="true"
|
||||||
aria-label="Description"
|
aria-label="Description"
|
||||||
|
@ -118,7 +117,8 @@
|
||||||
</markdown-field>
|
</markdown-field>
|
||||||
<div class="note-form-actions clearfix">
|
<div class="note-form-actions clearfix">
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="button"
|
||||||
|
@click="handleUpdate"
|
||||||
class="btn btn-nr btn-save">
|
class="btn btn-nr btn-save">
|
||||||
{{saveButtonTitle}}
|
{{saveButtonTitle}}
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -48,6 +48,7 @@
|
||||||
computed: {
|
computed: {
|
||||||
...mapGetters([
|
...mapGetters([
|
||||||
'notes',
|
'notes',
|
||||||
|
'notesById',
|
||||||
'getNotesDataByProp',
|
'getNotesDataByProp',
|
||||||
]),
|
]),
|
||||||
},
|
},
|
||||||
|
@ -55,7 +56,7 @@
|
||||||
...mapActions({
|
...mapActions({
|
||||||
actionFetchNotes: 'fetchNotes',
|
actionFetchNotes: 'fetchNotes',
|
||||||
poll: 'poll',
|
poll: 'poll',
|
||||||
toggleAward: 'toggleAward',
|
actionToggleAward: 'toggleAward',
|
||||||
scrollToNoteIfNeeded: 'scrollToNoteIfNeeded',
|
scrollToNoteIfNeeded: 'scrollToNoteIfNeeded',
|
||||||
setNotesData: 'setNotesData',
|
setNotesData: 'setNotesData',
|
||||||
setIssueData: 'setIssueData',
|
setIssueData: 'setIssueData',
|
||||||
|
@ -113,11 +114,11 @@
|
||||||
const { awardName, noteId } = data;
|
const { awardName, noteId } = data;
|
||||||
const endpoint = this.notesById[noteId].toggle_award_path;
|
const endpoint = this.notesById[noteId].toggle_award_path;
|
||||||
|
|
||||||
this.toggleAward({ endpoint, awardName, noteId })
|
this.actionToggleAward({ endpoint, awardName, noteId })
|
||||||
.catch(() => Flash('Something went wrong on our end.'));
|
.catch((error) => Flash('Something went wrong on our end.'));
|
||||||
});
|
});
|
||||||
|
|
||||||
//TODO: FILIPA: REMOVE JQUERY
|
// JQuery is needed here because it is a custom event being dispatched with jQuery.
|
||||||
$(document).on('issuable:change', (e, isClosed) => {
|
$(document).on('issuable:change', (e, isClosed) => {
|
||||||
eventHub.$emit('issueStateChanged', isClosed);
|
eventHub.$emit('issueStateChanged', isClosed);
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,45 +1,48 @@
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import issueNotesApp from './components/issue_notes_app.vue';
|
import issueNotesApp from './components/issue_notes_app.vue';
|
||||||
|
|
||||||
document.addEventListener('DOMContentLoaded', () => new Vue({
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
el: '#js-vue-notes',
|
const vm = new Vue({
|
||||||
components: {
|
el: '#js-vue-notes',
|
||||||
issueNotesApp,
|
components: {
|
||||||
},
|
issueNotesApp,
|
||||||
data() {
|
},
|
||||||
const notesDataset = document.getElementById('js-vue-notes').dataset;
|
data() {
|
||||||
|
const notesDataset = document.getElementById('js-vue-notes').dataset;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
issueData: JSON.parse(notesDataset.issueData),
|
issueData: JSON.parse(notesDataset.issueData),
|
||||||
currentUserData: JSON.parse(notesDataset.currentUserData),
|
currentUserData: JSON.parse(notesDataset.currentUserData),
|
||||||
notesData: {
|
notesData: {
|
||||||
lastFetchedAt: notesDataset.lastFetchedAt,
|
lastFetchedAt: notesDataset.lastFetchedAt,
|
||||||
discussionsPath: notesDataset.discussionsPath,
|
discussionsPath: notesDataset.discussionsPath,
|
||||||
newSessionPath: notesDataset.newSessionPath,
|
newSessionPath: notesDataset.newSessionPath,
|
||||||
registerPath: notesDataset.registerPath,
|
registerPath: notesDataset.registerPath,
|
||||||
notesPath: notesDataset.notesPath,
|
notesPath: notesDataset.notesPath,
|
||||||
markdownDocs: notesDataset.markdownDocs,
|
markdownDocs: notesDataset.markdownDocs,
|
||||||
quickActionsDocs: notesDataset.quickActionsDocs,
|
quickActionsDocs: notesDataset.quickActionsDocs,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
render(createElement) {
|
render(createElement) {
|
||||||
return createElement('issue-notes-app', {
|
return createElement('issue-notes-app', {
|
||||||
attrs: {
|
attrs: {
|
||||||
ref: 'notes',
|
ref: 'notes',
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
issueData: this.issueData,
|
issueData: this.issueData,
|
||||||
notesData: this.notesData,
|
notesData: this.notesData,
|
||||||
userData: this.currentUserData,
|
userData: this.currentUserData,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
}));
|
});
|
||||||
|
|
||||||
|
// This is used in note_polling_spec
|
||||||
|
window.issueNotes = {
|
||||||
|
refresh() {
|
||||||
|
vm.$refs.notes.$store.dispatch('poll');
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
// // TODO: FILIPA: FIX THIS
|
|
||||||
// window.issueNotes = {
|
|
||||||
// refresh() {
|
|
||||||
// vm.$refs.notes.$store.dispatch('poll');
|
|
||||||
// },
|
|
||||||
// };
|
|
||||||
|
|
|
@ -131,32 +131,31 @@ export const saveNote = ({ commit, dispatch }, noteData) => {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const poll = ({ commit, state, getters }) => {
|
export const poll = ({ commit, state, getters }) => service
|
||||||
return service.poll(state.notesData.notesPath, state.lastFetchedAt)
|
.poll(state.notesData.notesPath, state.lastFetchedAt)
|
||||||
.then(res => res.json())
|
.then(res => res.json())
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
if (res.notes.length) {
|
if (res.notes.length) {
|
||||||
const { notesById } = getters;
|
const { notesById } = getters;
|
||||||
|
|
||||||
res.notes.forEach((note) => {
|
res.notes.forEach((note) => {
|
||||||
if (notesById[note.id]) {
|
if (notesById[note.id]) {
|
||||||
commit(types.UPDATE_NOTE, note);
|
commit(types.UPDATE_NOTE, note);
|
||||||
} else if (note.type === constants.DISCUSSION_NOTE) {
|
} else if (note.type === constants.DISCUSSION_NOTE) {
|
||||||
const discussion = utils.findNoteObjectById(state.notes, note.discussion_id);
|
const discussion = utils.findNoteObjectById(state.notes, note.discussion_id);
|
||||||
|
|
||||||
if (discussion) {
|
if (discussion) {
|
||||||
commit(types.ADD_NEW_REPLY_TO_DISCUSSION, note);
|
commit(types.ADD_NEW_REPLY_TO_DISCUSSION, note);
|
||||||
} else {
|
|
||||||
commit(types.ADD_NEW_NOTE, note);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
commit(types.ADD_NEW_NOTE, note);
|
commit(types.ADD_NEW_NOTE, note);
|
||||||
}
|
}
|
||||||
});
|
} else {
|
||||||
}
|
commit(types.ADD_NEW_NOTE, note);
|
||||||
return res;
|
}
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
|
||||||
export const toggleAward = ({ commit, getters, dispatch }, data) => {
|
export const toggleAward = ({ commit, getters, dispatch }, data) => {
|
||||||
const { endpoint, awardName, noteId, skipMutalityCheck } = data;
|
const { endpoint, awardName, noteId, skipMutalityCheck } = data;
|
||||||
|
|
|
@ -10,17 +10,10 @@ export const getIssueDataByProp = state => prop => state.issueData[prop];
|
||||||
export const getUserData = state => state.userData;
|
export const getUserData = state => state.userData;
|
||||||
export const getUserDataByProp = state => prop => state.notesData[prop];
|
export const getUserDataByProp = state => prop => state.notesData[prop];
|
||||||
|
|
||||||
export const notesById = (state) => {
|
export const notesById = state => state.notes.reduce((acc, note) => {
|
||||||
const notesByIdObject = {};
|
note.notes.every(n => Object.assign(acc, { [n.id]: n }));
|
||||||
// TODO: FILIPA: TRANSFORM INTO A REDUCE
|
return acc;
|
||||||
state.notes.forEach((note) => {
|
}, {});
|
||||||
note.notes.forEach((n) => {
|
|
||||||
notesByIdObject[n.id] = n;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
return notesByIdObject;
|
|
||||||
};
|
|
||||||
|
|
||||||
const reverseNotes = array => array.slice(0).reverse();
|
const reverseNotes = array => array.slice(0).reverse();
|
||||||
const isLastNote = (note, userId) => !note.system && note.author.id === userId;
|
const isLastNote = (note, userId) => !note.system && note.author.id === userId;
|
||||||
|
@ -31,6 +24,7 @@ export const getCurrentUserLastNote = state => userId => reverseNotes(state.note
|
||||||
return acc;
|
return acc;
|
||||||
}, []).filter(el => el !== undefined)[0];
|
}, []).filter(el => el !== undefined)[0];
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
export const getDiscussionLastNote = state => (discussion, userId) => reverseNotes(discussion.notes)
|
export const getDiscussionLastNote = state => (discussion, userId) => reverseNotes(discussion.notes)
|
||||||
.find(el => isLastNote(el, userId));
|
.find(el => isLastNote(el, userId));
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,6 @@ export default new Vuex.Store({
|
||||||
notesData: {},
|
notesData: {},
|
||||||
userData: {},
|
userData: {},
|
||||||
issueData: {},
|
issueData: {},
|
||||||
paths: {},
|
|
||||||
},
|
},
|
||||||
actions,
|
actions,
|
||||||
getters,
|
getters,
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
new_session_path: new_session_path(:user, redirect_to_referer: 'yes'),
|
new_session_path: new_session_path(:user, redirect_to_referer: 'yes'),
|
||||||
markdown_docs: help_page_path('user/markdown'),
|
markdown_docs: help_page_path('user/markdown'),
|
||||||
quick_actions_docs: help_page_path('user/project/quick_actions'),
|
quick_actions_docs: help_page_path('user/project/quick_actions'),
|
||||||
notes_path: '#{notes_url}?full_data=1',
|
notes_path: "#{notes_url}?full_data=1",
|
||||||
last_fetched_at: Time.now.to_i,
|
last_fetched_at: Time.now.to_i,
|
||||||
issue_data: serialize_issuable(@issue),
|
issue_data: serialize_issuable(@issue),
|
||||||
current_user_data: UserSerializer.new.represent(current_user).to_json }}
|
current_user_data: UserSerializer.new.represent(current_user).to_json }}
|
||||||
|
|
Loading…
Reference in a new issue