Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
d2fd6bd5
Commit
d2fd6bd5
authored
Jun 14, 2019
by
Phil Hughes
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Added diff suggestion popover
Closes
https://gitlab.com/gitlab-org/gitlab-ce/issues/56523
parent
57783259
Changes
25
Hide whitespace changes
Inline
Side-by-side
Showing
25 changed files
with
269 additions
and
79 deletions
+269
-79
app/assets/javascripts/diffs/components/app.vue
app/assets/javascripts/diffs/components/app.vue
+16
-1
app/assets/javascripts/diffs/components/diff_line_note_form.vue
...sets/javascripts/diffs/components/diff_line_note_form.vue
+9
-1
app/assets/javascripts/diffs/index.js
app/assets/javascripts/diffs/index.js
+4
-0
app/assets/javascripts/diffs/store/actions.js
app/assets/javascripts/diffs/store/actions.js
+14
-2
app/assets/javascripts/diffs/store/modules/diff_state.js
app/assets/javascripts/diffs/store/modules/diff_state.js
+2
-0
app/assets/javascripts/diffs/store/mutation_types.js
app/assets/javascripts/diffs/store/mutation_types.js
+2
-0
app/assets/javascripts/diffs/store/mutations.js
app/assets/javascripts/diffs/store/mutations.js
+5
-2
app/assets/javascripts/notes/components/note_form.vue
app/assets/javascripts/notes/components/note_form.vue
+8
-1
app/assets/javascripts/vue_shared/components/markdown/field.vue
...sets/javascripts/vue_shared/components/markdown/field.vue
+7
-0
app/assets/javascripts/vue_shared/components/markdown/header.vue
...ets/javascripts/vue_shared/components/markdown/header.vue
+97
-61
app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
...scripts/vue_shared/components/markdown/toolbar_button.vue
+1
-0
app/assets/stylesheets/framework/markdown_area.scss
app/assets/stylesheets/framework/markdown_area.scss
+0
-2
app/assets/stylesheets/pages/diff.scss
app/assets/stylesheets/pages/diff.scss
+13
-1
app/helpers/user_callouts_helper.rb
app/helpers/user_callouts_helper.rb
+5
-0
app/models/user_callout_enums.rb
app/models/user_callout_enums.rb
+2
-1
app/views/projects/merge_requests/show.html.haml
app/views/projects/merge_requests/show.html.haml
+3
-1
changelogs/unreleased/diff-suggestions-popover.yml
changelogs/unreleased/diff-suggestions-popover.yml
+5
-0
locale/gitlab.pot
locale/gitlab.pot
+12
-0
spec/features/issues/markdown_toolbar_spec.rb
spec/features/issues/markdown_toolbar_spec.rb
+1
-1
spec/features/merge_request/user_posts_notes_spec.rb
spec/features/merge_request/user_posts_notes_spec.rb
+1
-1
spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
...tures/merge_request/user_suggests_changes_on_diff_spec.rb
+12
-0
spec/javascripts/diffs/components/app_spec.js
spec/javascripts/diffs/components/app_spec.js
+2
-0
spec/javascripts/diffs/store/actions_spec.js
spec/javascripts/diffs/store/actions_spec.js
+37
-3
spec/javascripts/diffs/store/mutations_spec.js
spec/javascripts/diffs/store/mutations_spec.js
+10
-0
spec/javascripts/vue_shared/components/markdown/header_spec.js
...javascripts/vue_shared/components/markdown/header_spec.js
+1
-1
No files found.
app/assets/javascripts/diffs/components/app.vue
View file @
d2fd6bd5
...
@@ -69,6 +69,16 @@ export default {
...
@@ -69,6 +69,16 @@ export default {
required
:
false
,
required
:
false
,
default
:
false
,
default
:
false
,
},
},
dismissEndpoint
:
{
type
:
String
,
required
:
false
,
default
:
''
,
},
showSuggestPopover
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
},
data
()
{
data
()
{
const
treeWidth
=
const
treeWidth
=
...
@@ -141,7 +151,12 @@ export default {
...
@@ -141,7 +151,12 @@ export default {
showTreeList
:
'
adjustView
'
,
showTreeList
:
'
adjustView
'
,
},
},
mounted
()
{
mounted
()
{
this
.
setBaseConfig
({
endpoint
:
this
.
endpoint
,
projectPath
:
this
.
projectPath
});
this
.
setBaseConfig
({
endpoint
:
this
.
endpoint
,
projectPath
:
this
.
projectPath
,
dismissEndpoint
:
this
.
dismissEndpoint
,
showSuggestPopover
:
this
.
showSuggestPopover
,
});
if
(
this
.
shouldShow
)
{
if
(
this
.
shouldShow
)
{
this
.
fetchData
();
this
.
fetchData
();
...
...
app/assets/javascripts/diffs/components/diff_line_note_form.vue
View file @
d2fd6bd5
...
@@ -42,6 +42,7 @@ export default {
...
@@ -42,6 +42,7 @@ export default {
noteableData
:
state
=>
state
.
notes
.
noteableData
,
noteableData
:
state
=>
state
.
notes
.
noteableData
,
diffViewType
:
state
=>
state
.
diffs
.
diffViewType
,
diffViewType
:
state
=>
state
.
diffs
.
diffViewType
,
}),
}),
...
mapState
(
'
diffs
'
,
[
'
showSuggestPopover
'
]),
...
mapGetters
(
'
diffs
'
,
[
'
getDiffFileByHash
'
]),
...
mapGetters
(
'
diffs
'
,
[
'
getDiffFileByHash
'
]),
...
mapGetters
([
...
mapGetters
([
'
isLoggedIn
'
,
'
isLoggedIn
'
,
...
@@ -80,7 +81,12 @@ export default {
...
@@ -80,7 +81,12 @@ export default {
}
}
},
},
methods
:
{
methods
:
{
...
mapActions
(
'
diffs
'
,
[
'
cancelCommentForm
'
,
'
assignDiscussionsToDiff
'
,
'
saveDiffDiscussion
'
]),
...
mapActions
(
'
diffs
'
,
[
'
cancelCommentForm
'
,
'
assignDiscussionsToDiff
'
,
'
saveDiffDiscussion
'
,
'
setSuggestPopoverDismissed
'
,
]),
handleCancelCommentForm
(
shouldConfirm
,
isDirty
)
{
handleCancelCommentForm
(
shouldConfirm
,
isDirty
)
{
if
(
shouldConfirm
&&
isDirty
)
{
if
(
shouldConfirm
&&
isDirty
)
{
const
msg
=
s__
(
'
Notes|Are you sure you want to cancel creating this comment?
'
);
const
msg
=
s__
(
'
Notes|Are you sure you want to cancel creating this comment?
'
);
...
@@ -125,11 +131,13 @@ export default {
...
@@ -125,11 +131,13 @@ export default {
:line=
"line"
:line=
"line"
:help-page-path=
"helpPagePath"
:help-page-path=
"helpPagePath"
:diff-file=
"diffFile"
:diff-file=
"diffFile"
:show-suggest-popover=
"showSuggestPopover"
save-button-title=
"Comment"
save-button-title=
"Comment"
class=
"diff-comment-form"
class=
"diff-comment-form"
@
handleFormUpdateAddToReview=
"addToReview"
@
handleFormUpdateAddToReview=
"addToReview"
@
cancelForm=
"handleCancelCommentForm"
@
cancelForm=
"handleCancelCommentForm"
@
handleFormUpdate=
"handleSaveNote"
@
handleFormUpdate=
"handleSaveNote"
@
handleSuggestDismissed=
"setSuggestPopoverDismissed"
/>
/>
</div>
</div>
</
template
>
</
template
>
app/assets/javascripts/diffs/index.js
View file @
d2fd6bd5
...
@@ -72,6 +72,8 @@ export default function initDiffsApp(store) {
...
@@ -72,6 +72,8 @@ export default function initDiffsApp(store) {
currentUser
:
JSON
.
parse
(
dataset
.
currentUserData
)
||
{},
currentUser
:
JSON
.
parse
(
dataset
.
currentUserData
)
||
{},
changesEmptyStateIllustration
:
dataset
.
changesEmptyStateIllustration
,
changesEmptyStateIllustration
:
dataset
.
changesEmptyStateIllustration
,
isFluidLayout
:
parseBoolean
(
dataset
.
isFluidLayout
),
isFluidLayout
:
parseBoolean
(
dataset
.
isFluidLayout
),
dismissEndpoint
:
dataset
.
dismissEndpoint
,
showSuggestPopover
:
parseBoolean
(
dataset
.
showSuggestPopover
),
};
};
},
},
computed
:
{
computed
:
{
...
@@ -99,6 +101,8 @@ export default function initDiffsApp(store) {
...
@@ -99,6 +101,8 @@ export default function initDiffsApp(store) {
shouldShow
:
this
.
activeTab
===
'
diffs
'
,
shouldShow
:
this
.
activeTab
===
'
diffs
'
,
changesEmptyStateIllustration
:
this
.
changesEmptyStateIllustration
,
changesEmptyStateIllustration
:
this
.
changesEmptyStateIllustration
,
isFluidLayout
:
this
.
isFluidLayout
,
isFluidLayout
:
this
.
isFluidLayout
,
dismissEndpoint
:
this
.
dismissEndpoint
,
showSuggestPopover
:
this
.
showSuggestPopover
,
},
},
});
});
},
},
...
...
app/assets/javascripts/diffs/store/actions.js
View file @
d2fd6bd5
...
@@ -36,8 +36,8 @@ import {
...
@@ -36,8 +36,8 @@ import {
import
{
diffViewerModes
}
from
'
~/ide/constants
'
;
import
{
diffViewerModes
}
from
'
~/ide/constants
'
;
export
const
setBaseConfig
=
({
commit
},
options
)
=>
{
export
const
setBaseConfig
=
({
commit
},
options
)
=>
{
const
{
endpoint
,
projectPath
}
=
options
;
const
{
endpoint
,
projectPath
,
dismissEndpoint
,
showSuggestPopover
}
=
options
;
commit
(
types
.
SET_BASE_CONFIG
,
{
endpoint
,
projectPath
});
commit
(
types
.
SET_BASE_CONFIG
,
{
endpoint
,
projectPath
,
dismissEndpoint
,
showSuggestPopover
});
};
};
export
const
fetchDiffFiles
=
({
state
,
commit
})
=>
{
export
const
fetchDiffFiles
=
({
state
,
commit
})
=>
{
...
@@ -455,5 +455,17 @@ export const toggleFullDiff = ({ dispatch, getters, state }, filePath) => {
...
@@ -455,5 +455,17 @@ export const toggleFullDiff = ({ dispatch, getters, state }, filePath) => {
export
const
setFileCollapsed
=
({
commit
},
{
filePath
,
collapsed
})
=>
export
const
setFileCollapsed
=
({
commit
},
{
filePath
,
collapsed
})
=>
commit
(
types
.
SET_FILE_COLLAPSED
,
{
filePath
,
collapsed
});
commit
(
types
.
SET_FILE_COLLAPSED
,
{
filePath
,
collapsed
});
export
const
setSuggestPopoverDismissed
=
({
commit
,
state
})
=>
axios
.
post
(
state
.
dismissEndpoint
,
{
feature_name
:
'
suggest_popover_dismissed
'
,
})
.
then
(()
=>
{
commit
(
types
.
SET_SHOW_SUGGEST_POPOVER
);
})
.
catch
(()
=>
{
createFlash
(
s__
(
'
MergeRequest|Error dismissing suggestion popover. Please try again.
'
));
});
// prevent babel-plugin-rewire from generating an invalid default during karma tests
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export
default
()
=>
{};
export
default
()
=>
{};
app/assets/javascripts/diffs/store/modules/diff_state.js
View file @
d2fd6bd5
...
@@ -28,4 +28,6 @@ export default () => ({
...
@@ -28,4 +28,6 @@ export default () => ({
renderTreeList
:
true
,
renderTreeList
:
true
,
showWhitespace
:
true
,
showWhitespace
:
true
,
fileFinderVisible
:
false
,
fileFinderVisible
:
false
,
dismissEndpoint
:
''
,
showSuggestPopover
:
true
,
});
});
app/assets/javascripts/diffs/store/mutation_types.js
View file @
d2fd6bd5
...
@@ -33,3 +33,5 @@ export const SET_HIDDEN_VIEW_DIFF_FILE_LINES = 'SET_HIDDEN_VIEW_DIFF_FILE_LINES'
...
@@ -33,3 +33,5 @@ export const SET_HIDDEN_VIEW_DIFF_FILE_LINES = 'SET_HIDDEN_VIEW_DIFF_FILE_LINES'
export
const
SET_CURRENT_VIEW_DIFF_FILE_LINES
=
'
SET_CURRENT_VIEW_DIFF_FILE_LINES
'
;
export
const
SET_CURRENT_VIEW_DIFF_FILE_LINES
=
'
SET_CURRENT_VIEW_DIFF_FILE_LINES
'
;
export
const
ADD_CURRENT_VIEW_DIFF_FILE_LINES
=
'
ADD_CURRENT_VIEW_DIFF_FILE_LINES
'
;
export
const
ADD_CURRENT_VIEW_DIFF_FILE_LINES
=
'
ADD_CURRENT_VIEW_DIFF_FILE_LINES
'
;
export
const
TOGGLE_DIFF_FILE_RENDERING_MORE
=
'
TOGGLE_DIFF_FILE_RENDERING_MORE
'
;
export
const
TOGGLE_DIFF_FILE_RENDERING_MORE
=
'
TOGGLE_DIFF_FILE_RENDERING_MORE
'
;
export
const
SET_SHOW_SUGGEST_POPOVER
=
'
SET_SHOW_SUGGEST_POPOVER
'
;
app/assets/javascripts/diffs/store/mutations.js
View file @
d2fd6bd5
...
@@ -11,8 +11,8 @@ import * as types from './mutation_types';
...
@@ -11,8 +11,8 @@ import * as types from './mutation_types';
export
default
{
export
default
{
[
types
.
SET_BASE_CONFIG
](
state
,
options
)
{
[
types
.
SET_BASE_CONFIG
](
state
,
options
)
{
const
{
endpoint
,
projectPath
}
=
options
;
const
{
endpoint
,
projectPath
,
dismissEndpoint
,
showSuggestPopover
}
=
options
;
Object
.
assign
(
state
,
{
endpoint
,
projectPath
});
Object
.
assign
(
state
,
{
endpoint
,
projectPath
,
dismissEndpoint
,
showSuggestPopover
});
},
},
[
types
.
SET_LOADING
](
state
,
isLoading
)
{
[
types
.
SET_LOADING
](
state
,
isLoading
)
{
...
@@ -302,4 +302,7 @@ export default {
...
@@ -302,4 +302,7 @@ export default {
file
.
renderingLines
=
!
file
.
renderingLines
;
file
.
renderingLines
=
!
file
.
renderingLines
;
},
},
[
types
.
SET_SHOW_SUGGEST_POPOVER
](
state
)
{
state
.
showSuggestPopover
=
false
;
},
};
};
app/assets/javascripts/notes/components/note_form.vue
View file @
d2fd6bd5
...
@@ -77,6 +77,11 @@ export default {
...
@@ -77,6 +77,11 @@ export default {
required
:
false
,
required
:
false
,
default
:
''
,
default
:
''
,
},
},
showSuggestPopover
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
},
data
()
{
data
()
{
let
updatedNoteBody
=
this
.
noteBody
;
let
updatedNoteBody
=
this
.
noteBody
;
...
@@ -247,6 +252,8 @@ export default {
...
@@ -247,6 +252,8 @@ export default {
:can-suggest=
"canSuggest"
:can-suggest=
"canSuggest"
:add-spacing-classes=
"false"
:add-spacing-classes=
"false"
:help-page-path=
"helpPagePath"
:help-page-path=
"helpPagePath"
:show-suggest-popover=
"showSuggestPopover"
@
handleSuggestDismissed=
"() => $emit('handleSuggestDismissed')"
>
>
<textarea
<textarea
id=
"note_note"
id=
"note_note"
...
@@ -303,7 +310,7 @@ export default {
...
@@ -303,7 +310,7 @@ export default {
{{ __('Add comment now') }}
{{ __('Add comment now') }}
</button>
</button>
<button
<button
class=
"btn
btn-cancel
note-edit-cancel js-close-discussion-note-form"
class=
"btn note-edit-cancel js-close-discussion-note-form"
type=
"button"
type=
"button"
@
click=
"cancelHandler()"
@
click=
"cancelHandler()"
>
>
...
...
app/assets/javascripts/vue_shared/components/markdown/field.vue
View file @
d2fd6bd5
...
@@ -67,6 +67,11 @@ export default {
...
@@ -67,6 +67,11 @@ export default {
required
:
false
,
required
:
false
,
default
:
''
,
default
:
''
,
},
},
showSuggestPopover
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
},
data
()
{
data
()
{
return
{
return
{
...
@@ -194,8 +199,10 @@ export default {
...
@@ -194,8 +199,10 @@ export default {
:preview-markdown=
"previewMarkdown"
:preview-markdown=
"previewMarkdown"
:line-content=
"lineContent"
:line-content=
"lineContent"
:can-suggest=
"canSuggest"
:can-suggest=
"canSuggest"
:show-suggest-popover=
"showSuggestPopover"
@
preview-markdown=
"showPreviewTab"
@
preview-markdown=
"showPreviewTab"
@
write-markdown=
"showWriteTab"
@
write-markdown=
"showWriteTab"
@
handleSuggestDismissed=
"() => $emit('handleSuggestDismissed')"
/>
/>
<div
v-show=
"!previewMarkdown"
class=
"md-write-holder"
>
<div
v-show=
"!previewMarkdown"
class=
"md-write-holder"
>
<div
class=
"zen-backdrop"
>
<div
class=
"zen-backdrop"
>
...
...
app/assets/javascripts/vue_shared/components/markdown/header.vue
View file @
d2fd6bd5
<
script
>
<
script
>
import
$
from
'
jquery
'
;
import
$
from
'
jquery
'
;
import
{
GlTooltipDirective
}
from
'
@gitlab/ui
'
;
import
{
Gl
Popover
,
GlButton
,
Gl
TooltipDirective
}
from
'
@gitlab/ui
'
;
import
ToolbarButton
from
'
./toolbar_button.vue
'
;
import
ToolbarButton
from
'
./toolbar_button.vue
'
;
import
Icon
from
'
../icon.vue
'
;
import
Icon
from
'
../icon.vue
'
;
...
@@ -8,6 +8,8 @@ export default {
...
@@ -8,6 +8,8 @@ export default {
components
:
{
components
:
{
ToolbarButton
,
ToolbarButton
,
Icon
,
Icon
,
GlPopover
,
GlButton
,
},
},
directives
:
{
directives
:
{
GlTooltip
:
GlTooltipDirective
,
GlTooltip
:
GlTooltipDirective
,
...
@@ -27,6 +29,11 @@ export default {
...
@@ -27,6 +29,11 @@ export default {
required
:
false
,
required
:
false
,
default
:
true
,
default
:
true
,
},
},
showSuggestPopover
:
{
type
:
Boolean
,
required
:
false
,
default
:
false
,
},
},
},
computed
:
{
computed
:
{
mdTable
()
{
mdTable
()
{
...
@@ -70,6 +77,9 @@ export default {
...
@@ -70,6 +77,9 @@ export default {
this
.
$emit
(
'
write-markdown
'
);
this
.
$emit
(
'
write-markdown
'
);
},
},
handleSuggestDismissed
()
{
this
.
$emit
(
'
handleSuggestDismissed
'
);
},
},
},
};
};
</
script
>
</
script
>
...
@@ -93,66 +103,92 @@ export default {
...
@@ -93,66 +103,92 @@ export default {
</button>
</button>
</li>
</li>
<li
:class=
"
{ active: !previewMarkdown }" class="md-header-toolbar">
<li
:class=
"
{ active: !previewMarkdown }" class="md-header-toolbar">
<toolbar-button
tag=
"**"
:button-title=
"__('Add bold text')"
icon=
"bold"
/>
<div
class=
"d-inline-block"
>
<toolbar-button
tag=
"*"
:button-title=
"__('Add italic text')"
icon=
"italic"
/>
<toolbar-button
tag=
"**"
:button-title=
"__('Add bold text')"
icon=
"bold"
/>
<toolbar-button
<toolbar-button
tag=
"*"
:button-title=
"__('Add italic text')"
icon=
"italic"
/>
:prepend=
"true"
<toolbar-button
tag=
"> "
:prepend=
"true"
:button-title=
"__('Insert a quote')"
tag=
"> "
icon=
"quote"
:button-title=
"__('Insert a quote')"
/>
icon=
"quote"
<toolbar-button
tag=
"`"
tag-block=
"```"
:button-title=
"__('Insert code')"
icon=
"code"
/>
/>
<toolbar-button
</div>
tag=
"[
{text}](url)"
<div
class=
"d-inline-block ml-md-2 ml-0"
>
tag-select="url"
<template
v-if=
"canSuggest"
>
:button-title="__('Add a link')"
<toolbar-button
icon="link"
ref=
"suggestButton"
/>
:tag=
"mdSuggestion"
<toolbar-button
:prepend=
"true"
:prepend=
"true"
:button-title=
"__('Insert suggestion')"
tag=
"* "
:cursor-offset=
"4"
:button-title=
"__('Add a bullet list')"
:tag-content=
"lineContent"
icon=
"list-bulleted"
icon=
"doc-code"
/>
class=
"qa-suggestion-btn"
<toolbar-button
@
click=
"handleSuggestDismissed"
:prepend=
"true"
/>
tag=
"1. "
<gl-popover
:button-title=
"__('Add a numbered list')"
v-if=
"showSuggestPopover"
icon=
"list-numbered"
:target=
"() => $refs.suggestButton"
/>
:css-classes=
"['diff-suggest-popover']"
<toolbar-button
placement=
"bottom"
:prepend=
"true"
:show=
"showSuggestPopover"
tag=
"* [ ] "
>
:button-title=
"__('Add a task list')"
<strong>
{{
__
(
'
New! Suggest changes directly
'
)
}}
</strong>
icon=
"task-done"
<p
class=
"mb-2"
>
/>
{{
__
(
'
Suggest code changes which are immediately applied. Try it out!
'
)
}}
<toolbar-button
</p>
:tag=
"mdTable"
<gl-button
variant=
"primary"
size=
"sm"
@
click=
"handleSuggestDismissed"
>
:prepend=
"true"
{{
__
(
'
Got it
'
)
}}
:button-title=
"__('Add a table')"
</gl-button>
icon=
"table"
</gl-popover>
/>
</
template
>
<toolbar-button
<toolbar-button
tag=
"`"
tag-block=
"```"
:button-title=
"__('Insert code')"
icon=
"code"
/>
v-if=
"canSuggest"
<toolbar-button
:tag=
"mdSuggestion"
tag=
"[{text}](url)"
:prepend=
"true"
tag-select=
"url"
:button-title=
"__('Insert suggestion')"
:button-title=
"__('Add a link')"
:cursor-offset=
"4"
icon=
"link"
:tag-content=
"lineContent"
/>
icon=
"doc-code"
</div>
class=
"qa-suggestion-btn"
<div
class=
"d-inline-block ml-md-2 ml-0"
>
/>
<toolbar-button
<button
:prepend=
"true"
v-gl-tooltip
tag=
"* "
:aria-label=
"__('Go full screen')"
:button-title=
"__('Add a bullet list')"
class=
"toolbar-btn toolbar-fullscreen-btn js-zen-enter"
icon=
"list-bulleted"
data-container=
"body"
/>
tabindex=
"-1"
<toolbar-button
:title=
"__('Go full screen')"
:prepend=
"true"
type=
"button"
tag=
"1. "
>
:button-title=
"__('Add a numbered list')"
<icon
name=
"screen-full"
/>
icon=
"list-numbered"
</button>
/>
<toolbar-button
:prepend=
"true"
tag=
"* [ ] "
:button-title=
"__('Add a task list')"
icon=
"task-done"
/>
<toolbar-button
:tag=
"mdTable"
:prepend=
"true"
:button-title=
"__('Add a table')"
icon=
"table"
/>
</div>
<div
class=
"d-inline-block ml-md-2 ml-0"
>
<button
v-gl-tooltip
:aria-label=
"__('Go full screen')"
class=
"toolbar-btn toolbar-fullscreen-btn js-zen-enter"
data-container=
"body"
tabindex=
"-1"
:title=
"__('Go full screen')"
type=
"button"
>
<icon
name=
"screen-full"
/>
</button>
</div>
</li>
</li>
</ul>
</ul>
</div>
</div>
...
...
app/assets/javascripts/vue_shared/components/markdown/toolbar_button.vue
View file @
d2fd6bd5
...
@@ -66,6 +66,7 @@ export default {
...
@@ -66,6 +66,7 @@ export default {
class=
"toolbar-btn js-md"
class=
"toolbar-btn js-md"
tabindex=
"-1"
tabindex=
"-1"
data-container=
"body"
data-container=
"body"
@
click=
"() => $emit('click')"
>
>
<icon
:name=
"icon"
/>
<icon
:name=
"icon"
/>
</button>
</button>
...
...
app/assets/stylesheets/framework/markdown_area.scss
View file @
d2fd6bd5
...
@@ -154,11 +154,9 @@
...
@@ -154,11 +154,9 @@
}
}
.toolbar-fullscreen-btn
{
.toolbar-fullscreen-btn
{
margin-left
:
$gl-padding
;
margin-right
:
-5px
;
margin-right
:
-5px
;
@include
media-breakpoint-down
(
xs
)
{
@include
media-breakpoint-down
(
xs
)
{
margin-left
:
0
;
margin-right
:
0
;
margin-right
:
0
;
}
}
}
}
...
...
app/assets/stylesheets/pages/diff.scss
View file @
d2fd6bd5
...
@@ -14,7 +14,7 @@
...
@@ -14,7 +14,7 @@
position
:
-
webkit-sticky
;
position
:
-
webkit-sticky
;
position
:
sticky
;
position
:
sticky
;
top
:
$mr-file-header-top
;
top
:
$mr-file-header-top
;
z-index
:
102
;
z-index
:
220
;
&
:
:
before
{
&
:
:
before
{
content
:
''
;
content
:
''
;
...
@@ -1122,3 +1122,15 @@ table.code {
...
@@ -1122,3 +1122,15 @@ table.code {
outline
:
0
;
outline
:
0
;
}
}
}
}
.diff-suggest-popover
{
&
.popover
{
width
:
250px
;
min-width
:
250px
;
z-index
:
210
;
}
.popover-header
{
display
:
none
;
}
}
app/helpers/user_callouts_helper.rb
View file @
d2fd6bd5
...
@@ -3,6 +3,7 @@
...
@@ -3,6 +3,7 @@
module
UserCalloutsHelper
module
UserCalloutsHelper
GKE_CLUSTER_INTEGRATION
=
'gke_cluster_integration'
.
freeze
GKE_CLUSTER_INTEGRATION
=
'gke_cluster_integration'
.
freeze
GCP_SIGNUP_OFFER
=
'gcp_signup_offer'
.
freeze
GCP_SIGNUP_OFFER
=
'gcp_signup_offer'
.
freeze
SUGGEST_POPOVER_DISMISSED
=
'suggest_popover_dismissed'
.
freeze
def
show_gke_cluster_integration_callout?
(
project
)
def
show_gke_cluster_integration_callout?
(
project
)
can?
(
current_user
,
:create_cluster
,
project
)
&&
can?
(
current_user
,
:create_cluster
,
project
)
&&
...
@@ -20,6 +21,10 @@ module UserCalloutsHelper
...
@@ -20,6 +21,10 @@ module UserCalloutsHelper
def
render_dashboard_gold_trial
(
user
)
def
render_dashboard_gold_trial
(
user
)
end
end
def
show_suggest_popover?
!
user_dismissed?
(
SUGGEST_POPOVER_DISMISSED
)
end
private
private
def
user_dismissed?
(
feature_name
)
def
user_dismissed?
(
feature_name
)
...
...
app/models/user_callout_enums.rb
View file @
d2fd6bd5
...
@@ -10,7 +10,8 @@ module UserCalloutEnums
...
@@ -10,7 +10,8 @@ module UserCalloutEnums
{
{
gke_cluster_integration:
1
,
gke_cluster_integration:
1
,
gcp_signup_offer:
2
,
gcp_signup_offer:
2
,
cluster_security_warning:
3
cluster_security_warning:
3
,
suggest_popover_dismissed:
4
}
}
end
end
end
end
app/views/projects/merge_requests/show.html.haml
View file @
d2fd6bd5
...
@@ -80,7 +80,9 @@
...
@@ -80,7 +80,9 @@
current_user_data:
UserSerializer
.
new
(
project:
@project
).
represent
(
current_user
,
{},
MergeRequestUserEntity
).
to_json
,
current_user_data:
UserSerializer
.
new
(
project:
@project
).
represent
(
current_user
,
{},
MergeRequestUserEntity
).
to_json
,
project_path:
project_path
(
@merge_request
.
project
),
project_path:
project_path
(
@merge_request
.
project
),
changes_empty_state_illustration:
image_path
(
'illustrations/merge_request_changes_empty.svg'
),
changes_empty_state_illustration:
image_path
(
'illustrations/merge_request_changes_empty.svg'
),
is_fluid_layout:
fluid_layout
.
to_s
}
}
is_fluid_layout:
fluid_layout
.
to_s
,
dismiss_endpoint:
user_callouts_path
,
show_suggest_popover:
show_suggest_popover?
.
to_s
}
}
.mr-loading-status
.mr-loading-status
=
spinner
=
spinner
...
...
changelogs/unreleased/diff-suggestions-popover.yml
0 → 100644
View file @
d2fd6bd5
---
title
:
Added diff suggestion feature discovery popover
merge_request
:
author
:
type
:
added
locale/gitlab.pot
View file @
d2fd6bd5
...
@@ -4761,6 +4761,9 @@ msgstr ""
...
@@ -4761,6 +4761,9 @@ msgstr ""
msgid "Google authentication is not %{link_to_documentation}. Ask your GitLab administrator if you want to use this service."
msgid "Google authentication is not %{link_to_documentation}. Ask your GitLab administrator if you want to use this service."
msgstr ""
msgstr ""
msgid "Got it"
msgstr ""
msgid "Got it!"
msgid "Got it!"
msgstr ""
msgstr ""
...
@@ -6153,6 +6156,9 @@ msgstr ""
...
@@ -6153,6 +6156,9 @@ msgstr ""
msgid "MergeRequest| %{paragraphStart}changed the description %{descriptionChangedTimes} times %{timeDifferenceMinutes}%{paragraphEnd}"
msgid "MergeRequest| %{paragraphStart}changed the description %{descriptionChangedTimes} times %{timeDifferenceMinutes}%{paragraphEnd}"
msgstr ""
msgstr ""
msgid "MergeRequest|Error dismissing suggestion popover. Please try again."
msgstr ""
msgid "MergeRequest|Error loading full diff. Please try again."
msgid "MergeRequest|Error loading full diff. Please try again."
msgstr ""
msgstr ""
...
@@ -6509,6 +6515,9 @@ msgstr ""
...
@@ -6509,6 +6515,9 @@ msgstr ""
msgid "New users set to external"
msgid "New users set to external"
msgstr ""
msgstr ""
msgid "New! Suggest changes directly"
msgstr ""
msgid "New..."
msgid "New..."
msgstr ""
msgstr ""
...
@@ -9643,6 +9652,9 @@ msgstr ""
...
@@ -9643,6 +9652,9 @@ msgstr ""
msgid "Successfully unlocked"
msgid "Successfully unlocked"
msgstr ""
msgstr ""
msgid "Suggest code changes which are immediately applied. Try it out!"
msgstr ""
msgid "Suggested change"
msgid "Suggested change"
msgstr ""
msgstr ""
...
...
spec/features/issues/markdown_toolbar_spec.rb
View file @
d2fd6bd5
...
@@ -32,7 +32,7 @@ describe 'Issue markdown toolbar', :js do
...
@@ -32,7 +32,7 @@ describe 'Issue markdown toolbar', :js do
find
(
'.js-main-target-form #note-body'
)
find
(
'.js-main-target-form #note-body'
)
page
.
evaluate_script
(
'document.querySelectorAll(".js-main-target-form #note-body")[0].setSelectionRange(4, 50)'
)
page
.
evaluate_script
(
'document.querySelectorAll(".js-main-target-form #note-body")[0].setSelectionRange(4, 50)'
)
find
(
'.toolbar-btn:nth-child(2)'
)
.
click
all
(
'.toolbar-btn'
)[
1
]
.
click
expect
(
find
(
'#note-body'
)[
:value
]).
to
eq
(
"test
\n
*underline*
\n
"
)
expect
(
find
(
'#note-body'
)[
:value
]).
to
eq
(
"test
\n
*underline*
\n
"
)
end
end
...
...
spec/features/merge_request/user_posts_notes_spec.rb
View file @
d2fd6bd5
...
@@ -141,7 +141,7 @@ describe 'Merge request > User posts notes', :js do
...
@@ -141,7 +141,7 @@ describe 'Merge request > User posts notes', :js do
page
.
within
(
'.current-note-edit-form'
)
do
page
.
within
(
'.current-note-edit-form'
)
do
expect
(
find
(
'#note_note'
).
value
).
to
eq
(
'This is the new content'
)
expect
(
find
(
'#note_note'
).
value
).
to
eq
(
'This is the new content'
)
fi
nd
(
'.js-md:first-chil
d'
).
click
fi
rst
(
'.js-m
d'
).
click
expect
(
find
(
'#note_note'
).
value
).
to
eq
(
'This is the new content****'
)
expect
(
find
(
'#note_note'
).
value
).
to
eq
(
'This is the new content****'
)
end
end
end
end
...
...
spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
View file @
d2fd6bd5
...
@@ -28,6 +28,18 @@ describe 'User comments on a diff', :js do
...
@@ -28,6 +28,18 @@ describe 'User comments on a diff', :js do
end
end
context
'single suggestion note'
do
context
'single suggestion note'
do
it
'hides suggestion popover'
do
click_diff_line
(
find
(
"[id='
#{
sample_compare
.
changes
[
1
][
:line_code
]
}
']"
))
expect
(
page
).
to
have_selector
(
'.diff-suggest-popover'
)
page
.
within
(
'.diff-suggest-popover'
)
do
click_button
'Got it'
end
expect
(
page
).
not_to
have_selector
(
'.diff-suggest-popover'
)
end
it
'suggestion is presented'
do
it
'suggestion is presented'
do
click_diff_line
(
find
(
"[id='
#{
sample_compare
.
changes
[
1
][
:line_code
]
}
']"
))
click_diff_line
(
find
(
"[id='
#{
sample_compare
.
changes
[
1
][
:line_code
]
}
']"
))
...
...
spec/javascripts/diffs/components/app_spec.js
View file @
d2fd6bd5
...
@@ -37,6 +37,8 @@ describe('diffs/components/app', () => {
...
@@ -37,6 +37,8 @@ describe('diffs/components/app', () => {
projectPath
:
'
namespace/project
'
,
projectPath
:
'
namespace/project
'
,
currentUser
:
{},
currentUser
:
{},
changesEmptyStateIllustration
:
''
,
changesEmptyStateIllustration
:
''
,
dismissEndpoint
:
''
,
showSuggestPopover
:
true
,
...
props
,
...
props
,
},
},
store
,
store
,
...
...
spec/javascripts/diffs/store/actions_spec.js
View file @
d2fd6bd5
...
@@ -37,6 +37,7 @@ import actions, {
...
@@ -37,6 +37,7 @@ import actions, {
toggleFullDiff
,
toggleFullDiff
,
setFileCollapsed
,
setFileCollapsed
,
setExpandedDiffLines
,
setExpandedDiffLines
,
setSuggestPopoverDismissed
,
}
from
'
~/diffs/store/actions
'
;
}
from
'
~/diffs/store/actions
'
;
import
eventHub
from
'
~/notes/event_hub
'
;
import
eventHub
from
'
~/notes/event_hub
'
;
import
*
as
types
from
'
~/diffs/store/mutation_types
'
;
import
*
as
types
from
'
~/diffs/store/mutation_types
'
;
...
@@ -68,12 +69,19 @@ describe('DiffsStoreActions', () => {
...
@@ -68,12 +69,19 @@ describe('DiffsStoreActions', () => {
it
(
'
should set given endpoint and project path
'
,
done
=>
{
it
(
'
should set given endpoint and project path
'
,
done
=>
{
const
endpoint
=
'
/diffs/set/endpoint
'
;
const
endpoint
=
'
/diffs/set/endpoint
'
;
const
projectPath
=
'
/root/project
'
;
const
projectPath
=
'
/root/project
'
;
const
dismissEndpoint
=
'
/-/user_callouts
'
;
const
showSuggestPopover
=
false
;
testAction
(
testAction
(
setBaseConfig
,
setBaseConfig
,
{
endpoint
,
projectPath
},
{
endpoint
,
projectPath
,
dismissEndpoint
,
showSuggestPopover
},
{
endpoint
:
''
,
projectPath
:
''
},
{
endpoint
:
''
,
projectPath
:
''
,
dismissEndpoint
:
''
,
showSuggestPopover
:
true
},
[{
type
:
types
.
SET_BASE_CONFIG
,
payload
:
{
endpoint
,
projectPath
}
}],
[
{
type
:
types
.
SET_BASE_CONFIG
,
payload
:
{
endpoint
,
projectPath
,
dismissEndpoint
,
showSuggestPopover
},
},
],
[],
[],
done
,
done
,
);
);
...
@@ -1080,4 +1088,30 @@ describe('DiffsStoreActions', () => {
...
@@ -1080,4 +1088,30 @@ describe('DiffsStoreActions', () => {
);
);
});
});
});
});
describe
(
'
setSuggestPopoverDismissed
'
,
()
=>
{
it
(
'
commits SET_SHOW_SUGGEST_POPOVER
'
,
done
=>
{
const
state
=
{
dismissEndpoint
:
`
${
gl
.
TEST_HOST
}
/-/user_callouts`
};
const
mock
=
new
MockAdapter
(
axios
);
mock
.
onPost
(
state
.
dismissEndpoint
).
reply
(
200
,
{});
spyOn
(
axios
,
'
post
'
).
and
.
callThrough
();
testAction
(
setSuggestPopoverDismissed
,
null
,
state
,
[{
type
:
types
.
SET_SHOW_SUGGEST_POPOVER
}],
[],
()
=>
{
expect
(
axios
.
post
).
toHaveBeenCalledWith
(
state
.
dismissEndpoint
,
{
feature_name
:
'
suggest_popover_dismissed
'
,
});
mock
.
restore
();
done
();
},
);
});
});
});
});
spec/javascripts/diffs/store/mutations_spec.js
View file @
d2fd6bd5
...
@@ -850,4 +850,14 @@ describe('DiffsStoreMutations', () => {
...
@@ -850,4 +850,14 @@ describe('DiffsStoreMutations', () => {
expect
(
file
.
renderingLines
).
toBe
(
false
);
expect
(
file
.
renderingLines
).
toBe
(
false
);
});
});
});
});
describe
(
'
SET_SHOW_SUGGEST_POPOVER
'
,
()
=>
{
it
(
'
sets showSuggestPopover to false
'
,
()
=>
{
const
state
=
{
showSuggestPopover
:
true
};
mutations
[
types
.
SET_SHOW_SUGGEST_POPOVER
](
state
);
expect
(
state
.
showSuggestPopover
).
toBe
(
false
);
});
});
});
});
spec/javascripts/vue_shared/components/markdown/header_spec.js
View file @
d2fd6bd5
...
@@ -22,13 +22,13 @@ describe('Markdown field header component', () => {
...
@@ -22,13 +22,13 @@ describe('Markdown field header component', () => {
'
Add bold text
'
,
'
Add bold text
'
,
'
Add italic text
'
,
'
Add italic text
'
,
'
Insert a quote
'
,
'
Insert a quote
'
,
'
Insert suggestion
'
,
'
Insert code
'
,
'
Insert code
'
,
'
Add a link
'
,
'
Add a link
'
,
'
Add a bullet list
'
,
'
Add a bullet list
'
,
'
Add a numbered list
'
,
'
Add a numbered list
'
,
'
Add a task list
'
,
'
Add a task list
'
,
'
Add a table
'
,
'
Add a table
'
,
'
Insert suggestion
'
,
'
Go full screen
'
,
'
Go full screen
'
,
];
];
const
elements
=
vm
.
$el
.
querySelectorAll
(
'
.toolbar-btn
'
);
const
elements
=
vm
.
$el
.
querySelectorAll
(
'
.toolbar-btn
'
);
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment