diff options
author | jerasmus <jerasmus@gitlab.com> | 2018-11-21 16:47:57 +0200 |
---|---|---|
committer | jerasmus <jerasmus@gitlab.com> | 2018-11-21 16:47:57 +0200 |
commit | e89d8b485c7ece09534168c13a3fb55c0a1cb20f (patch) | |
tree | 4bade7b0d919ad30c25043582a064e9ec61ebdb7 | |
parent | bd082c69d2be456ef19f992066796cd7c8bd4d1c (diff) | |
download | gitlab-ce-suggest-change-to-diff-line-fe.tar.gz |
Add toolbar icon + UX adjustmentssuggest-change-to-diff-line-fe
Added MD toolbar icon.
Refined the UI to match ux mockups.
11 files changed, 115 insertions, 11 deletions
diff --git a/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue b/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue index 91b87fb042c..712acdcca85 100644 --- a/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue +++ b/app/assets/javascripts/diffs/components/inline_diff_comment_row.vue @@ -37,7 +37,11 @@ export default { <tr :class="className" class="notes_holder"> <td class="notes_content" colspan="3"> <div class="content"> - <diff-discussions v-if="line.discussions.length" :discussions="line.discussions" /> + <diff-discussions + v-if="line.discussions.length" + :line="line" + :discussions="line.discussions" + /> <diff-line-note-form v-if="diffLineCommentForms[line.line_code]" :diff-file-hash="diffFileHash" diff --git a/app/assets/javascripts/lib/utils/text_markdown.js b/app/assets/javascripts/lib/utils/text_markdown.js index 3618c6af7e2..dec85dc1da8 100644 --- a/app/assets/javascripts/lib/utils/text_markdown.js +++ b/app/assets/javascripts/lib/utils/text_markdown.js @@ -39,7 +39,7 @@ function blockTagText(text, textArea, blockTag, selected) { } } -function moveCursor({ textArea, tag, positionBetweenTags, removedLastNewLine, select }) { +function moveCursor({ textArea, tag, cursorOffset, positionBetweenTags, removedLastNewLine, select }) { var pos; if (!textArea.setSelectionRange) { return; @@ -61,11 +61,15 @@ function moveCursor({ textArea, tag, positionBetweenTags, removedLastNewLine, se pos -= 1; } + if(cursorOffset) { + pos -= cursorOffset; + } + return textArea.setSelectionRange(pos, pos); } } -export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wrap, select }) { +export function insertMarkdownText({ textArea, text, tag, cursorOffset, blockTag, selected, wrap, select }) { var textToInsert, selectedSplit, startChar, @@ -154,20 +158,21 @@ export function insertMarkdownText({ textArea, text, tag, blockTag, selected, wr return moveCursor({ textArea, tag: tag.replace(textPlaceholder, selected), + cursorOffset, positionBetweenTags: wrap && selected.length === 0, removedLastNewLine, select, }); } -function updateText({ textArea, tag, blockTag, wrap, select }) { +function updateText({ textArea, tag, cursorOffset, blockTag, wrap, select }) { var $textArea, selected, text; $textArea = $(textArea); textArea = $textArea.get(0); text = $textArea.val(); selected = selectedText(text, textArea); $textArea.focus(); - return insertMarkdownText({ textArea, text, tag, blockTag, selected, wrap, select }); + return insertMarkdownText({ textArea, text, tag, cursorOffset, blockTag, selected, wrap, select }); } export function addMarkdownListeners(form) { @@ -178,6 +183,7 @@ export function addMarkdownListeners(form) { return updateText({ textArea: $this.closest('.md-area').find('textarea'), tag: $this.data('mdTag'), + cursorOffset: $this.data('mdCursorOffset'), blockTag: $this.data('mdBlock'), wrap: !$this.data('mdPrepend'), select: $this.data('mdSelect'), diff --git a/app/assets/javascripts/notes/components/note_body.vue b/app/assets/javascripts/notes/components/note_body.vue index c0bee600181..c0bce9bcd65 100644 --- a/app/assets/javascripts/notes/components/note_body.vue +++ b/app/assets/javascripts/notes/components/note_body.vue @@ -5,6 +5,7 @@ import noteAwardsList from './note_awards_list.vue'; import noteAttachment from './note_attachment.vue'; import noteForm from './note_form.vue'; import autosave from '../mixins/autosave'; +import suggestion from '~/vue_shared/components/markdown/suggestion.vue'; export default { components: { @@ -12,6 +13,7 @@ export default { noteAwardsList, noteAttachment, noteForm, + suggestion, }, mixins: [autosave], props: { @@ -19,6 +21,11 @@ export default { type: Object, required: true, }, + line: { + type: Object, + required: false, + default: null, + }, canEdit: { type: Boolean, required: true, @@ -33,6 +40,21 @@ export default { noteBody() { return this.note.note; }, + mockSuggestion() { + // temporary: this will be generated on the backend and returned via api call in parent + return ` + <p dir="auto">I suggest</p> + 
 + <pre class="code highlight js-syntax-highlight suggestion" lang="suggestion" v-pre="true"><code class="js-render-suggestion"><span id="LC1" class="line" lang="suggestion"><p>Foo</p></span></code></pre> + 
 + + <p dir="auto">Or this</p> + 
 + <pre class="code highlight js-syntax-highlight suggestion" lang="suggestion" v-pre="true"><code class="js-render-suggestion"><span id="LC1" class="line" lang="suggestion"><p>Bar</p></span></code></pre>`; + }, + isSuggestion() { + return this.mockSuggestion.includes('js-render-suggestion'); + }, }, mounted() { this.renderGFM(); @@ -68,7 +90,17 @@ export default { <template> <div ref="note-body" :class="{ 'js-task-list-container': canEdit }" class="note-body"> - <div class="note-text md" v-html="note.note_html"></div> + <suggestion + v-if="isSuggestion" + :note="note" + :line="line" + :suggestion-html="mockSuggestion" + /> + <div + v-else + class="note-text md" + v-html="mockSuggestion" + ></div> <note-form v-if="isEditing" ref="noteForm" diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue index ad58267b533..fed5e2400b3 100644 --- a/app/assets/javascripts/notes/components/note_form.vue +++ b/app/assets/javascripts/notes/components/note_form.vue @@ -48,6 +48,11 @@ export default { required: false, default: '', }, + line: { + type: Object, + required: false, + default: null, + }, }, data() { return { @@ -166,6 +171,7 @@ export default { :markdown-version="markdownVersion" :quick-actions-docs-path="quickActionsDocsPath" :add-spacing-classes="false" + :line="line" > <textarea id="note_note" diff --git a/app/assets/javascripts/vue_shared/components/markdown/field.vue b/app/assets/javascripts/vue_shared/components/markdown/field.vue index 21d6519191f..392c08fc5c0 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/field.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/field.vue @@ -6,12 +6,14 @@ import GLForm from '../../../gl_form'; import markdownHeader from './header.vue'; import markdownToolbar from './toolbar.vue'; import icon from '../icon.vue'; +import suggestion from '~/vue_shared/components/markdown/suggestion.vue'; export default { components: { markdownHeader, markdownToolbar, icon, + suggestion, }, props: { markdownPreviewPath: { @@ -48,6 +50,11 @@ export default { required: false, default: true, }, + line: { + type: Object, + required: false, + default: null, + }, }, data() { return { @@ -63,6 +70,21 @@ export default { const referencedUsersThreshold = 10; return this.referencedUsers.length >= referencedUsersThreshold; }, + mockSuggestion() { + // temporary: this will be generated on the backend and returned via api call in parent + return ` + <p dir="auto">I suggest</p> + 
 + <pre class="code highlight js-syntax-highlight suggestion" lang="suggestion" v-pre="true"><code class="js-render-suggestion"><span id="LC1" class="line" lang="suggestion"><p>Foo</p></span></code></pre> + 
 + + <p dir="auto">Or this</p> + 
 + <pre class="code highlight js-syntax-highlight suggestion" lang="suggestion" v-pre="true"><code class="js-render-suggestion"><span id="LC1" class="line" lang="suggestion"><p>Bar</p></span></code></pre>`; + }, + isSuggestion() { + return this.mockSuggestion.includes('js-render-suggestion'); + }, }, mounted() { /* @@ -163,7 +185,16 @@ export default { </div> </div> <div v-show="previewMarkdown" class="md md-preview-holder md-preview js-vue-md-preview"> - <div ref="markdown-preview" v-html="markdownPreview"></div> + <suggestion + v-if="isSuggestion" + :suggestion-html="mockSuggestion" + :line="line" + /> + <div + v-else + ref="markdown-preview" + v-html="mockSuggestion" + ></div> <span v-if="markdownPreviewLoading"> Loading... </span> </div> <template v-if="previewMarkdown && !markdownPreviewLoading"> diff --git a/app/assets/javascripts/vue_shared/components/markdown/header.vue b/app/assets/javascripts/vue_shared/components/markdown/header.vue index 4c4ba537065..8c68a9d5be6 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/header.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/header.vue @@ -119,6 +119,13 @@ export default { :button-title="__('Add a table')" icon="table" /> + <toolbar-button + tag="```suggestion {text} ```" + :prepend="true" + :button-title="__('Insert suggestion')" + :cursor-offset="4" + icon="doc-code" + /> <button v-gl-tooltip aria-label="Go full screen" diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestion.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestion.vue index d6b0ce2ea9c..18cba8aab39 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/suggestion.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/suggestion.vue @@ -102,7 +102,6 @@ export default { <div> <div ref="container" - class="md-suggestion-diff" v-html="suggestionHtml" ></div> </div> diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue index 6a2a7adb314..7b30053508f 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff.vue @@ -29,12 +29,12 @@ export default { </script> <template> - <div class="md-suggestion-diff-content"> + <div> <suggestion-diff-header :can-apply="canApply" @apply="applySuggestion" /> - <table class="mb-3"> + <table class="mb-3 md-suggestion-diff"> <tbody> <!-- New Line --> <tr class="line_holder new"> diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue index ddb303b8962..463fc39b5ff 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/suggestion_diff_header.vue @@ -1,5 +1,8 @@ <script> +import Icon from '~/vue_shared/components/icon.vue'; + export default { + components: { Icon }, props: { canApply: { type: Boolean, @@ -17,7 +20,10 @@ export default { <template> <div class="file-title-flex-parent md-suggestion-header border-bottom-0 mt-2"> - Suggested change + <div> + Suggested change + <icon name="question-o" css-classes="link-highlight" /> + </div> <button v-if="canApply" type="button" diff --git a/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue b/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue index a6d2cecdf7e..4bf6a0b9b26 100644 --- a/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue +++ b/app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue @@ -37,6 +37,11 @@ export default { required: false, default: false, }, + cursorOffset: { + type: Number, + required: false, + default: 0, + }, }, }; </script> @@ -45,6 +50,7 @@ export default { <button v-gl-tooltip :data-md-tag="tag" + :data-md-cursor-offset="cursorOffset" :data-md-select="tagSelect" :data-md-block="tagBlock" :data-md-prepend="prepend" diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss index 6ef3d700015..e83af08f478 100644 --- a/app/assets/stylesheets/framework/markdown_area.scss +++ b/app/assets/stylesheets/framework/markdown_area.scss @@ -265,10 +265,17 @@ } } +.md-suggestion-diff { + border: 1px solid $border-color !important; +} + .md-suggestion-header { border: 1px solid $border-color; font-weight: $gl-font-weight-bold; height: 45px; + svg { + color: $blue-600; + } } @include media-breakpoint-down(xs) { |