Commit 05ef7ba1 authored by Dmitriy Zaporozhets's avatar Dmitriy Zaporozhets

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
parents c342a9ab 58ceb8e9
......@@ -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,19 +31,13 @@ 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'))
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'))
when 'projects:merge_requests:show'
new Diff()
......@@ -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()
......
#= 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('')
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
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,
......
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){
......
%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
......
= 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"
- 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?
......
- 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
......
= 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
......
- 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"
......
- 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'
- 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();
= form_for [@project.namespace.becomes(Namespace), @project, @merge_request], remote: true, html: {class: 'edit-merge_request inline-update js-merge-request-update'} do |f|
= 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 @merge_request.assignee
%strong= link_to_member(@project, @merge_request.assignee, size: 24)
- if issuable.assignee
%strong= link_to_member(@project, issuable.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)
- 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 @merge_request.milestone
- if issuable.milestone
%span.back-to-milestone
= link_to namespace_project_milestone_path(@project.namespace, @project, @merge_request.milestone) do
= link_to namespace_project_milestone_path(@project.namespace, @project, issuable.milestone) do
%strong
= icon('clock-o')
= @merge_request.milestone.title
= issuable.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 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 = @merge_request.subscribed?(current_user)
- subscribed = issuable.subscribed?(current_user)
%div.prepend-top-20.clearfix
.issuable-context-title
%label
......@@ -46,4 +46,5 @@
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)}")
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,8 +37,9 @@
.clearfix
.error-alert
%hr
.form-group
%hr
- if can?(current_user, :admin_issue, @project)
.form-group
.issue-assignee
= f.label :assignee_id, class: 'control-label' do
%i.fa.fa-user
......@@ -49,7 +50,7 @@
selected: issuable.assignee_id, project: @target_project || @project)
&nbsp;
= link_to 'Assign to me', '#', class: 'btn assign-to-me-link'
.form-group
.form-group
.issue-milestone
= f.label :milestone_id, class: 'control-label' do
%i.fa.fa-clock-o
......@@ -64,7 +65,7 @@
&nbsp;
- 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
.form-group
= f.label :label_ids, class: 'control-label' do
%i.fa.fa-tag
Labels
......
......@@ -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'
......
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'}
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