Merge branch 'permission-improvements' into 'master'
Update permissions for issue tracker management Don't allow guest or reporter to set assignee, milestone and label when create or update new issue and merge request. After this change `Guest` and `Reporter` rule is used to report issues but only `Developer` and higher roles can manage issues (schedule milestone, assign to user or close any issue) Also I removed some duplication code between issues and merge requests and put all issuable partials in one directory See merge request !890
This commit is contained in:
commit
05ef7ba105
43 changed files with 203 additions and 247 deletions
|
@ -21,6 +21,7 @@ v 7.13.0 (unreleased)
|
|||
- Show a user's Two-factor Authentication status in the administration area.
|
||||
- Explicit error when commit not found in the CI
|
||||
- Improve performance for issue and merge request pages
|
||||
- Users with guest access level can not set assignee, labels or milestones for issue and merge request
|
||||
|
||||
v 7.12.0 (unreleased)
|
||||
- Fix Error 500 when one user attempts to access a personal, internal snippet (Stan Hu)
|
||||
|
|
|
@ -31,20 +31,14 @@ class Dispatcher
|
|||
when 'projects:compare:show'
|
||||
new Diff()
|
||||
when 'projects:issues:new','projects:issues:edit'
|
||||
GitLab.GfmAutoComplete.setup()
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
new ZenMode()
|
||||
new DropzoneInput($('.issue-form'))
|
||||
if page == 'projects:issues:new'
|
||||
new IssuableForm($('.issue-form'))
|
||||
new IssuableForm($('.issue-form'))
|
||||
when 'projects:merge_requests:new', 'projects:merge_requests:edit'
|
||||
GitLab.GfmAutoComplete.setup()
|
||||
new Diff()
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
new ZenMode()
|
||||
new DropzoneInput($('.merge-request-form'))
|
||||
if page == 'projects:merge_requests:new'
|
||||
new IssuableForm($('.merge-request-form'))
|
||||
new IssuableForm($('.merge-request-form'))
|
||||
when 'projects:merge_requests:show'
|
||||
new Diff()
|
||||
shortcut_handler = new ShortcutsIssuable()
|
||||
|
@ -113,13 +107,6 @@ class Dispatcher
|
|||
new NamespaceSelect()
|
||||
when 'dashboard'
|
||||
shortcut_handler = new ShortcutsDashboardNavigation()
|
||||
switch path[1]
|
||||
when 'issues', 'merge_requests'
|
||||
new UsersSelect()
|
||||
when 'groups'
|
||||
switch path[1]
|
||||
when 'issues', 'merge_requests'
|
||||
new UsersSelect()
|
||||
when 'profiles'
|
||||
new Profile()
|
||||
when 'projects'
|
||||
|
@ -135,8 +122,6 @@ class Dispatcher
|
|||
new ProjectNew()
|
||||
when 'show'
|
||||
new ProjectShow()
|
||||
when 'issues', 'merge_requests'
|
||||
new UsersSelect()
|
||||
when 'wikis'
|
||||
new Wikis()
|
||||
shortcut_handler = new ShortcutsNavigation()
|
||||
|
|
22
app/assets/javascripts/issuable_context.js.coffee
Normal file
22
app/assets/javascripts/issuable_context.js.coffee
Normal file
|
@ -0,0 +1,22 @@
|
|||
#= require jquery.waitforimages
|
||||
|
||||
class @IssuableContext
|
||||
constructor: ->
|
||||
new UsersSelect()
|
||||
$('select.select2').select2({width: 'resolve', dropdownAutoWidth: true})
|
||||
|
||||
$(".context .inline-update").on "change", "select", ->
|
||||
$(this).submit()
|
||||
$(".context .inline-update").on "change", ".js-assignee", ->
|
||||
$(this).submit()
|
||||
|
||||
$('.issuable-details').waitForImages ->
|
||||
$('.issuable-affix').affix offset:
|
||||
top: ->
|
||||
@top = ($('.issuable-affix').offset().top - 70)
|
||||
bottom: ->
|
||||
@bottom = $('.footer').outerHeight(true)
|
||||
$('.issuable-affix').on 'affix.bs.affix', ->
|
||||
$(@).width($(@).outerWidth())
|
||||
.on 'affixed-top.bs.affix affixed-bottom.bs.affix', ->
|
||||
$(@).width('')
|
|
@ -1,5 +1,9 @@
|
|||
class @IssuableForm
|
||||
constructor: (@form) ->
|
||||
GitLab.GfmAutoComplete.setup()
|
||||
new UsersSelect()
|
||||
new ZenMode()
|
||||
|
||||
@titleField = @form.find("input[name*='[title]']")
|
||||
@descriptionField = @form.find("textarea[name*='[description]']")
|
||||
|
||||
|
|
|
@ -3,29 +3,12 @@
|
|||
|
||||
class @Issue
|
||||
constructor: ->
|
||||
$('.edit-issue.inline-update input[type="submit"]').hide()
|
||||
$(".context .inline-update").on "change", "select", ->
|
||||
$(this).submit()
|
||||
$(".context .inline-update").on "change", "#issue_assignee_id", ->
|
||||
$(this).submit()
|
||||
|
||||
# Prevent duplicate event bindings
|
||||
@disableTaskList()
|
||||
|
||||
if $("a.btn-close").length
|
||||
@initTaskList()
|
||||
|
||||
$('.issue-details').waitForImages ->
|
||||
$('.issuable-affix').affix offset:
|
||||
top: ->
|
||||
@top = ($('.issuable-affix').offset().top - 70)
|
||||
bottom: ->
|
||||
@bottom = $('.footer').outerHeight(true)
|
||||
$('.issuable-affix').on 'affix.bs.affix', ->
|
||||
$(@).width($(@).outerWidth())
|
||||
.on 'affixed-top.bs.affix affixed-bottom.bs.affix', ->
|
||||
$(@).width('')
|
||||
|
||||
initTaskList: ->
|
||||
$('.issue-details .js-task-list-container').taskList('enable')
|
||||
$(document).on 'tasklist:changed', '.issue-details .js-task-list-container', @updateTaskList
|
||||
|
@ -42,5 +25,5 @@ class @Issue
|
|||
|
||||
$.ajax
|
||||
type: 'PATCH'
|
||||
url: $('form.js-issue-update').attr('action')
|
||||
url: $('form.js-issuable-update').attr('action')
|
||||
data: patchData
|
||||
|
|
|
@ -10,7 +10,6 @@ class @MergeRequest
|
|||
# action - String, current controller action
|
||||
#
|
||||
constructor: (@opts) ->
|
||||
@initContextWidget()
|
||||
this.$el = $('.merge-request')
|
||||
|
||||
this.$('.show-all-commits').on 'click', =>
|
||||
|
@ -26,28 +25,10 @@ class @MergeRequest
|
|||
if $("a.btn-close").length
|
||||
@initTaskList()
|
||||
|
||||
$('.merge-request-details').waitForImages ->
|
||||
$('.issuable-affix').affix offset:
|
||||
top: ->
|
||||
@top = ($('.issuable-affix').offset().top - 70)
|
||||
bottom: ->
|
||||
@bottom = $('.footer').outerHeight(true)
|
||||
$('.issuable-affix').on 'affix.bs.affix', ->
|
||||
$(@).width($(@).outerWidth())
|
||||
.on 'affixed-top.bs.affix affixed-bottom.bs.affix', ->
|
||||
$(@).width('')
|
||||
|
||||
# Local jQuery finder
|
||||
$: (selector) ->
|
||||
this.$el.find(selector)
|
||||
|
||||
initContextWidget: ->
|
||||
$('.edit-merge_request.inline-update input[type="submit"]').hide()
|
||||
$(".context .inline-update").on "change", "select", ->
|
||||
$(this).submit()
|
||||
$(".context .inline-update").on "change", "#merge_request_assignee_id", ->
|
||||
$(this).submit()
|
||||
|
||||
showAllCommits: ->
|
||||
this.$('.first-commits').remove()
|
||||
this.$('.all-commits').removeClass 'hide'
|
||||
|
@ -68,5 +49,5 @@ class @MergeRequest
|
|||
|
||||
$.ajax
|
||||
type: 'PATCH'
|
||||
url: $('form.js-merge-request-update').attr('action')
|
||||
url: $('form.js-issuable-update').attr('action')
|
||||
data: patchData
|
||||
|
|
|
@ -145,9 +145,3 @@ h2.issue-title {
|
|||
.issue-form .select2-container {
|
||||
width: 250px !important;
|
||||
}
|
||||
|
||||
.issues-holder {
|
||||
.issue-info {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,4 +52,12 @@ module GitlabRoutingHelper
|
|||
def project_snippet_url(entity, *args)
|
||||
namespace_project_snippet_url(entity.project.namespace, entity.project, entity, *args)
|
||||
end
|
||||
|
||||
def toggle_subscription_path(entity, *args)
|
||||
if entity.is_a?(Issue)
|
||||
toggle_subscription_namespace_project_issue_path(entity.project.namespace, entity.project, entity)
|
||||
else
|
||||
toggle_subscription_namespace_project_merge_request_path(entity.project.namespace, entity.project, entity)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -185,7 +185,6 @@ class Ability
|
|||
:modify_issue,
|
||||
:modify_project_snippet,
|
||||
:modify_merge_request,
|
||||
:admin_issue,
|
||||
:admin_milestone,
|
||||
:admin_project_snippet,
|
||||
:admin_project_member,
|
||||
|
|
|
@ -26,4 +26,12 @@ class IssuableBaseService < BaseService
|
|||
issuable, issuable.project, current_user, branch_type,
|
||||
old_branch, new_branch)
|
||||
end
|
||||
|
||||
def filter_params
|
||||
unless can?(current_user, :admin_issue, project)
|
||||
params.delete(:milestone_id)
|
||||
params.delete(:label_ids)
|
||||
params.delete(:assignee_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
module Issues
|
||||
class CreateService < Issues::BaseService
|
||||
def execute
|
||||
filter_params
|
||||
label_params = params[:label_ids]
|
||||
issue = project.issues.new(params.except(:label_ids))
|
||||
issue.author = current_user
|
||||
|
|
|
@ -17,6 +17,7 @@ module Issues
|
|||
params[:assignee_id] = "" if params[:assignee_id] == IssuableFinder::NONE
|
||||
params[:milestone_id] = "" if params[:milestone_id] == IssuableFinder::NONE
|
||||
|
||||
filter_params
|
||||
old_labels = issue.labels.to_a
|
||||
|
||||
if params.present? && issue.update_attributes(params.except(:state_event,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
module MergeRequests
|
||||
class CreateService < MergeRequests::BaseService
|
||||
def execute
|
||||
filter_params
|
||||
label_params = params[:label_ids]
|
||||
merge_request = MergeRequest.new(params.except(:label_ids))
|
||||
merge_request.source_project = project
|
||||
|
|
|
@ -27,6 +27,7 @@ module MergeRequests
|
|||
params[:assignee_id] = "" if params[:assignee_id] == IssuableFinder::NONE
|
||||
params[:milestone_id] = "" if params[:milestone_id] == IssuableFinder::NONE
|
||||
|
||||
filter_params
|
||||
old_labels = merge_request.labels.to_a
|
||||
|
||||
if params.present? && merge_request.update_attributes(
|
||||
|
|
|
@ -17,5 +17,5 @@
|
|||
= link_to issues_dashboard_url(format: :atom, private_token: current_user.private_token), class: 'btn' do
|
||||
%i.fa.fa-rss
|
||||
|
||||
= render 'shared/issuable_filter', type: :issues
|
||||
= render 'shared/issuable/filter', type: :issues
|
||||
= render 'shared/issues'
|
||||
|
|
|
@ -7,5 +7,5 @@
|
|||
List all merge requests from all projects you have access to.
|
||||
%hr
|
||||
.append-bottom-20
|
||||
= render 'shared/issuable_filter', type: :merge_requests
|
||||
= render 'shared/issuable/filter', type: :merge_requests
|
||||
= render 'shared/merge_requests'
|
||||
|
|
|
@ -21,5 +21,5 @@
|
|||
= link_to issues_group_url(@group, format: :atom, private_token: current_user.private_token), class: 'btn' do
|
||||
%i.fa.fa-rss
|
||||
|
||||
= render 'shared/issuable_filter', type: :issues
|
||||
= render 'shared/issuable/filter', type: :issues
|
||||
= render 'shared/issues'
|
||||
|
|
|
@ -10,5 +10,5 @@
|
|||
To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page.
|
||||
%hr
|
||||
.append-bottom-20
|
||||
= render 'shared/issuable_filter', type: :merge_requests
|
||||
= render 'shared/issuable/filter', type: :merge_requests
|
||||
= render 'shared/merge_requests'
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
= cross_project_reference(@project, @issue)
|
||||
%hr
|
||||
.context
|
||||
= render partial: 'issue_context', locals: { issue: @issue }
|
||||
= render 'shared/issuable/context', issuable: @issue
|
||||
|
||||
- if @issue.labels.any?
|
||||
.issuable-context-title
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
%hr
|
||||
|
||||
= form_for [@project.namespace.becomes(Namespace), @project, @issue], html: { class: 'form-horizontal issue-form gfm-form' } do |f|
|
||||
= render 'projects/issuable_form', f: f, issuable: @issue
|
||||
= render 'shared/issuable/form', f: f, issuable: @issue
|
||||
|
||||
:javascript
|
||||
$('.assign-to-me-link').on('click', function(e){
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
%li{ id: dom_id(issue), class: issue_css_classes(issue), url: issue_path(issue) }
|
||||
- if controller.controller_name == 'issues'
|
||||
- if controller.controller_name == 'issues' && can?(current_user, :admin_issue, @project)
|
||||
.issue-check
|
||||
= check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, class: "selected_issue", disabled: !can?(current_user, :modify_issue, issue)
|
||||
= check_box_tag dom_id(issue,"selected"), nil, false, 'data-id' => issue.id, class: "selected_issue"
|
||||
|
||||
.issue-title
|
||||
%span.issue-title-text
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
= form_for [@project.namespace.becomes(Namespace), @project, @issue], remote: true, html: {class: 'edit-issue inline-update js-issue-update'} do |f|
|
||||
%div.prepend-top-20
|
||||
.issuable-context-title
|
||||
%label
|
||||
Assignee:
|
||||
- if issue.assignee
|
||||
%strong= link_to_member(@project, @issue.assignee, size: 24)
|
||||
- else
|
||||
none
|
||||
- if can?(current_user, :modify_issue, @issue)
|
||||
= users_select_tag('issue[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @issue.assignee_id, null_user: true, first_user: true)
|
||||
|
||||
%div.prepend-top-20.clearfix
|
||||
.issuable-context-title
|
||||
%label
|
||||
Milestone:
|
||||
- if issue.milestone
|
||||
%span.back-to-milestone
|
||||
= link_to namespace_project_milestone_path(@project.namespace, @project, @issue.milestone) do
|
||||
%strong
|
||||
%i.fa.fa-clock-o
|
||||
= @issue.milestone.title
|
||||
- else
|
||||
none
|
||||
- if can?(current_user, :modify_issue, @issue)
|
||||
= f.select(:milestone_id, milestone_options(@issue), { include_blank: "Select milestone" }, {class: 'select2 select2-compact js-select2 js-milestone'})
|
||||
= hidden_field_tag :issue_context
|
||||
= f.submit class: 'btn'
|
||||
|
||||
- if current_user
|
||||
- subscribed = @issue.subscribed?(current_user)
|
||||
%div.prepend-top-20.clearfix
|
||||
.issuable-context-title
|
||||
%label
|
||||
Subscription:
|
||||
%button.btn.btn-block.subscribe-button{:type => 'button'}
|
||||
%i.fa.fa-eye
|
||||
%span= subscribed ? "Unsubscribe" : "Subscribe"
|
||||
- subscribtion_status = subscribed ? "subscribed" : "unsubscribed"
|
||||
.subscription-status{"data-status" => subscribtion_status}
|
||||
.description-block.unsubscribed{class: ( "hidden" if subscribed )}
|
||||
You're not receiving notifications from this thread.
|
||||
.description-block.subscribed{class: ( "hidden" unless subscribed )}
|
||||
You're receiving notifications because you're subscribed to this thread.
|
||||
|
||||
:coffeescript
|
||||
new Subscription("#{toggle_subscription_namespace_project_issue_path(@issue.project.namespace, @project, @issue)}")
|
|
@ -11,14 +11,14 @@
|
|||
= link_to namespace_project_issues_path(@project.namespace, @project, :atom, { private_token: current_user.private_token }), class: 'btn append-right-10' do
|
||||
%i.fa.fa-rss
|
||||
|
||||
= render 'shared/issuable_search_form', path: namespace_project_issues_path(@project.namespace, @project)
|
||||
= render 'shared/issuable/search_form', path: namespace_project_issues_path(@project.namespace, @project)
|
||||
|
||||
- if can? current_user, :write_issue, @project
|
||||
= link_to new_namespace_project_issue_path(@project.namespace, @project, issue: { assignee_id: @issuable_finder.assignee.try(:id), milestone_id: @issuable_finder.milestones.try(:first).try(:id) }), class: "btn btn-new pull-left", title: "New Issue", id: "new_issue_link" do
|
||||
%i.fa.fa-plus
|
||||
New Issue
|
||||
|
||||
= render 'shared/issuable_filter', type: :issues
|
||||
= render 'shared/issuable/filter', type: :issues
|
||||
|
||||
.issues-holder
|
||||
= render "issues"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- page_title "#{@issue.title} (##{@issue.iid})", "Issues"
|
||||
.issue
|
||||
.issue-details
|
||||
.issue-details.issuable-details
|
||||
%h4.page-title
|
||||
.issue-box{ class: issue_box_class(@issue) }
|
||||
- if @issue.closed?
|
||||
|
|
|
@ -1,17 +1,3 @@
|
|||
- if params[:status_only]
|
||||
- if @issue.valid?
|
||||
:plain
|
||||
$("##{dom_id(@issue)}").fadeOut();
|
||||
- elsif params[:issue_context]
|
||||
$('.context').html("#{escape_javascript(render partial: 'issue_context', locals: { issue: @issue })}");
|
||||
$('.context').effect('highlight');
|
||||
- if @issue.milestone
|
||||
$('.milestone-nav-link').replaceWith("<span class='milestone-nav-link'>| <span class='light'>Milestone</span> #{escape_javascript(link_to @issue.milestone.title, namespace_project_milestone_path(@issue.project.namespace, @issue.project, @issue.milestone))}</span>")
|
||||
- else
|
||||
$('.milestone-nav-link').html('')
|
||||
|
||||
|
||||
$('select.select2').select2({width: 'resolve', dropdownAutoWidth: true})
|
||||
$('.edit-issue.inline-update input[type="submit"]').hide();
|
||||
new UsersSelect()
|
||||
$('.context').html("#{escape_javascript(render 'shared/issuable/context', issuable: @issue)}");
|
||||
$('.context').effect('highlight')
|
||||
new Issue();
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
= cross_project_reference(@project, @merge_request)
|
||||
%hr
|
||||
.context
|
||||
= render partial: 'projects/merge_requests/show/context', locals: { merge_request: @merge_request }
|
||||
= render 'shared/issuable/context', issuable: @merge_request
|
||||
|
||||
- if @merge_request.labels.any?
|
||||
.issuable-context-title
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], html: { class: 'merge-request-form form-horizontal gfm-form' } do |f|
|
||||
.merge-request-form-info
|
||||
= render 'projects/issuable_form', f: f, issuable: @merge_request
|
||||
= render 'shared/issuable/form', f: f, issuable: @merge_request
|
||||
|
||||
:javascript
|
||||
disableButtonIfEmptyField("#merge_request_title", ".btn-save");
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
%hr
|
||||
= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], html: { class: 'merge-request-form form-horizontal gfm-form' } do |f|
|
||||
.merge-request-form-info
|
||||
= render 'projects/issuable_form', f: f, issuable: @merge_request
|
||||
= render 'shared/issuable/form', f: f, issuable: @merge_request
|
||||
= f.hidden_field :source_project_id
|
||||
= f.hidden_field :source_branch
|
||||
= f.hidden_field :target_project_id
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- page_title "#{@merge_request.title} (##{@merge_request.iid})", "Merge Requests"
|
||||
.merge-request{'data-url' => merge_request_path(@merge_request)}
|
||||
.merge-request-details
|
||||
.merge-request-details.issuable-details
|
||||
= render "projects/merge_requests/show/mr_title"
|
||||
%hr
|
||||
= render "projects/merge_requests/show/mr_box"
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
- page_title "Merge Requests"
|
||||
.append-bottom-10
|
||||
.pull-right
|
||||
= render 'shared/issuable_search_form', path: namespace_project_merge_requests_path(@project.namespace, @project)
|
||||
= render 'shared/issuable/search_form', path: namespace_project_merge_requests_path(@project.namespace, @project)
|
||||
|
||||
- if can? current_user, :write_merge_request, @project
|
||||
.pull-left.hidden-xs
|
||||
= link_to new_namespace_project_merge_request_path(@project.namespace, @project), class: "btn btn-new", title: "New Merge Request" do
|
||||
%i.fa.fa-plus
|
||||
New Merge Request
|
||||
= render 'shared/issuable_filter', type: :merge_requests
|
||||
= render 'shared/issuable/filter', type: :merge_requests
|
||||
.merge-requests-holder
|
||||
= render 'merge_requests'
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], remote: true, html: {class: 'edit-merge_request inline-update js-merge-request-update'} do |f|
|
||||
%div.prepend-top-20
|
||||
.issuable-context-title
|
||||
%label
|
||||
Assignee:
|
||||
- if @merge_request.assignee
|
||||
%strong= link_to_member(@project, @merge_request.assignee, size: 24)
|
||||
- else
|
||||
none
|
||||
.issuable-context-selectbox
|
||||
- if can?(current_user, :modify_merge_request, @merge_request)
|
||||
= users_select_tag('merge_request[assignee_id]', placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: @merge_request.assignee_id, project: @target_project, null_user: true)
|
||||
|
||||
%div.prepend-top-20.clearfix
|
||||
.issuable-context-title
|
||||
%label
|
||||
Milestone:
|
||||
- if @merge_request.milestone
|
||||
%span.back-to-milestone
|
||||
= link_to namespace_project_milestone_path(@project.namespace, @project, @merge_request.milestone) do
|
||||
%strong
|
||||
= icon('clock-o')
|
||||
= @merge_request.milestone.title
|
||||
- else
|
||||
none
|
||||
.issuable-context-selectbox
|
||||
- if can?(current_user, :modify_merge_request, @merge_request)
|
||||
= f.select(:milestone_id, milestone_options(@merge_request), { include_blank: 'Select milestone' }, {class: 'select2 select2-compact js-select2 js-milestone'})
|
||||
= hidden_field_tag :merge_request_context
|
||||
= f.submit class: 'btn'
|
||||
|
||||
- if current_user
|
||||
- subscribed = @merge_request.subscribed?(current_user)
|
||||
%div.prepend-top-20.clearfix
|
||||
.issuable-context-title
|
||||
%label
|
||||
Subscription:
|
||||
%button.btn.btn-block.subscribe-button{:type => 'button'}
|
||||
= icon('eye')
|
||||
%span= subscribed ? 'Unsubscribe' : 'Subscribe'
|
||||
- subscribtion_status = subscribed ? 'subscribed' : 'unsubscribed'
|
||||
.subscription-status{data: {status: subscribtion_status}}
|
||||
.description-block.unsubscribed{class: ( 'hidden' if subscribed )}
|
||||
You're not receiving notifications from this thread.
|
||||
.description-block.subscribed{class: ( 'hidden' unless subscribed )}
|
||||
You're receiving notifications because you're subscribed to this thread.
|
||||
|
||||
:coffeescript
|
||||
new Subscription("#{toggle_subscription_namespace_project_merge_request_path(@merge_request.project.namespace, @project, @merge_request)}")
|
|
@ -1,8 +1,3 @@
|
|||
- if params[:merge_request_context]
|
||||
$('.context').html("#{escape_javascript(render partial: 'projects/merge_requests/show/context', locals: { issue: @issue })}");
|
||||
$('.context').effect('highlight');
|
||||
|
||||
new UsersSelect()
|
||||
|
||||
$('select.select2').select2({width: 'resolve', dropdownAutoWidth: true});
|
||||
merge_request = new MergeRequest();
|
||||
$('.context').html("#{escape_javascript(render 'shared/issuable/context', issuable: @merge_request)}");
|
||||
$('.context').effect('highlight')
|
||||
merge_request = new MergeRequest();
|
||||
|
|
50
app/views/shared/issuable/_context.html.haml
Normal file
50
app/views/shared/issuable/_context.html.haml
Normal file
|
@ -0,0 +1,50 @@
|
|||
= form_for [@project.namespace.becomes(Namespace), @project, issuable], remote: true, html: {class: 'issuable-context-form inline-update js-issuable-update'} do |f|
|
||||
%div.prepend-top-20
|
||||
.issuable-context-title
|
||||
%label
|
||||
Assignee:
|
||||
- if issuable.assignee
|
||||
%strong= link_to_member(@project, issuable.assignee, size: 24)
|
||||
- else
|
||||
none
|
||||
.issuable-context-selectbox
|
||||
- if can?(current_user, :admin_issue, @project)
|
||||
= users_select_tag("#{issuable.class.table_name.singularize}[assignee_id]", placeholder: 'Select assignee', class: 'custom-form-control js-select2 js-assignee', selected: issuable.assignee_id, project: @target_project, null_user: true)
|
||||
|
||||
%div.prepend-top-20.clearfix
|
||||
.issuable-context-title
|
||||
%label
|
||||
Milestone:
|
||||
- if issuable.milestone
|
||||
%span.back-to-milestone
|
||||
= link_to namespace_project_milestone_path(@project.namespace, @project, issuable.milestone) do
|
||||
%strong
|
||||
= icon('clock-o')
|
||||
= issuable.milestone.title
|
||||
- else
|
||||
none
|
||||
.issuable-context-selectbox
|
||||
- if can?(current_user, :admin_issue, @project)
|
||||
= f.select(:milestone_id, milestone_options(issuable), { include_blank: 'Select milestone' }, {class: 'select2 select2-compact js-select2 js-milestone'})
|
||||
= hidden_field_tag :issuable_context
|
||||
= f.submit class: 'btn hide'
|
||||
|
||||
- if current_user
|
||||
- subscribed = issuable.subscribed?(current_user)
|
||||
%div.prepend-top-20.clearfix
|
||||
.issuable-context-title
|
||||
%label
|
||||
Subscription:
|
||||
%button.btn.btn-block.subscribe-button{:type => 'button'}
|
||||
= icon('eye')
|
||||
%span= subscribed ? 'Unsubscribe' : 'Subscribe'
|
||||
- subscribtion_status = subscribed ? 'subscribed' : 'unsubscribed'
|
||||
.subscription-status{data: {status: subscribtion_status}}
|
||||
.description-block.unsubscribed{class: ( 'hidden' if subscribed )}
|
||||
You're not receiving notifications from this thread.
|
||||
.description-block.subscribed{class: ( 'hidden' unless subscribed )}
|
||||
You're receiving notifications because you're subscribed to this thread.
|
||||
|
||||
:coffeescript
|
||||
new Subscription("#{toggle_subscription_path(issuable)}")
|
||||
new IssuableContext()
|
|
@ -29,11 +29,10 @@
|
|||
|
||||
.issues-details-filters
|
||||
= form_tag page_filter_path(without: [:assignee_id, :author_id, :milestone_title, :label_name]), method: :get, class: 'filter-form' do
|
||||
- if controller.controller_name == 'issues'
|
||||
- if controller.controller_name == 'issues' && can?(current_user, :admin_issue, @project)
|
||||
.check-all-holder
|
||||
= check_box_tag "check_all_issues", nil, false,
|
||||
class: "check_all_issues left",
|
||||
disabled: !can?(current_user, :modify_issue, @project)
|
||||
class: "check_all_issues left"
|
||||
.issues-other-filters
|
||||
.filter-item.inline
|
||||
= users_select_tag(:assignee_id, selected: params[:assignee_id],
|
||||
|
@ -64,6 +63,8 @@
|
|||
= button_tag "Update issues", class: "btn update_selected_issues btn-save"
|
||||
|
||||
:coffeescript
|
||||
new UsersSelect()
|
||||
|
||||
$('form.filter-form').on 'submit', (event) ->
|
||||
event.preventDefault()
|
||||
Turbolinks.visit @.action + '&' + $(@).serialize()
|
|
@ -37,47 +37,48 @@
|
|||
|
||||
.clearfix
|
||||
.error-alert
|
||||
%hr
|
||||
.form-group
|
||||
.issue-assignee
|
||||
= f.label :assignee_id, class: 'control-label' do
|
||||
%i.fa.fa-user
|
||||
Assign to
|
||||
%hr
|
||||
- if can?(current_user, :admin_issue, @project)
|
||||
.form-group
|
||||
.issue-assignee
|
||||
= f.label :assignee_id, class: 'control-label' do
|
||||
%i.fa.fa-user
|
||||
Assign to
|
||||
.col-sm-10
|
||||
= users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]",
|
||||
placeholder: 'Select a user', class: 'custom-form-control', null_user: true,
|
||||
selected: issuable.assignee_id, project: @target_project || @project)
|
||||
|
||||
= link_to 'Assign to me', '#', class: 'btn assign-to-me-link'
|
||||
.form-group
|
||||
.issue-milestone
|
||||
= f.label :milestone_id, class: 'control-label' do
|
||||
%i.fa.fa-clock-o
|
||||
Milestone
|
||||
.col-sm-10
|
||||
- if milestone_options(issuable).present?
|
||||
= f.select(:milestone_id, milestone_options(issuable),
|
||||
{ include_blank: 'Select milestone' }, { class: 'select2' })
|
||||
- else
|
||||
.prepend-top-10
|
||||
%span.light No open milestones available.
|
||||
|
||||
- if can? current_user, :admin_milestone, issuable.project
|
||||
= link_to 'Create new milestone', new_namespace_project_milestone_path(issuable.project.namespace, issuable.project), target: :blank
|
||||
.form-group
|
||||
= f.label :label_ids, class: 'control-label' do
|
||||
%i.fa.fa-tag
|
||||
Labels
|
||||
.col-sm-10
|
||||
= users_select_tag("#{issuable.class.model_name.param_key}[assignee_id]",
|
||||
placeholder: 'Select a user', class: 'custom-form-control', null_user: true,
|
||||
selected: issuable.assignee_id, project: @target_project || @project)
|
||||
|
||||
= link_to 'Assign to me', '#', class: 'btn assign-to-me-link'
|
||||
.form-group
|
||||
.issue-milestone
|
||||
= f.label :milestone_id, class: 'control-label' do
|
||||
%i.fa.fa-clock-o
|
||||
Milestone
|
||||
.col-sm-10
|
||||
- if milestone_options(issuable).present?
|
||||
= f.select(:milestone_id, milestone_options(issuable),
|
||||
{ include_blank: 'Select milestone' }, { class: 'select2' })
|
||||
- if issuable.project.labels.any?
|
||||
= f.collection_select :label_ids, issuable.project.labels.all, :id, :name,
|
||||
{ selected: issuable.label_ids }, multiple: true, class: 'select2'
|
||||
- else
|
||||
.prepend-top-10
|
||||
%span.light No open milestones available.
|
||||
%span.light No labels yet.
|
||||
|
||||
- if can? current_user, :admin_milestone, issuable.project
|
||||
= link_to 'Create new milestone', new_namespace_project_milestone_path(issuable.project.namespace, issuable.project), target: :blank
|
||||
.form-group
|
||||
= f.label :label_ids, class: 'control-label' do
|
||||
%i.fa.fa-tag
|
||||
Labels
|
||||
.col-sm-10
|
||||
- if issuable.project.labels.any?
|
||||
= f.collection_select :label_ids, issuable.project.labels.all, :id, :name,
|
||||
{ selected: issuable.label_ids }, multiple: true, class: 'select2'
|
||||
- else
|
||||
.prepend-top-10
|
||||
%span.light No labels yet.
|
||||
|
||||
- if can? current_user, :admin_label, issuable.project
|
||||
= link_to 'Create new label', new_namespace_project_label_path(issuable.project.namespace, issuable.project), target: :blank
|
||||
- if can? current_user, :admin_label, issuable.project
|
||||
= link_to 'Create new label', new_namespace_project_label_path(issuable.project.namespace, issuable.project), target: :blank
|
||||
|
||||
- if issuable.is_a?(MergeRequest)
|
||||
%hr
|
|
@ -184,3 +184,15 @@ Feature: Project Issues
|
|||
Then I should see that I am subscribed
|
||||
When I click button "Unsubscribe"
|
||||
Then I should see that I am unsubscribed
|
||||
|
||||
Scenario: I submit new unassigned issue as guest
|
||||
Given I logout
|
||||
Given public project "Community"
|
||||
When I visit project "Community" page
|
||||
And I click link "New Issue"
|
||||
And I should not see assignee field
|
||||
And I should not see milestone field
|
||||
And I should not see labels field
|
||||
And I submit new issue "500 error on profile"
|
||||
Then I should see issue "500 error on profile"
|
||||
|
||||
|
|
|
@ -262,6 +262,24 @@ class Spinach::Features::ProjectIssues < Spinach::FeatureSteps
|
|||
end
|
||||
end
|
||||
|
||||
step 'I should not see labels field' do
|
||||
page.within '.issue-form' do
|
||||
expect(page).not_to have_content("Labels")
|
||||
end
|
||||
end
|
||||
|
||||
step 'I should not see milestone field' do
|
||||
page.within '.issue-form' do
|
||||
expect(page).not_to have_content("Milestone")
|
||||
end
|
||||
end
|
||||
|
||||
step 'I should not see assignee field' do
|
||||
page.within '.issue-form' do
|
||||
expect(page).not_to have_content("Assign to")
|
||||
end
|
||||
end
|
||||
|
||||
def filter_issue(text)
|
||||
fill_in 'issue_search', with: text
|
||||
end
|
||||
|
|
|
@ -157,7 +157,7 @@ module API
|
|||
if issue.valid?
|
||||
# Find or create labels and attach to issue. Labels are valid because
|
||||
# we already checked its name, so there can't be an error here
|
||||
unless params[:labels].nil?
|
||||
if params[:labels] && can?(current_user, :admin_issue, user_project)
|
||||
issue.remove_labels
|
||||
# Create and add labels to the new created issue
|
||||
issue.add_labels_by_names(params[:labels].split(','))
|
||||
|
|
|
@ -218,7 +218,7 @@ describe 'Issues', feature: true do
|
|||
it 'with dropdown menu' do
|
||||
visit namespace_project_issue_path(project.namespace, project, issue)
|
||||
|
||||
find('.edit-issue.inline-update #issue_assignee_id').
|
||||
find('.context #issue_assignee_id').
|
||||
set project.team.members.first.id
|
||||
click_button 'Update Issue'
|
||||
|
||||
|
@ -257,7 +257,7 @@ describe 'Issues', feature: true do
|
|||
it 'with dropdown menu' do
|
||||
visit namespace_project_issue_path(project.namespace, project, issue)
|
||||
|
||||
find('.edit-issue.inline-update').
|
||||
find('.context').
|
||||
select(milestone.title, from: 'issue_milestone_id')
|
||||
click_button 'Update Issue'
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
require 'spec_helper'
|
||||
|
||||
feature 'Task Lists' do
|
||||
feature 'Task Lists', feature: true do
|
||||
include Warden::Test::Helpers
|
||||
|
||||
let(:project) { create(:project) }
|
||||
|
@ -52,7 +52,7 @@ feature 'Task Lists' do
|
|||
expect(page).to have_selector(container)
|
||||
expect(page).to have_selector("#{container} .wiki .task-list .task-list-item .task-list-item-checkbox")
|
||||
expect(page).to have_selector("#{container} .js-task-list-field")
|
||||
expect(page).to have_selector('form.js-issue-update')
|
||||
expect(page).to have_selector('form.js-issuable-update')
|
||||
expect(page).to have_selector('a.btn-close')
|
||||
end
|
||||
|
||||
|
@ -128,7 +128,7 @@ feature 'Task Lists' do
|
|||
expect(page).to have_selector(container)
|
||||
expect(page).to have_selector("#{container} .wiki .task-list .task-list-item .task-list-item-checkbox")
|
||||
expect(page).to have_selector("#{container} .js-task-list-field")
|
||||
expect(page).to have_selector('form.js-merge-request-update')
|
||||
expect(page).to have_selector('form.js-issuable-update')
|
||||
expect(page).to have_selector('a.btn-close')
|
||||
end
|
||||
|
||||
|
|
|
@ -10,4 +10,4 @@
|
|||
%textarea.js-task-list-field
|
||||
\- [ ] Task List Item
|
||||
|
||||
%form.js-issue-update{action: '/foo'}
|
||||
%form.js-issuable-update{action: '/foo'}
|
||||
|
|
|
@ -10,4 +10,4 @@
|
|||
%textarea.js-task-list-field
|
||||
\- [ ] Task List Item
|
||||
|
||||
%form.js-merge-request-update{action: '/foo'}
|
||||
%form.js-issuable-update{action: '/foo'}
|
||||
|
|
Loading…
Reference in a new issue