Commit 4ae67fca authored by Douwe Maan's avatar Douwe Maan

Show warning when a comment will add 10 or more people to the discussion.

parent 1f78aeba
...@@ -3,6 +3,7 @@ Please view this file on the master branch, on stable branches it's out of date. ...@@ -3,6 +3,7 @@ Please view this file on the master branch, on stable branches it's out of date.
v 7.12.0 (unreleased) v 7.12.0 (unreleased)
- Don't notify users mentioned in code blocks or blockquotes. - Don't notify users mentioned in code blocks or blockquotes.
- Omit link to generate labels if user does not have access to create them (Stan Hu) - Omit link to generate labels if user does not have access to create them (Stan Hu)
- Show warning when a comment will add 10 or more people to the discussion.
- Disable changing of the source branch in merge request update API (Stan Hu) - Disable changing of the source branch in merge request update API (Stan Hu)
- Shorten merge request WIP text. - Shorten merge request WIP text.
- Add option to disallow users from registering any application to use GitLab as an OAuth provider - Add option to disallow users from registering any application to use GitLab as an OAuth provider
......
...@@ -10,12 +10,17 @@ class @DropzoneInput ...@@ -10,12 +10,17 @@ class @DropzoneInput
iconSpinner = "<i class=\"fa fa-spinner fa-spin div-dropzone-icon\"></i>" iconSpinner = "<i class=\"fa fa-spinner fa-spin div-dropzone-icon\"></i>"
btnAlert = "<button type=\"button\"" + alertAttr + ">&times;</button>" btnAlert = "<button type=\"button\"" + alertAttr + ">&times;</button>"
project_uploads_path = window.project_uploads_path or null project_uploads_path = window.project_uploads_path or null
markdown_preview_path = window.markdown_preview_path or null
max_file_size = gon.max_file_size or 10 max_file_size = gon.max_file_size or 10
form_textarea = $(form).find("textarea.markdown-area") form_textarea = $(form).find("textarea.markdown-area")
form_textarea.wrap "<div class=\"div-dropzone\"></div>" form_textarea.wrap "<div class=\"div-dropzone\"></div>"
form_textarea.bind 'paste', (event) => form_textarea.bind 'paste', (event) =>
handlePaste(event) handlePaste(event)
form_textarea.bind "input", ->
hideReferencedUsers()
form_textarea.bind "blur", ->
renderMarkdown()
form_dropzone = $(form).find('.div-dropzone') form_dropzone = $(form).find('.div-dropzone')
form_dropzone.parent().addClass "div-dropzone-wrapper" form_dropzone.parent().addClass "div-dropzone-wrapper"
...@@ -45,16 +50,7 @@ class @DropzoneInput ...@@ -45,16 +50,7 @@ class @DropzoneInput
form.find(".md-write-holder").hide() form.find(".md-write-holder").hide()
form.find(".md-preview-holder").show() form.find(".md-preview-holder").show()
preview = form.find(".js-md-preview") renderMarkdown()
mdText = form.find(".markdown-area").val()
if mdText.trim().length is 0
preview.text "Nothing to preview."
else
preview.text "Loading..."
$.post($(this).data("url"),
md_text: mdText
).success (previewData) ->
preview.html previewData
# Write button # Write button
$(document).off "click", ".js-md-write-button" $(document).off "click", ".js-md-write-button"
...@@ -133,6 +129,40 @@ class @DropzoneInput ...@@ -133,6 +129,40 @@ class @DropzoneInput
child = $(dropzone[0]).children("textarea") child = $(dropzone[0]).children("textarea")
hideReferencedUsers = ->
referencedUsers = form.find(".js-referenced-users")
referencedUsers.hide()
renderReferencedUsers = (users) ->
referencedUsers = form.find(".js-referenced-users")
if referencedUsers.length
if users.length >= 10
referencedUsers.show()
referencedUsers.find(".js-referenced-users-count").text users.length
else
referencedUsers.hide()
renderMarkdown = ->
preview = form.find(".js-md-preview")
mdText = form.find(".markdown-area").val()
if mdText.trim().length is 0
preview.text "Nothing to preview."
hideReferencedUsers()
else
preview.text "Loading..."
$.ajax(
type: "POST",
url: markdown_preview_path,
data: {
text: mdText
},
dataType: "json"
).success (data) ->
preview.html data.body
renderReferencedUsers data.references.users
formatLink = (link) -> formatLink = (link) ->
text = "[#{link.alt}](#{link.url})" text = "[#{link.alt}](#{link.url})"
text = "!#{text}" if link.is_image text = "!#{text}" if link.is_image
......
...@@ -10,7 +10,7 @@ GitLab.GfmAutoComplete = ...@@ -10,7 +10,7 @@ GitLab.GfmAutoComplete =
# Team Members # Team Members
Members: Members:
template: '<li>${username} <small>${name}</small></li>' template: '<li>${username} <small>${title}</small></li>'
# Issues and MergeRequests # Issues and MergeRequests
Issues: Issues:
...@@ -34,7 +34,13 @@ GitLab.GfmAutoComplete = ...@@ -34,7 +34,13 @@ GitLab.GfmAutoComplete =
searchKey: 'search' searchKey: 'search'
callbacks: callbacks:
beforeSave: (members) -> beforeSave: (members) ->
$.map members, (m) -> name: m.name, username: m.username, search: "#{m.username} #{m.name}" $.map members, (m) ->
title = m.name
title += " (#{m.count})" if m.count
username: m.username
title: sanitize(title)
search: sanitize("#{m.username} #{m.name}")
input.atwho input.atwho
at: '#' at: '#'
...@@ -44,7 +50,10 @@ GitLab.GfmAutoComplete = ...@@ -44,7 +50,10 @@ GitLab.GfmAutoComplete =
insertTpl: '${atwho-at}${id}' insertTpl: '${atwho-at}${id}'
callbacks: callbacks:
beforeSave: (issues) -> beforeSave: (issues) ->
$.map issues, (i) -> id: i.iid, title: sanitize(i.title), search: "#{i.iid} #{i.title}" $.map issues, (i) ->
id: i.iid
title: sanitize(i.title)
search: "#{i.iid} #{i.title}"
input.atwho input.atwho
at: '!' at: '!'
...@@ -54,7 +63,10 @@ GitLab.GfmAutoComplete = ...@@ -54,7 +63,10 @@ GitLab.GfmAutoComplete =
insertTpl: '${atwho-at}${id}' insertTpl: '${atwho-at}${id}'
callbacks: callbacks:
beforeSave: (merges) -> beforeSave: (merges) ->
$.map merges, (m) -> id: m.iid, title: sanitize(m.title), search: "#{m.iid} #{m.title}" $.map merges, (m) ->
id: m.iid
title: sanitize(m.title)
search: "#{m.iid} #{m.title}"
input.one 'focus', => input.one 'focus', =>
$.getJSON(@dataSource).done (data) -> $.getJSON(@dataSource).done (data) ->
......
...@@ -52,6 +52,22 @@ ...@@ -52,6 +52,22 @@
transition: opacity 200ms ease-in-out; transition: opacity 200ms ease-in-out;
} }
.md-area {
position: relative;
}
.md-header ul {
float: left;
}
.js-referenced-users {
padding: 10px 0;
color: #999;
margin-left: 10px;
margin-top: 1px;
margin-right: 130px;
}
.md-preview-holder { .md-preview-holder {
background: #FFF; background: #FFF;
border: 1px solid #ddd; border: 1px solid #ddd;
......
...@@ -19,6 +19,10 @@ ...@@ -19,6 +19,10 @@
} }
} }
.js-referenced-users {
margin-right: 0;
}
.issues-filters, .issues-filters,
.dash-projects-filters, .dash-projects-filters,
.check-all-holder { .check-all-holder {
......
.zennable { .zennable {
position: relative;
.zen-toggle-comment { .zen-toggle-comment {
display: none; display: none;
} }
...@@ -8,8 +6,9 @@ ...@@ -8,8 +6,9 @@
.zen-enter-link { .zen-enter-link {
color: #888; color: #888;
position: absolute; position: absolute;
top: -26px; top: 0px;
right: 4px; right: 4px;
line-height: 40px;
} }
.zen-leave-link { .zen-leave-link {
......
...@@ -39,11 +39,8 @@ ...@@ -39,11 +39,8 @@
.new_note, .edit_note { .new_note, .edit_note {
.buttons { .buttons {
float: left;
margin-top: 8px; margin-top: 8px;
} margin-bottom: 3px;
.clearfix {
margin-bottom: 0;
} }
.note-preview-holder { .note-preview-holder {
...@@ -82,7 +79,6 @@ ...@@ -82,7 +79,6 @@
.note-form-actions { .note-form-actions {
background: #F9F9F9; background: #F9F9F9;
height: 45px;
.note-form-option { .note-form-option {
margin-top: 8px; margin-top: 8px;
......
...@@ -151,7 +151,17 @@ class ProjectsController < ApplicationController ...@@ -151,7 +151,17 @@ class ProjectsController < ApplicationController
end end
def markdown_preview def markdown_preview
render text: view_context.markdown(params[:md_text]) text = params[:text]
ext = Gitlab::ReferenceExtractor.new(@project, current_user)
ext.analyze(text)
render json: {
body: view_context.markdown(text),
references: {
users: ext.users.map(&:username)
}
}
end end
private private
......
...@@ -38,13 +38,13 @@ module Projects ...@@ -38,13 +38,13 @@ module Projects
def groups def groups
current_user.authorized_groups.sort_by(&:path).map do |group| current_user.authorized_groups.sort_by(&:path).map do |group|
count = group.users.count count = group.users.count
{ username: group.path, name: "#{group.name} (#{count})" } { username: group.path, name: group.name, count: count }
end end
end end
def all_members def all_members
count = project.team.members.flatten.count count = project.team.members.flatten.count
[{ username: "all", name: "All Project and Group Members (#{count})" }] [{ username: "all", name: "All Project and Group Members", count: count }]
end end
end end
end end
...@@ -15,8 +15,10 @@ ...@@ -15,8 +15,10 @@
%meta{name: 'viewport', content: 'width=device-width, initial-scale=1, maximum-scale=1'} %meta{name: 'viewport', content: 'width=device-width, initial-scale=1, maximum-scale=1'}
%meta{name: 'theme-color', content: '#474D57'} %meta{name: 'theme-color', content: '#474D57'}
= yield(:meta_tags) = yield :meta_tags
= render 'layouts/google_analytics' if extra_config.has_key?('google_analytics_id') = render 'layouts/google_analytics' if extra_config.has_key?('google_analytics_id')
= render 'layouts/piwik' if extra_config.has_key?('piwik_url') && extra_config.has_key?('piwik_site_id') = render 'layouts/piwik' if extra_config.has_key?('piwik_url') && extra_config.has_key?('piwik_site_id')
= render 'layouts/bootlint' if Rails.env.development? = render 'layouts/bootlint' if Rails.env.development?
= yield :scripts_head
...@@ -22,5 +22,3 @@ ...@@ -22,5 +22,3 @@
= render "layouts/flash" = render "layouts/flash"
.clearfix .clearfix
= yield = yield
= yield :embedded_scripts
...@@ -8,3 +8,5 @@ ...@@ -8,3 +8,5 @@
= render "layouts/header/public", title: header_title = render "layouts/header/public", title: header_title
= render 'layouts/page', sidebar: sidebar = render 'layouts/page', sidebar: sidebar
= yield :scripts_body
...@@ -2,7 +2,13 @@ ...@@ -2,7 +2,13 @@
- header_title project_title(@project) - header_title project_title(@project)
- sidebar "project" unless sidebar - sidebar "project" unless sidebar
- content_for :embedded_scripts do - content_for :scripts_head do
-if current_user
:javascript
window.project_uploads_path = "#{namespace_project_uploads_path @project.namespace, @project}";
window.markdown_preview_path = "#{markdown_preview_namespace_project_path(@project.namespace, @project)}";
- content_for :scripts_body do
= render "layouts/init_auto_complete" if current_user = render "layouts/init_auto_complete" if current_user
= render template: "layouts/application" = render template: "layouts/application"
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
= f.label :description, 'Description', class: 'control-label' = f.label :description, 'Description', class: 'control-label'
.col-sm-10 .col-sm-10
= render layout: 'projects/md_preview', locals: { preview_class: "wiki" } do = render layout: 'projects/md_preview', locals: { preview_class: "wiki", referenced_users: true } do
= render 'projects/zen', f: f, attr: :description, = render 'projects/zen', f: f, attr: :description,
classes: 'description form-control' classes: 'description form-control'
.col-sm-12.hint .col-sm-12.hint
......
%ul.nav.nav-tabs .md-area
%li.active .md-header.clearfix
= link_to '#md-write-holder', class: 'js-md-write-button' do %ul.nav.nav-tabs
Write %li.active
%li = link_to '#md-write-holder', class: 'js-md-write-button' do
= link_to '#md-preview-holder', class: 'js-md-preview-button', Write
data: { url: markdown_preview_namespace_project_path(@project.namespace, @project) } do %li
Preview = link_to '#md-preview-holder', class: 'js-md-preview-button' do
%div Preview
.md-write-holder
= yield - if defined?(referenced_users) && referenced_users
.md.md-preview-holder.hide %span.js-referenced-users.pull-left.hide
.js-md-preview{class: (preview_class if defined?(preview_class))} = icon('exclamation-triangle')
You are about to add
%strong
%span.js-referenced-users-count 0
people
to the discussion. Proceed with caution.
%div
.md-write-holder
= yield
.md.md-preview-holder.hide
.js-md-preview{class: (preview_class if defined?(preview_class))}
...@@ -10,5 +10,3 @@ ...@@ -10,5 +10,3 @@
$('#issue_assignee_id').val("#{current_user.id}").trigger("change"); $('#issue_assignee_id').val("#{current_user.id}").trigger("change");
e.preventDefault(); e.preventDefault();
}); });
window.project_uploads_path = "#{namespace_project_uploads_path @project.namespace, @project}";
...@@ -8,5 +8,3 @@ ...@@ -8,5 +8,3 @@
$('#merge_request_assignee_id').val("#{current_user.id}").trigger("change"); $('#merge_request_assignee_id').val("#{current_user.id}").trigger("change");
e.preventDefault(); e.preventDefault();
}); });
window.project_uploads_path = "#{namespace_project_uploads_path @project.namespace, @project}";
...@@ -51,8 +51,6 @@ ...@@ -51,8 +51,6 @@
e.preventDefault(); e.preventDefault();
}); });
window.project_uploads_path = "#{namespace_project_uploads_path @project.namespace, @project}";
:javascript :javascript
var merge_request var merge_request
merge_request = new MergeRequest({ merge_request = new MergeRequest({
......
...@@ -50,5 +50,3 @@ ...@@ -50,5 +50,3 @@
dateFormat: "yy-mm-dd", dateFormat: "yy-mm-dd",
onSelect: function(dateText, inst) { $("#milestone_due_date").val(dateText) } onSelect: function(dateText, inst) { $("#milestone_due_date").val(dateText) }
}).datepicker("setDate", $.datepicker.parseDate('yy-mm-dd', $('#milestone_due_date').val())); }).datepicker("setDate", $.datepicker.parseDate('yy-mm-dd', $('#milestone_due_date').val()));
window.project_uploads_path = "#{namespace_project_uploads_path @project.namespace, @project}";
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
= f.hidden_field :noteable_id = f.hidden_field :noteable_id
= f.hidden_field :noteable_type = f.hidden_field :noteable_type
= render layout: 'projects/md_preview', locals: { preview_class: "note-text" } do = render layout: 'projects/md_preview', locals: { preview_class: "note-text", referenced_users: true } do
= render 'projects/zen', f: f, attr: :note, = render 'projects/zen', f: f, attr: :note,
classes: 'note_text js-note-text' classes: 'note_text js-note-text'
...@@ -15,10 +15,7 @@ ...@@ -15,10 +15,7 @@
.error-alert .error-alert
.note-form-actions .note-form-actions
.buttons .buttons.clearfix
= f.submit 'Add Comment', class: "btn comment-btn btn-grouped js-comment-button" = f.submit 'Add Comment', class: "btn comment-btn btn-grouped js-comment-button"
= yield(:note_actions) = yield(:note_actions)
%a.btn.grouped.js-close-discussion-note-form Cancel %a.btn.grouped.js-close-discussion-note-form Cancel
:javascript
window.project_uploads_path = "#{namespace_project_uploads_path @project.namespace, @project}";
...@@ -41,6 +41,3 @@ ...@@ -41,6 +41,3 @@
- else - else
= f.submit 'Create page', class: "btn-create btn" = f.submit 'Create page', class: "btn-create btn"
= link_to "Cancel", namespace_project_wiki_path(@project.namespace, @project, :home), class: "btn btn-cancel" = link_to "Cancel", namespace_project_wiki_path(@project.namespace, @project, :home), class: "btn btn-cancel"
:javascript
window.project_uploads_path = "#{namespace_project_uploads_path @project.namespace, @project}";
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