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
340515b7
Commit
340515b7
authored
Aug 16, 2021
by
Brett Walker
Committed by
Natalia Tepluhina
Aug 16, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Display issue type icon on issue creation form
parent
46982343
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
101 additions
and
45 deletions
+101
-45
app/assets/javascripts/issue_show/components/fields/type.vue
app/assets/javascripts/issue_show/components/fields/type.vue
+3
-1
app/assets/javascripts/issue_show/constants.js
app/assets/javascripts/issue_show/constants.js
+2
-2
app/helpers/issues_helper.rb
app/helpers/issues_helper.rb
+8
-0
app/views/shared/issuable/form/_type_selector.html.haml
app/views/shared/issuable/form/_type_selector.html.haml
+3
-3
spec/features/issues/form_spec.rb
spec/features/issues/form_spec.rb
+29
-7
spec/frontend/issue_show/components/fields/type_spec.js
spec/frontend/issue_show/components/fields/type_spec.js
+13
-1
spec/helpers/issues_helper_spec.rb
spec/helpers/issues_helper_spec.rb
+43
-31
No files found.
app/assets/javascripts/issue_show/components/fields/type.vue
View file @
340515b7
<
script
>
import
{
GlFormGroup
,
GlDropdown
,
GlDropdownItem
}
from
'
@gitlab/ui
'
;
import
{
GlFormGroup
,
GlDropdown
,
GlDropdownItem
,
GlIcon
}
from
'
@gitlab/ui
'
;
import
{
capitalize
}
from
'
lodash
'
;
import
{
__
}
from
'
~/locale
'
;
import
{
IssuableTypes
}
from
'
../../constants
'
;
...
...
@@ -15,6 +15,7 @@ export default {
IssuableTypes
,
components
:
{
GlFormGroup
,
GlIcon
,
GlDropdown
,
GlDropdownItem
,
},
...
...
@@ -72,6 +73,7 @@ export default {
is-check-item
@
click=
"updateIssueType(type.value)"
>
<gl-icon
:name=
"type.icon"
/>
{{
type
.
text
}}
</gl-dropdown-item>
</gl-dropdown>
...
...
app/assets/javascripts/issue_show/constants.js
View file @
340515b7
...
...
@@ -28,8 +28,8 @@ export const STATUS_PAGE_PUBLISHED = __('Published on status page');
export
const
JOIN_ZOOM_MEETING
=
__
(
'
Join Zoom meeting
'
);
export
const
IssuableTypes
=
[
{
value
:
'
issue
'
,
text
:
__
(
'
Issue
'
)
},
{
value
:
'
incident
'
,
text
:
__
(
'
Incident
'
)
},
{
value
:
'
issue
'
,
text
:
__
(
'
Issue
'
)
,
icon
:
'
issue-type-issue
'
},
{
value
:
'
incident
'
,
text
:
__
(
'
Incident
'
)
,
icon
:
'
issue-type-incident
'
},
];
export
const
IssueTypePath
=
'
issues
'
;
...
...
app/helpers/issues_helper.rb
View file @
340515b7
...
...
@@ -48,6 +48,14 @@ module IssuesHelper
end
end
def
work_item_type_icon
(
issue_type
)
if
WorkItem
::
Type
.
base_types
.
include?
(
issue_type
)
"issue-type-
#{
issue_type
.
to_s
.
dasherize
}
"
else
'issue-type-issue'
end
end
def
confidential_icon
(
issue
)
sprite_icon
(
'eye-slash'
,
css_class:
'gl-vertical-align-text-bottom'
)
if
issue
.
confidential?
end
...
...
app/views/shared/issuable/form/_type_selector.html.haml
View file @
340515b7
...
...
@@ -16,14 +16,14 @@
=
_
(
"Select type"
)
%button
.dropdown-title-button.dropdown-menu-close.gl-ml-auto
{
type:
'button'
,
"aria-label"
=>
_
(
'Close'
)
}
=
sprite_icon
(
'close'
,
size:
16
,
css_class:
'dropdown-menu-close-icon'
)
.dropdown-content
.dropdown-content
{
data:
{
testid:
'issue-type-select-dropdown'
}
}
%ul
%li
.js-filter-issuable-type
=
link_to
new_project_issue_path
(
@project
),
class:
(
"is-active"
if
issuable
.
issue?
)
do
=
_
(
"Issue"
)
#{
sprite_icon
(
work_item_type_icon
(
:issue
),
css_class:
'gl-icon'
)
}
#{
_
(
"Issue"
)
}
%li
.js-filter-issuable-type
{
data:
{
track:
{
event:
"select_issue_type_incident"
,
label:
"select_issue_type_incident_dropdown_option"
}
}
}
=
link_to
new_project_issue_path
(
@project
,
{
issuable_template:
'incident'
,
issue:
{
issue_type:
'incident'
}
}),
class:
(
"is-active"
if
issuable
.
incident?
)
do
=
_
(
"Incident"
)
#{
sprite_icon
(
work_item_type_icon
(
:incident
),
css_class:
'gl-icon'
)
}
#{
_
(
"Incident"
)
}
#js-type-popover
...
...
spec/features/issues/form_spec.rb
View file @
340515b7
...
...
@@ -6,13 +6,13 @@ RSpec.describe 'New/edit issue', :js do
include
ActionView
::
Helpers
::
JavaScriptHelper
include
FormHelper
let
!
(
:project
)
{
create
(
:project
)
}
let
!
(
:user
)
{
create
(
:user
)}
let
!
(
:user2
)
{
create
(
:user
)}
let
!
(
:milestone
)
{
create
(
:milestone
,
project:
project
)
}
let
!
(
:label
)
{
create
(
:label
,
project:
project
)
}
let
!
(
:label2
)
{
create
(
:label
,
project:
project
)
}
let
!
(
:issue
)
{
create
(
:issue
,
project:
project
,
assignees:
[
user
],
milestone:
milestone
)
}
let
_it_be
(
:project
)
{
create
(
:project
)
}
let
_it_be
(
:user
)
{
create
(
:user
)}
let
_it_be
(
:user2
)
{
create
(
:user
)}
let
_it_be
(
:milestone
)
{
create
(
:milestone
,
project:
project
)
}
let
_it_be
(
:label
)
{
create
(
:label
,
project:
project
)
}
let
_it_be
(
:label2
)
{
create
(
:label
,
project:
project
)
}
let
_it_be
(
:issue
)
{
create
(
:issue
,
project:
project
,
assignees:
[
user
],
milestone:
milestone
)
}
before
do
stub_licensed_features
(
multiple_issue_assignees:
false
,
issue_weights:
false
)
...
...
@@ -234,6 +234,28 @@ RSpec.describe 'New/edit issue', :js do
expect
(
page
).
to
have_selector
(
'.atwho-view'
)
end
describe
'displays issue type options in the dropdown'
do
before
do
page
.
within
(
'.issue-form'
)
do
click_button
'Issue'
end
end
it
'correctly displays the Issue type option with an icon'
,
:aggregate_failures
do
page
.
within
(
'[data-testid="issue-type-select-dropdown"]'
)
do
expect
(
page
).
to
have_selector
(
'[data-testid="issue-type-issue-icon"]'
)
expect
(
page
).
to
have_content
(
'Issue'
)
end
end
it
'correctly displays the Incident type option with an icon'
,
:aggregate_failures
do
page
.
within
(
'[data-testid="issue-type-select-dropdown"]'
)
do
expect
(
page
).
to
have_selector
(
'[data-testid="issue-type-incident-icon"]'
)
expect
(
page
).
to
have_content
(
'Incident'
)
end
end
end
describe
'milestone'
do
let!
(
:milestone
)
{
create
(
:milestone
,
title:
'"><img src=x onerror=alert(document.domain)>'
,
project:
project
)
}
...
...
spec/frontend/issue_show/components/fields/type_spec.js
View file @
340515b7
import
{
GlFormGroup
,
GlDropdown
,
GlDropdownItem
}
from
'
@gitlab/ui
'
;
import
{
GlFormGroup
,
GlDropdown
,
GlDropdownItem
,
GlIcon
}
from
'
@gitlab/ui
'
;
import
{
shallowMount
,
createLocalVue
}
from
'
@vue/test-utils
'
;
import
VueApollo
from
'
vue-apollo
'
;
import
createMockApollo
from
'
helpers/mock_apollo_helper
'
;
...
...
@@ -35,6 +35,9 @@ describe('Issue type field component', () => {
const
findTypeFromGroup
=
()
=>
wrapper
.
findComponent
(
GlFormGroup
);
const
findTypeFromDropDown
=
()
=>
wrapper
.
findComponent
(
GlDropdown
);
const
findTypeFromDropDownItems
=
()
=>
wrapper
.
findAllComponents
(
GlDropdownItem
);
const
findTypeFromDropDownItemAt
=
(
at
)
=>
findTypeFromDropDownItems
().
at
(
at
);
const
findTypeFromDropDownItemIconAt
=
(
at
)
=>
findTypeFromDropDownItems
().
at
(
at
).
findComponent
(
GlIcon
);
const
createComponent
=
({
data
}
=
{})
=>
{
fakeApollo
=
createMockApollo
([],
mockResolvers
);
...
...
@@ -60,6 +63,15 @@ describe('Issue type field component', () => {
wrapper
.
destroy
();
});
it
.
each
`
at | text | icon
${
0
}
|
${
IssuableTypes
[
0
].
text
}
|
${
IssuableTypes
[
0
].
icon
}
${
1
}
|
${
IssuableTypes
[
1
].
text
}
|
${
IssuableTypes
[
1
].
icon
}
`
(
`renders the issue type $text with an icon in the dropdown`
,
({
at
,
text
,
icon
})
=>
{
expect
(
findTypeFromDropDownItemIconAt
(
at
).
attributes
(
'
name
'
)).
toBe
(
icon
);
expect
(
findTypeFromDropDownItemAt
(
at
).
text
()).
toBe
(
text
);
});
it
(
'
renders a form group with the correct label
'
,
()
=>
{
expect
(
findTypeFromGroup
().
attributes
(
'
label
'
)).
toBe
(
i18n
.
label
);
});
...
...
spec/helpers/issues_helper_spec.rb
View file @
340515b7
# frozen_string_literal: true
require
"spec_helper"
require
'spec_helper'
RSpec
.
describe
IssuesHelper
do
let
(
:project
)
{
create
(
:project
)
}
let
(
:issue
)
{
create
:issue
,
project:
project
}
let
(
:ext_project
)
{
create
:redmine_project
}
describe
'#work_item_type_icon'
do
it
'returns icon of all standard base types'
do
WorkItem
::
Type
.
base_types
.
each
do
|
type
|
expect
(
work_item_type_icon
(
type
[
0
])).
to
eq
"issue-type-
#{
type
[
0
].
to_s
.
dasherize
}
"
end
end
it
'defaults to issue icon if type is unknown'
do
expect
(
work_item_type_icon
(
'invalid'
)).
to
eq
'issue-type-issue'
end
end
describe
'#award_user_list'
do
it
"returns a comma-separated list of the first X users"
do
it
'returns a comma-separated list of the first X users'
do
user
=
build_stubbed
(
:user
,
name:
'Joe'
)
awards
=
Array
.
new
(
3
,
build_stubbed
(
:award_emoji
,
user:
user
))
...
...
@@ -24,7 +36,7 @@ RSpec.describe IssuesHelper do
expect
(
award_user_list
([
award
],
nil
)).
to
eq
'Joe'
end
it
"truncates lists"
do
it
'truncates lists'
do
user
=
build_stubbed
(
:user
,
name:
'Jane'
)
awards
=
Array
.
new
(
5
,
build_stubbed
(
:award_emoji
,
user:
user
))
...
...
@@ -32,14 +44,14 @@ RSpec.describe IssuesHelper do
.
to
eq
(
'Jane, Jane, Jane, and 2 more.'
)
end
it
"displays the current user in front of other users"
do
it
'displays the current user in front of other users'
do
current_user
=
build_stubbed
(
:user
)
my_award
=
build_stubbed
(
:award_emoji
,
user:
current_user
)
award
=
build_stubbed
(
:award_emoji
,
user:
build_stubbed
(
:user
,
name:
'Jane'
))
awards
=
Array
.
new
(
5
,
award
).
push
(
my_award
)
expect
(
award_user_list
(
awards
,
current_user
,
limit:
2
))
.
to
eq
(
"You, Jane, and 4 more."
)
.
to
eq
(
'You, Jane, and 4 more.'
)
end
end
...
...
@@ -54,19 +66,19 @@ RSpec.describe IssuesHelper do
end
end
it
"returns disabled string for unauthenticated user"
do
expect
(
helper
.
award_state_class
(
awardable
,
AwardEmoji
.
all
,
nil
)).
to
eq
(
"disabled"
)
it
'returns disabled string for unauthenticated user'
do
expect
(
helper
.
award_state_class
(
awardable
,
AwardEmoji
.
all
,
nil
)).
to
eq
(
'disabled'
)
end
it
"returns disabled for a user that does not have access to the awardable"
do
expect
(
helper
.
award_state_class
(
awardable
,
AwardEmoji
.
all
,
build
(
:user
))).
to
eq
(
"disabled"
)
it
'returns disabled for a user that does not have access to the awardable'
do
expect
(
helper
.
award_state_class
(
awardable
,
AwardEmoji
.
all
,
build
(
:user
))).
to
eq
(
'disabled'
)
end
it
"returns active string for author"
do
expect
(
helper
.
award_state_class
(
awardable
,
AwardEmoji
.
all
,
upvote
.
user
)).
to
eq
(
"active"
)
it
'returns active string for author'
do
expect
(
helper
.
award_state_class
(
awardable
,
AwardEmoji
.
all
,
upvote
.
user
)).
to
eq
(
'active'
)
end
it
"is blank for a user that has access to the awardable"
do
it
'is blank for a user that has access to the awardable'
do
user
=
build
(
:user
)
expect
(
helper
).
to
receive
(
:can?
).
with
(
user
,
:award_emoji
,
awardable
).
and_return
(
true
)
...
...
@@ -74,40 +86,40 @@ RSpec.describe IssuesHelper do
end
end
describe
"awards_sort"
do
it
"sorts a hash so thumbsup and thumbsdown are always on top"
do
data
=
{
"thumbsdown"
=>
"some value"
,
"lifter"
=>
"some value"
,
"thumbsup"
=>
"some value"
}
describe
'awards_sort'
do
it
'sorts a hash so thumbsup and thumbsdown are always on top'
do
data
=
{
'thumbsdown'
=>
'some value'
,
'lifter'
=>
'some value'
,
'thumbsup'
=>
'some value'
}
expect
(
awards_sort
(
data
).
keys
).
to
eq
(
%w(thumbsup thumbsdown lifter)
)
end
end
describe
"#link_to_discussions_to_resolve"
do
describe
"passing only a merge request"
do
describe
'#link_to_discussions_to_resolve'
do
describe
'passing only a merge request'
do
let
(
:merge_request
)
{
create
(
:merge_request
)
}
it
"links just the merge request"
do
it
'links just the merge request'
do
expected_path
=
project_merge_request_path
(
merge_request
.
project
,
merge_request
)
expect
(
link_to_discussions_to_resolve
(
merge_request
,
nil
)).
to
include
(
expected_path
)
end
it
"contains the reference to the merge request"
do
it
'contains the reference to the merge request'
do
expect
(
link_to_discussions_to_resolve
(
merge_request
,
nil
)).
to
include
(
merge_request
.
to_reference
)
end
end
describe
"when passing a discussion"
do
describe
'when passing a discussion'
do
let
(
:diff_note
)
{
create
(
:diff_note_on_merge_request
)
}
let
(
:merge_request
)
{
diff_note
.
noteable
}
let
(
:discussion
)
{
diff_note
.
to_discussion
}
it
"links to the merge request with first note if a single discussion was passed"
do
it
'links to the merge request with first note if a single discussion was passed'
do
expected_path
=
Gitlab
::
UrlBuilder
.
build
(
diff_note
)
expect
(
link_to_discussions_to_resolve
(
merge_request
,
discussion
)).
to
include
(
expected_path
)
end
it
"contains both the reference to the merge request and a mention of the discussion"
do
it
'contains both the reference to the merge request and a mention of the discussion'
do
expect
(
link_to_discussions_to_resolve
(
merge_request
,
discussion
)).
to
include
(
"
#{
merge_request
.
to_reference
}
(discussion
#{
diff_note
.
id
}
)"
)
end
end
...
...
@@ -235,13 +247,13 @@ RSpec.describe IssuesHelper do
end
describe
'#use_startup_call'
do
it
"returns false when a query param is present"
do
it
'returns false when a query param is present'
do
allow
(
controller
.
request
).
to
receive
(
:query_parameters
).
and_return
({
foo:
'bar'
})
expect
(
helper
.
use_startup_call?
).
to
eq
(
false
)
end
it
"returns false when user has stored sort preference"
do
it
'returns false when user has stored sort preference'
do
controller
.
instance_variable_set
(
:@sort
,
'updated_asc'
)
expect
(
helper
.
use_startup_call?
).
to
eq
(
false
)
...
...
@@ -265,13 +277,13 @@ RSpec.describe IssuesHelper do
it
'returns expected result'
do
expected
=
{
can_create_issue:
"true"
,
can_reopen_issue:
"true"
,
can_report_spam:
"false"
,
can_update_issue:
"true"
,
can_create_issue:
'true'
,
can_reopen_issue:
'true'
,
can_report_spam:
'false'
,
can_update_issue:
'true'
,
iid:
issue
.
iid
,
is_issue_author:
"false"
,
issue_type:
"issue"
,
is_issue_author:
'false'
,
issue_type:
'issue'
,
new_issue_path:
new_project_issue_path
(
project
),
project_path:
project
.
full_path
,
report_abuse_path:
new_abuse_report_path
(
user_id:
issue
.
author
.
id
,
ref_url:
issue_url
(
issue
)),
...
...
@@ -345,7 +357,7 @@ RSpec.describe IssuesHelper do
end
it
'returns manual ordering class'
do
expect
(
helper
.
issue_manual_ordering_class
).
to
eq
(
"manual-ordering"
)
expect
(
helper
.
issue_manual_ordering_class
).
to
eq
(
'manual-ordering'
)
end
context
'when manual sorting disabled'
do
...
...
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