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
75044a7f
Commit
75044a7f
authored
Dec 07, 2020
by
Brett Walker
Committed by
sstern
Jan 12, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add copy email to issue sidebar
Add ability for a user to copy email to clipboard from the sidebar
parent
cf4abe87
Changes
10
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
330 additions
and
167 deletions
+330
-167
app/assets/javascripts/sidebar/components/copy_email_to_clipboard.vue
...avascripts/sidebar/components/copy_email_to_clipboard.vue
+43
-0
app/assets/javascripts/sidebar/mount_sidebar.js
app/assets/javascripts/sidebar/mount_sidebar.js
+17
-0
app/assets/stylesheets/framework/sidebar.scss
app/assets/stylesheets/framework/sidebar.scss
+13
-0
app/views/shared/issuable/_sidebar.html.haml
app/views/shared/issuable/_sidebar.html.haml
+4
-0
changelogs/unreleased/ss-copy-clipboard-email.yml
changelogs/unreleased/ss-copy-clipboard-email.yml
+5
-0
doc/user/project/issues/issue_data_and_actions.md
doc/user/project/issues/issue_data_and_actions.md
+7
-0
locale/gitlab.pot
locale/gitlab.pot
+6
-0
spec/features/issues/issue_sidebar_spec.rb
spec/features/issues/issue_sidebar_spec.rb
+191
-167
spec/frontend/sidebar/components/copy_email_to_clipboard_spec.js
...ontend/sidebar/components/copy_email_to_clipboard_spec.js
+22
-0
spec/frontend/vue_shared/components/clipboard_button_spec.js
spec/frontend/vue_shared/components/clipboard_button_spec.js
+22
-0
No files found.
app/assets/javascripts/sidebar/components/copy_email_to_clipboard.vue
0 → 100644
View file @
75044a7f
<
script
>
import
{
s__
,
__
,
sprintf
}
from
'
~/locale
'
;
import
ClipboardButton
from
'
~/vue_shared/components/clipboard_button.vue
'
;
export
default
{
i18n
:
{
copyEmail
:
__
(
'
Copy email address
'
),
},
components
:
{
ClipboardButton
,
},
props
:
{
copyText
:
{
type
:
String
,
required
:
true
,
},
},
computed
:
{
emailText
()
{
return
sprintf
(
s__
(
'
RightSidebar|Issue email: %{copyText}
'
),
{
copyText
:
this
.
copyText
});
},
},
};
</
script
>
<
template
>
<div
data-qa-selector=
"copy-forward-email"
class=
"copy-email-address gl-display-flex gl-align-items-center gl-justify-content-space-between"
>
<span
class=
"gl-overflow-hidden gl-text-overflow-ellipsis gl-white-space-nowrap hide-collapsed gl-w-85p"
>
{{
emailText
}}
</span
>
<clipboard-button
class=
"copy-email-button gl-bg-none!"
category=
"tertiary"
:title=
"$options.i18n.copyEmail"
:text=
"copyText"
tooltip-placement=
"left"
/>
</div>
</
template
>
app/assets/javascripts/sidebar/mount_sidebar.js
View file @
75044a7f
...
...
@@ -12,6 +12,7 @@ import sidebarParticipants from './components/participants/sidebar_participants.
import
sidebarSubscriptions
from
'
./components/subscriptions/sidebar_subscriptions.vue
'
;
import
SidebarSeverity
from
'
./components/severity/sidebar_severity.vue
'
;
import
Translate
from
'
../vue_shared/translate
'
;
import
CopyEmailToClipboard
from
'
./components/copy_email_to_clipboard.vue
'
;
import
createDefaultClient
from
'
~/lib/graphql
'
;
import
{
isInIssuePage
,
isInIncidentPage
,
parseBoolean
}
from
'
~/lib/utils/common_utils
'
;
import
createFlash
from
'
~/flash
'
;
...
...
@@ -272,6 +273,21 @@ function mountSeverityComponent() {
});
}
function
mountCopyEmailComponent
()
{
const
el
=
document
.
getElementById
(
'
issuable-copy-email
'
);
if
(
!
el
)
return
;
const
{
createNoteEmail
}
=
getSidebarOptions
();
// eslint-disable-next-line no-new
new
Vue
({
el
,
render
:
(
createElement
)
=>
createElement
(
CopyEmailToClipboard
,
{
props
:
{
copyText
:
createNoteEmail
}
}),
});
}
export
function
mountSidebar
(
mediator
)
{
mountAssigneesComponent
(
mediator
);
mountReviewersComponent
(
mediator
);
...
...
@@ -279,6 +295,7 @@ export function mountSidebar(mediator) {
mountLockComponent
();
mountParticipantsComponent
(
mediator
);
mountSubscriptionsComponent
(
mediator
);
mountCopyEmailComponent
();
new
SidebarMoveIssue
(
mediator
,
...
...
app/assets/stylesheets/framework/sidebar.scss
View file @
75044a7f
...
...
@@ -58,6 +58,19 @@
height
:
$gl-padding
;
}
}
.copy-email-button
{
// TODO: replace with utility
@include
gl-w-full
;
@include
gl-h-full
;
}
.copy-email-address
{
height
:
60px
;
&
:hover
{
background
:
$gray-100
;
}
}
}
.right-sidebar-expanded
{
...
...
app/views/shared/issuable/_sidebar.html.haml
View file @
75044a7f
...
...
@@ -2,6 +2,7 @@
This should be removed when this sidebar is converted to Vue since assignee data is also available in the `issuable_sidebar` hash
-
issuable_type
=
issuable_sidebar
[
:type
]
-
show_forwarding_email
=
!
issuable_sidebar
[
:create_note_email
].
nil?
-
signed_in
=
!!
issuable_sidebar
.
dig
(
:current_user
,
:id
)
-
can_edit_issuable
=
issuable_sidebar
.
dig
(
:current_user
,
:can_edit
)
-
add_page_startup_api_call
"
#{
issuable_sidebar
[
:issuable_json_path
]
}
?serializer=sidebar_extras"
...
...
@@ -145,6 +146,9 @@
=
_
(
'Source branch: %{source_branch_open}%{source_branch}%{source_branch_close}'
).
html_safe
%
{
source_branch_open:
"<cite class='ref-name' title='
#{
source_branch
}
'>"
.
html_safe
,
source_branch_close:
"</cite>"
.
html_safe
,
source_branch:
source_branch
}
=
clipboard_button
(
text:
source_branch
,
title:
_
(
'Copy branch name'
),
placement:
"left"
,
boundary:
'viewport'
)
-
if
show_forwarding_email
.block
#issuable-copy-email
-
if
issuable_sidebar
.
dig
(
:current_user
,
:can_move
)
.block.js-sidebar-move-issue-block
.sidebar-collapsed-icon
{
data:
{
toggle:
'tooltip'
,
placement:
'left'
,
container:
'body'
,
boundary:
'viewport'
},
title:
_
(
'Move issue'
)
}
...
...
changelogs/unreleased/ss-copy-clipboard-email.yml
0 → 100644
View file @
75044a7f
---
title
:
Add copy email to issue sidebar
merge_request
:
50127
author
:
type
:
added
doc/user/project/issues/issue_data_and_actions.md
View file @
75044a7f
...
...
@@ -35,6 +35,7 @@ The numbers in the image correspond to the following features:
-
**12.**
[
Participants
](
#participants
)
-
**13.**
[
Notifications
](
#notifications
)
-
**14.**
[
Reference
](
#reference
)
-
[
Issue email
](
#email
)
-
**15.**
[
Edit
](
#edit
)
-
**16.**
[
Description
](
#description
)
-
**17.**
[
Mentions
](
#mentions
)
...
...
@@ -174,6 +175,12 @@ for the issue. Notifications are automatically enabled after you participate in
`foo/bar#xxx`
, where
`foo`
is the
`username`
or
`groupname`
,
`bar`
is the
`project-name`
, and
`xxx`
is the issue number.
### Email
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/18816) in GitLab 13.8.
Guest users can see a button to copy the email address for the issue. Sending an email to this address creates a comment containing the email body.
### Edit
Clicking this icon opens the issue for editing. All the fields which
...
...
locale/gitlab.pot
View file @
75044a7f
...
...
@@ -7899,6 +7899,9 @@ msgstr ""
msgid "Copy commit SHA"
msgstr ""
msgid "Copy email address"
msgstr ""
msgid "Copy environment"
msgstr ""
...
...
@@ -24309,6 +24312,9 @@ msgstr ""
msgid "Revoked project access token %{project_access_token_name}!"
msgstr ""
msgid "RightSidebar|Issue email: %{copyText}"
msgstr ""
msgid "RightSidebar|adding a"
msgstr ""
...
...
spec/features/issues/issue_sidebar_spec.rb
View file @
75044a7f
...
...
@@ -12,6 +12,11 @@ RSpec.describe 'Issue Sidebar' do
let
(
:issue
)
{
create
(
:labeled_issue
,
project:
project
,
labels:
[
label
])
}
let!
(
:xss_label
)
{
create
(
:label
,
project:
project
,
title:
'<script>alert("xss");</script>'
)
}
before
do
stub_incoming_email_setting
(
enabled:
true
,
address:
"p+%{key}@gl.ab"
)
end
context
'when signed in'
do
before
do
sign_in
(
user
)
end
...
...
@@ -243,6 +248,12 @@ RSpec.describe 'Issue Sidebar' do
expect
(
page
).
not_to
have_selector
(
'.block.labels .js-sidebar-dropdown-toggle'
)
end
context
'sidebar'
,
:js
do
it
'finds issue copy forwarding email'
do
expect
(
find
(
'[data-qa-selector="copy-forward-email"]'
).
text
).
to
eq
"Issue email:
#{
issue
.
creatable_note_email_address
(
user
)
}
"
end
end
context
'interacting with collapsed sidebar'
,
:js
do
collapsed_sidebar_selector
=
'aside.right-sidebar.right-sidebar-collapsed'
expanded_sidebar_selector
=
'aside.right-sidebar.right-sidebar-expanded'
...
...
@@ -266,6 +277,19 @@ RSpec.describe 'Issue Sidebar' do
end
end
end
end
context
'when not signed in'
do
context
'sidebar'
,
:js
do
before
do
visit_issue
(
project
,
issue
)
end
it
'does not find issue email'
do
expect
(
page
).
not_to
have_selector
(
'[data-qa-selector="copy-forward-email"]'
)
end
end
end
def
visit_issue
(
project
,
issue
)
visit
project_issue_path
(
project
,
issue
)
...
...
spec/frontend/sidebar/components/copy_email_to_clipboard_spec.js
0 → 100644
View file @
75044a7f
import
{
mount
}
from
'
@vue/test-utils
'
;
import
{
getByText
}
from
'
@testing-library/dom
'
;
import
ClipboardButton
from
'
~/vue_shared/components/clipboard_button.vue
'
;
import
CopyEmailToClipboard
from
'
~/sidebar/components/copy_email_to_clipboard.vue
'
;
describe
(
'
CopyEmailToClipboard component
'
,
()
=>
{
const
sampleEmail
=
'
sample+email@test.com
'
;
const
wrapper
=
mount
(
CopyEmailToClipboard
,
{
propsData
:
{
copyText
:
sampleEmail
,
},
});
it
(
'
renders the Issue email text with the forwardable email
'
,
()
=>
{
expect
(
getByText
(
wrapper
.
element
,
`Issue email:
${
sampleEmail
}
`
)).
not
.
toBeNull
();
});
it
(
'
finds ClipboardButton with the correct props
'
,
()
=>
{
expect
(
wrapper
.
find
(
ClipboardButton
).
props
(
'
text
'
)).
toBe
(
sampleEmail
);
});
});
spec/frontend/vue_shared/components/clipboard_button_spec.js
View file @
75044a7f
import
{
mount
}
from
'
@vue/test-utils
'
;
import
{
GlButton
}
from
'
@gitlab/ui
'
;
import
ClipboardButton
from
'
~/vue_shared/components/clipboard_button.vue
'
;
import
initCopyToClipboard
from
'
~/behaviors/copy_to_clipboard
'
;
describe
(
'
clipboard button
'
,
()
=>
{
let
wrapper
;
...
...
@@ -87,4 +88,25 @@ describe('clipboard button', () => {
expect
(
onClick
).
toHaveBeenCalled
();
});
describe
(
'
integration
'
,
()
=>
{
it
(
'
actually copies to clipboard
'
,
()
=>
{
initCopyToClipboard
();
document
.
execCommand
=
()
=>
{};
jest
.
spyOn
(
document
,
'
execCommand
'
).
mockImplementation
(()
=>
true
);
createWrapper
(
{
text
:
'
copy me
'
,
title
:
'
Copy this value
'
,
},
{
attachTo
:
document
.
body
},
);
findButton
().
trigger
(
'
click
'
);
expect
(
document
.
execCommand
).
toHaveBeenCalledWith
(
'
copy
'
);
});
});
});
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