Commit bdb6f1e6 authored by Jacob Schatz's avatar Jacob Schatz

Merge branch 'gl-dropdown-issuable-form' into 'master'

GL dropdowns in issuable form

## What does this MR do?

Changed all the issuable dropdown menus over to user GL dropdowns. This brings the dropdowns to be inline with the issuable filter dropdowns and allows for labels to be created whilst creating/editing an issuable.

## What are the relevant issue numbers?

Closes #12574 

## Screenshots (if relevant)


See merge request !4970
parents dfb0b5de afbd631c
...@@ -39,6 +39,8 @@ class Dispatcher ...@@ -39,6 +39,8 @@ class Dispatcher
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
new GLForm($('.issue-form')) new GLForm($('.issue-form'))
new IssuableForm($('.issue-form')) new IssuableForm($('.issue-form'))
new LabelsSelect()
new MilestoneSelect()
when 'projects:merge_requests:new', 'projects:merge_requests:edit' when 'projects:merge_requests:new', 'projects:merge_requests:edit'
new Diff() new Diff()
shortcut_handler = new ShortcutsNavigation() shortcut_handler = new ShortcutsNavigation()
......
...@@ -184,20 +184,22 @@ class @LabelsSelect ...@@ -184,20 +184,22 @@ class @LabelsSelect
.value() .value()
if $dropdown.hasClass 'js-extra-options' if $dropdown.hasClass 'js-extra-options'
if showNo extraData = []
data.unshift(
id: 0
title: 'No Label'
)
if showAny if showAny
data.unshift( extraData.push(
isAny: true isAny: true
title: 'Any Label' title: 'Any Label'
) )
if data.length > 2 if showNo
data.splice 2, 0, 'divider' extraData.push(
id: 0
title: 'No Label'
)
if extraData.length
extraData.push 'divider'
data = extraData.concat(data)
callback data callback data
...@@ -287,6 +289,12 @@ class @LabelsSelect ...@@ -287,6 +289,12 @@ class @LabelsSelect
defaultLabel defaultLabel
fieldName: $dropdown.data('field-name') fieldName: $dropdown.data('field-name')
id: (label) -> id: (label) ->
if $dropdown.hasClass('js-issuable-form-dropdown')
if label.id is 0
return
else
return label.id
if $dropdown.hasClass("js-filter-submit") and not label.isAny? if $dropdown.hasClass("js-filter-submit") and not label.isAny?
label.title label.title
else else
...@@ -300,6 +308,9 @@ class @LabelsSelect ...@@ -300,6 +308,9 @@ class @LabelsSelect
$selectbox.hide() $selectbox.hide()
# display:block overrides the hide-collapse rule # display:block overrides the hide-collapse rule
$value.removeAttr('style') $value.removeAttr('style')
return if $dropdown.hasClass('js-issuable-form-dropdown')
if $dropdown.hasClass 'js-multiselect' if $dropdown.hasClass 'js-multiselect'
if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex) if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
selectedLabels = $dropdown selectedLabels = $dropdown
...@@ -321,7 +332,7 @@ class @LabelsSelect ...@@ -321,7 +332,7 @@ class @LabelsSelect
clicked: (label) -> clicked: (label) ->
_this.enableBulkLabelDropdown() _this.enableBulkLabelDropdown()
if $dropdown.hasClass('js-filter-bulk-update') if $dropdown.hasClass('js-filter-bulk-update') or $dropdown.hasClass('js-issuable-form-dropdown')
return return
page = $('body').data 'page' page = $('body').data 'page'
......
...@@ -62,7 +62,7 @@ class @MilestoneSelect ...@@ -62,7 +62,7 @@ class @MilestoneSelect
title: 'Upcoming' title: 'Upcoming'
) )
if extraOptions.length > 2 if extraOptions.length > 0
extraOptions.push 'divider' extraOptions.push 'divider'
callback(extraOptions.concat(data)) callback(extraOptions.concat(data))
......
...@@ -151,11 +151,13 @@ class @UsersSelect ...@@ -151,11 +151,13 @@ class @UsersSelect
# display:block overrides the hide-collapse rule # display:block overrides the hide-collapse rule
$value.css('display', '') $value.css('display', '')
clicked: (user) -> clicked: (user, $el, e) ->
page = $('body').data 'page' page = $('body').data 'page'
isIssueIndex = page is 'projects:issues:index' isIssueIndex = page is 'projects:issues:index'
isMRIndex = page is page is 'projects:merge_requests:index' isMRIndex = page is page is 'projects:merge_requests:index'
if $dropdown.hasClass('js-filter-bulk-update') if $dropdown.hasClass('js-filter-bulk-update') or $dropdown.hasClass('js-issuable-form-dropdown')
e.preventDefault()
selectedId = user.id
return return
if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex) if $dropdown.hasClass('js-filter-submit') and (isIssueIndex or isMRIndex)
...@@ -168,7 +170,8 @@ class @UsersSelect ...@@ -168,7 +170,8 @@ class @UsersSelect
.closest('.selectbox') .closest('.selectbox')
.find("input[name='#{$dropdown.data('field-name')}']").val() .find("input[name='#{$dropdown.data('field-name')}']").val()
assignTo(selected) assignTo(selected)
id: (user) ->
user.id
renderRow: (user) -> renderRow: (user) ->
username = if user.username then "@#{user.username}" else "" username = if user.username then "@#{user.username}" else ""
avatar = if user.avatar_url then user.avatar_url else false avatar = if user.avatar_url then user.avatar_url else false
......
...@@ -56,7 +56,7 @@ ...@@ -56,7 +56,7 @@
position: absolute; position: absolute;
top: 50%; top: 50%;
right: 6px; right: 6px;
margin-top: -4px; margin-top: -6px;
color: $dropdown-toggle-icon-color; color: $dropdown-toggle-icon-color;
font-size: 10px; font-size: 10px;
} }
......
...@@ -324,6 +324,10 @@ ...@@ -324,6 +324,10 @@
.issuable-form-select-holder { .issuable-form-select-holder {
display: inline-block; display: inline-block;
width: 250px; width: 250px;
.dropdown-menu-toggle {
width: 100%;
}
} }
.table-holder { .table-holder {
......
...@@ -9,7 +9,7 @@ module IssuablesHelper ...@@ -9,7 +9,7 @@ module IssuablesHelper
def multi_label_name(current_labels, default_label) def multi_label_name(current_labels, default_label)
# current_labels may be a string from before # current_labels may be a string from before
if current_labels.is_a?(Array) if current_labels.is_a?(Array) && current_labels.any?
if current_labels.count > 1 if current_labels.count > 1
"#{current_labels[0]} +#{current_labels.count - 1} more" "#{current_labels[0]} +#{current_labels.count - 1} more"
else else
......
...@@ -21,10 +21,10 @@ ...@@ -21,10 +21,10 @@
placeholder: "Search assignee", data: { any_user: "Any Assignee", first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: (@project.id if @project), selected: params[:assignee_id], field_name: "assignee_id", default_label: "Assignee" } }) placeholder: "Search assignee", data: { any_user: "Any Assignee", first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: (@project.id if @project), selected: params[:assignee_id], field_name: "assignee_id", default_label: "Assignee" } })
.filter-item.inline.milestone-filter .filter-item.inline.milestone-filter
= render "shared/issuable/milestone_dropdown" = render "shared/issuable/milestone_dropdown", selected: params[:milestone_title], name: :milestone_title, show_any: true, show_upcoming: true
.filter-item.inline.labels-filter .filter-item.inline.labels-filter
= render "shared/issuable/label_dropdown" = render "shared/issuable/label_dropdown", selected: params[:label_name], data_options: { field_name: "label_name[]" }
.pull-right .pull-right
= render 'shared/sort_dropdown' = render 'shared/sort_dropdown'
......
...@@ -59,38 +59,24 @@ ...@@ -59,38 +59,24 @@
= f.label :assignee_id, "Assignee", class: "control-label #{"col-lg-4" if has_due_date}" = f.label :assignee_id, "Assignee", class: "control-label #{"col-lg-4" if has_due_date}"
.col-sm-10{ class: ("col-lg-8" if has_due_date) } .col-sm-10{ class: ("col-lg-8" if has_due_date) }
.issuable-form-select-holder .issuable-form-select-holder
= users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]", - project = @target_project || @project
placeholder: 'Select assignee', class: 'custom-form-control', null_user: true, - if issuable.assignee_id
selected: issuable.assignee_id, project: @target_project || @project, = hidden_field_tag("#{issuable.class.model_name.param_key}[assignee_id]", issuable.assignee_id)
first_user: true, current_user: true, include_blank: true) = dropdown_tag(user_dropdown_label(issuable.assignee_id, "Assignee"), options: { toggle_class: "js-user-search js-issuable-form-dropdown js-assignee-search", title: "Filter by assignee", filter: true, dropdown_class: "dropdown-menu-user dropdown-menu-selectable dropdown-menu-assignee js-filter-submit",
%div placeholder: "Search assignee", data: { first_user: (current_user.username if current_user), null_user: true, current_user: true, project_id: (project.id if project), selected: issuable.assignee_id, field_name: "#{issuable.class.model_name.param_key}[assignee_id]", default_label: "Assignee" } })
= link_to 'Assign to me', '#', class: 'assign-to-me-link prepend-top-5 inline'
.form-group.issue-milestone .form-group.issue-milestone
= f.label :milestone_id, "Milestone", class: "control-label #{"col-lg-4" if has_due_date}" = f.label :milestone_id, "Milestone", class: "control-label #{"col-lg-4" if has_due_date}"
.col-sm-10{ class: ("col-lg-8" if has_due_date) } .col-sm-10{ class: ("col-lg-8" if has_due_date) }
- if milestone_options(issuable).present?
.issuable-form-select-holder .issuable-form-select-holder
= f.select(:milestone_id, milestone_options(issuable), = render "shared/issuable/milestone_dropdown", selected: issuable.milestone_id, name: "#{issuable.class.model_name.param_key}[milestone_id]", show_any: false, show_upcoming: false
{ include_blank: true }, { class: 'select2', data: { placeholder: 'Select milestone' } })
- else
.prepend-top-10
%span.light No open milestones available.
- if can? current_user, :admin_milestone, issuable.project
%div
= link_to 'Create new milestone', new_namespace_project_milestone_path(issuable.project.namespace, issuable.project), target: :blank, class: "prepend-top-5 inline"
.form-group .form-group
- has_labels = issuable.project.labels.any? - has_labels = issuable.project.labels.any?
- selected_labels = issuable.label_ids.any? ? issuable.label_ids : nil
- label_dropdown_toggle = issuable.labels.map { |label| label.title }
= f.label :label_ids, "Labels", class: "control-label #{"col-lg-4" if has_due_date}" = f.label :label_ids, "Labels", class: "control-label #{"col-lg-4" if has_due_date}"
.col-sm-10{ class: "#{"col-lg-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" } .col-sm-10{ class: "#{"col-lg-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" }
- if has_labels
.issuable-form-select-holder .issuable-form-select-holder
= f.collection_select :label_ids, issuable.project.labels.all, :id, :name, = render "shared/issuable/label_dropdown", classes: ["js-issuable-form-dropdown"], selected: selected_labels, selected_toggle: label_dropdown_toggle, data_options: { field_name: "#{issuable.class.model_name.param_key}[label_ids][]", show_any: "false" }
{ selected: issuable.label_ids }, multiple: true, class: 'select2', data: { placeholder: "Select labels" }
- else
%span.light No labels yet.
- if can? current_user, :admin_label, issuable.project
%div
= link_to 'Create new label', new_namespace_project_label_path(issuable.project.namespace, issuable.project), target: :blank, class: "prepend-top-5 inline"
- if has_due_date - if has_due_date
.col-lg-6 .col-lg-6
.form-group .form-group
......
...@@ -4,19 +4,21 @@ ...@@ -4,19 +4,21 @@
- show_footer = local_assigns.fetch(:show_footer, true) - show_footer = local_assigns.fetch(:show_footer, true)
- data_options = local_assigns.fetch(:data_options, {}) - data_options = local_assigns.fetch(:data_options, {})
- classes = local_assigns.fetch(:classes, []) - classes = local_assigns.fetch(:classes, [])
- dropdown_data = {toggle: 'dropdown', field_name: 'label_name[]', show_no: "true", show_any: "true", selected: params[:label_name], project_id: @project.try(:id), labels: labels_filter_path, default_label: "Label"} - selected = local_assigns.fetch(:selected, nil)
- selected_toggle = local_assigns.fetch(:selected_toggle, nil)
- dropdown_data = {toggle: 'dropdown', field_name: "label_name[]", show_no: "true", show_any: "true", selected: selected, project_id: @project.try(:id), labels: labels_filter_path, default_label: "Label"}
- dropdown_data.merge!(data_options) - dropdown_data.merge!(data_options)
- classes << 'js-extra-options' if extra_options - classes << 'js-extra-options' if extra_options
- classes << 'js-filter-submit' if filter_submit - classes << 'js-filter-submit' if filter_submit
- if params[:label_name].present? - if selected.present?
- if params[:label_name].respond_to?('any?') - if selected.respond_to?('any?')
- params[:label_name].each do |label| - selected.each do |label|
= hidden_field_tag "label_name[]", label, id: nil = hidden_field_tag data_options[:field_name], label, id: nil
.dropdown .dropdown
%button.dropdown-menu-toggle.js-label-select.js-multiselect{class: classes.join(' '), type: "button", data: dropdown_data} %button.dropdown-menu-toggle.js-label-select.js-multiselect{class: classes.join(' '), type: "button", data: dropdown_data}
%span.dropdown-toggle-text %span.dropdown-toggle-text
= h(multi_label_name(params[:label_name], "Label")) = h(multi_label_name(selected_toggle || selected, "Label"))
= icon('chevron-down') = icon('chevron-down')
.dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable .dropdown-menu.dropdown-select.dropdown-menu-paging.dropdown-menu-labels.dropdown-menu-selectable
= render partial: "shared/issuable/label_page_default", locals: { title: "Filter by label", show_footer: show_footer, show_create: show_create } = render partial: "shared/issuable/label_page_default", locals: { title: "Filter by label", show_footer: show_footer, show_create: show_create }
......
- if params[:milestone_title].present? - if selected.present?
= hidden_field_tag(:milestone_title, params[:milestone_title]) = hidden_field_tag(name, selected)
= dropdown_tag(milestone_dropdown_label(params[:milestone_title]), options: { title: "Filter by milestone", toggle_class: 'js-milestone-select js-filter-submit', filter: true, dropdown_class: "dropdown-menu-selectable", = dropdown_tag(milestone_dropdown_label(selected), options: { title: "Filter by milestone", toggle_class: 'js-milestone-select js-filter-submit', filter: true, dropdown_class: "dropdown-menu-selectable",
placeholder: "Search milestones", footer_content: @project.present?, data: { show_no: true, show_any: true, show_upcoming: true, field_name: "milestone_title", selected: params[:milestone_title], project_id: @project.try(:id), milestones: milestones_filter_dropdown_path, default_label: "Milestone" } }) do placeholder: "Search milestones", footer_content: @project.present?, data: { show_no: true, show_any: show_any, show_upcoming: show_upcoming, field_name: name, selected: selected, project_id: @project.try(:id), milestones: milestones_filter_dropdown_path, default_label: "Milestone" } }) do
- if @project - if @project
%ul.dropdown-footer-list %ul.dropdown-footer-list
- if can? current_user, :admin_milestone, @project - if can? current_user, :admin_milestone, @project
......
...@@ -37,6 +37,7 @@ Feature: Project Issues ...@@ -37,6 +37,7 @@ Feature: Project Issues
And I submit new issue "500 error on profile" And I submit new issue "500 error on profile"
Then I should see issue "500 error on profile" Then I should see issue "500 error on profile"
@javascript
Scenario: I submit new unassigned issue with labels Scenario: I submit new unassigned issue with labels
Given project "Shop" has labels: "bug", "feature", "enhancement" Given project "Shop" has labels: "bug", "feature", "enhancement"
And I click link "New Issue" And I click link "New Issue"
......
...@@ -135,19 +135,17 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps ...@@ -135,19 +135,17 @@ class Spinach::Features::ProjectForkedMergeRequests < Spinach::FeatureSteps
end end
step 'I click "Assign to" dropdown"' do step 'I click "Assign to" dropdown"' do
first('.ajax-users-select').click click_button 'Assignee'
end end
step 'I should see the target project ID in the input selector' do step 'I should see the target project ID in the input selector' do
expect(page).to have_selector("input[data-project-id=\"#{@project.id}\"]") expect(find('.js-assignee-search')["data-project-id"]).to eq "#{@project.id}"
end end
step 'I should see the users from the target project ID' do step 'I should see the users from the target project ID' do
expect(page).to have_selector('.user-result', visible: true, count: 3) expect(page).to have_content 'Unassigned'
users = page.all('.user-name') expect(page).to have_content current_user.name
expect(users[0].text).to eq 'Unassigned' expect(page).to have_content @project.users.first.name
expect(users[1].text).to eq current_user.name
expect(users[2].text).to eq @project.users.first.name
end end
# Verify a link is generated against the correct project # Verify a link is generated against the correct project
......
...@@ -82,7 +82,8 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps ...@@ -82,7 +82,8 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
step 'I submit new issue "500 error on profile" with label \'bug\'' do step 'I submit new issue "500 error on profile" with label \'bug\'' do
fill_in "issue_title", with: "500 error on profile" fill_in "issue_title", with: "500 error on profile"
select 'bug', from: "Labels" click_button "Label"
click_link "bug"
click_button "Submit issue" click_button "Submit issue"
end end
......
...@@ -55,7 +55,7 @@ feature 'issue move to another project' do ...@@ -55,7 +55,7 @@ feature 'issue move to another project' do
first('.select2-choice').click first('.select2-choice').click
end end
fill_in('s2id_autogen2_search', with: new_project_search.name) fill_in('s2id_autogen1_search', with: new_project_search.name)
page.within '.select2-drop' do page.within '.select2-drop' do
expect(page).to have_content(new_project_search.name) expect(page).to have_content(new_project_search.name)
......
...@@ -50,9 +50,8 @@ describe 'Issues', feature: true do ...@@ -50,9 +50,8 @@ describe 'Issues', feature: true do
expect(page).to have_content "Assignee #{@user.name}" expect(page).to have_content "Assignee #{@user.name}"
first('#s2id_issue_assignee_id').click first('.js-user-search').click
sleep 2 # wait for ajax stuff to complete click_link 'Unassigned'
first('.user-result').click
click_button 'Save changes' click_button 'Save changes'
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment