Commit e5a4b269 authored by Fatih Acet's avatar Fatih Acet

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into milestone-tooltip

parents 58456e26 b4812e2e
...@@ -61,6 +61,8 @@ update-knapsack: ...@@ -61,6 +61,8 @@ update-knapsack:
- scripts/merge-reports knapsack/rspec_report.json knapsack/rspec_node_*.json - scripts/merge-reports knapsack/rspec_report.json knapsack/rspec_node_*.json
- scripts/merge-reports knapsack/spinach_report.json knapsack/spinach_node_*.json - scripts/merge-reports knapsack/spinach_report.json knapsack/spinach_node_*.json
- rm -f knapsack/*_node_*.json - rm -f knapsack/*_node_*.json
only:
- master
# Execute all testing suites # Execute all testing suites
......
...@@ -1088,6 +1088,9 @@ Rails/TimeZone: ...@@ -1088,6 +1088,9 @@ Rails/TimeZone:
Rails/Validation: Rails/Validation:
Enabled: false Enabled: false
Rails/UniqBeforePluck:
Enabled: false
##################### RSpec ################################## ##################### RSpec ##################################
# Check that instances are not being stubbed globally. # Check that instances are not being stubbed globally.
......
...@@ -9,6 +9,7 @@ v 8.9.0 (unreleased) ...@@ -9,6 +9,7 @@ v 8.9.0 (unreleased)
- Make EmailsOnPushWorker use Sidekiq mailers queue - Make EmailsOnPushWorker use Sidekiq mailers queue
- Fix wiki page events' webhook to point to the wiki repository - Fix wiki page events' webhook to point to the wiki repository
- Fix issue todo not remove when leave project !4150 (Long Nguyen) - Fix issue todo not remove when leave project !4150 (Long Nguyen)
- Allow customisable text on the 'nearly there' page after a user signs up
- Bump recaptcha gem to 3.0.0 to remove deprecated stoken support - Bump recaptcha gem to 3.0.0 to remove deprecated stoken support
- Allow forking projects with restricted visibility level - Allow forking projects with restricted visibility level
- Improve note validation to prevent errors when creating invalid note via API - Improve note validation to prevent errors when creating invalid note via API
...@@ -18,6 +19,7 @@ v 8.9.0 (unreleased) ...@@ -18,6 +19,7 @@ v 8.9.0 (unreleased)
- Redesign navigation for project pages - Redesign navigation for project pages
- Fix groups API to list only user's accessible projects - Fix groups API to list only user's accessible projects
- Redesign account and email confirmation emails - Redesign account and email confirmation emails
- `git clone https://host/namespace/project` now works, in addition to using the `.git` suffix
- Bump nokogiri to 1.6.8 - Bump nokogiri to 1.6.8
- Use gitlab-shell v3.0.0 - Use gitlab-shell v3.0.0
- Use Knapsack to evenly distribute tests across multiple nodes - Use Knapsack to evenly distribute tests across multiple nodes
...@@ -50,6 +52,8 @@ v 8.9.0 (unreleased) ...@@ -50,6 +52,8 @@ v 8.9.0 (unreleased)
- Replace Colorize with Rainbow for coloring console output in Rake tasks. - Replace Colorize with Rainbow for coloring console output in Rake tasks.
- An indicator is now displayed at the top of the comment field for confidential issues. - An indicator is now displayed at the top of the comment field for confidential issues.
- RepositoryCheck::SingleRepositoryWorker public and private methods are now instrumented - RepositoryCheck::SingleRepositoryWorker public and private methods are now instrumented
- Improve issuables APIs performance when accessing notes !4471
- External links now open in a new tab
v 8.8.4 (unreleased) v 8.8.4 (unreleased)
- Ensure branch cleanup regardless of whether the GitHub import process succeeds - Ensure branch cleanup regardless of whether the GitHub import process succeeds
......
...@@ -142,15 +142,26 @@ ...@@ -142,15 +142,26 @@
} }
&.btn-grouped { &.btn-grouped {
margin-right: 7px; margin-right: $btn-side-margin;
float: left; float: left;
&.inline {
float: none;
}
&:last-child { &:last-child {
margin-right: 0; margin-right: 0;
} }
&.btn-sm {
margin-right: $btn-sm-side-margin;
}
&.btn-xs { &.btn-xs {
margin-right: 3px; margin-right: $btn-xs-side-margin;
} }
} }
&.disabled { &.disabled {
pointer-events: auto !important; pointer-events: auto !important;
} }
......
...@@ -124,6 +124,7 @@ ...@@ -124,6 +124,7 @@
position: relative; position: relative;
padding: 5px 10px; padding: 5px 10px;
color: $dropdown-link-color; color: $dropdown-link-color;
line-height: initial;
text-overflow: ellipsis; text-overflow: ellipsis;
border-radius: 2px; border-radius: 2px;
white-space: nowrap; white-space: nowrap;
......
...@@ -79,6 +79,9 @@ $provider-btn-not-active-color: #4688f1; ...@@ -79,6 +79,9 @@ $provider-btn-not-active-color: #4688f1;
$link-underline-blue: #4a8bee; $link-underline-blue: #4a8bee;
$layout-link-gray: #7e7c7c; $layout-link-gray: #7e7c7c;
$todo-alert-blue: #428bca; $todo-alert-blue: #428bca;
$btn-side-margin: 7px;
$btn-sm-side-margin: 5px;
$btn-xs-side-margin: 5px;
/* /*
* Color schema * Color schema
...@@ -121,7 +124,7 @@ $border-white-normal: #d6dae2; ...@@ -121,7 +124,7 @@ $border-white-normal: #d6dae2;
$border-white-dark: #c6cacf; $border-white-dark: #c6cacf;
$border-gray-light: #dcdcdc; $border-gray-light: #dcdcdc;
$border-gray-normal: rgba(0, 0, 0, 0.10); $border-gray-normal: #d7d7d7;
$border-gray-dark: #c6cacf; $border-gray-dark: #c6cacf;
$border-green-light: #2faa60; $border-green-light: #2faa60;
......
...@@ -2,13 +2,21 @@ ...@@ -2,13 +2,21 @@
margin-bottom: 20px; margin-bottom: 20px;
border-bottom: 1px solid #eee; border-bottom: 1px solid #eee;
> h1 { > h1, h2, h3, h4, h5, h6 {
font-weight: 400; font-weight: 400;
} }
.lead { .lead {
margin-bottom: 20px; margin-bottom: 20px;
} }
ul, ol {
padding-left: 0;
}
li {
list-style-type: none;
}
} }
.confirmation-content { .confirmation-content {
......
...@@ -74,6 +74,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController ...@@ -74,6 +74,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:two_factor_grace_period, :two_factor_grace_period,
:gravatar_enabled, :gravatar_enabled,
:sign_in_text, :sign_in_text,
:after_sign_up_text,
:help_page_text, :help_page_text,
:home_page_url, :home_page_url,
:after_sign_out_path, :after_sign_out_path,
......
...@@ -14,6 +14,7 @@ class SessionsController < Devise::SessionsController ...@@ -14,6 +14,7 @@ class SessionsController < Devise::SessionsController
before_action :load_recaptcha before_action :load_recaptcha
def new def new
set_minimum_password_length
if Gitlab.config.ldap.enabled if Gitlab.config.ldap.enabled
@ldap_servers = Gitlab::LDAP::Config.servers @ldap_servers = Gitlab::LDAP::Config.servers
else else
......
...@@ -15,6 +15,10 @@ module ApplicationSettingsHelper ...@@ -15,6 +15,10 @@ module ApplicationSettingsHelper
current_application_settings.sign_in_text current_application_settings.sign_in_text
end end
def after_sign_up_text
current_application_settings.after_sign_up_text
end
def shared_runners_text def shared_runners_text
current_application_settings.shared_runners_text current_application_settings.shared_runners_text
end end
......
...@@ -113,7 +113,10 @@ class ApplicationSetting < ActiveRecord::Base ...@@ -113,7 +113,10 @@ class ApplicationSetting < ActiveRecord::Base
signup_enabled: Settings.gitlab['signup_enabled'], signup_enabled: Settings.gitlab['signup_enabled'],
signin_enabled: Settings.gitlab['signin_enabled'], signin_enabled: Settings.gitlab['signin_enabled'],
gravatar_enabled: Settings.gravatar['enabled'], gravatar_enabled: Settings.gravatar['enabled'],
sign_in_text: Settings.extra['sign_in_text'], sign_in_text: nil,
after_sign_up_text: nil,
help_page_text: nil,
shared_runners_text: nil,
restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'], restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'],
max_attachment_size: Settings.gitlab['max_attachment_size'], max_attachment_size: Settings.gitlab['max_attachment_size'],
session_expire_delay: Settings.gitlab['session_expire_delay'], session_expire_delay: Settings.gitlab['session_expire_delay'],
......
...@@ -198,7 +198,7 @@ class Commit ...@@ -198,7 +198,7 @@ class Commit
end end
def notes_with_associations def notes_with_associations
notes.includes(:author, :project) notes.includes(:author)
end end
def method_missing(m, *args, &block) def method_missing(m, *args, &block)
......
...@@ -17,7 +17,12 @@ module Issuable ...@@ -17,7 +17,12 @@ module Issuable
belongs_to :assignee, class_name: "User" belongs_to :assignee, class_name: "User"
belongs_to :updated_by, class_name: "User" belongs_to :updated_by, class_name: "User"
belongs_to :milestone belongs_to :milestone
has_many :notes, as: :noteable, dependent: :destroy has_many :notes, as: :noteable, dependent: :destroy do
def authors_loaded?
# We check first if we're loaded to not load unnecesarily.
loaded? && to_a.all? { |note| note.association(:author).loaded? }
end
end
has_many :label_links, as: :target, dependent: :destroy has_many :label_links, as: :target, dependent: :destroy
has_many :labels, through: :label_links has_many :labels, through: :label_links
has_many :todos, as: :target, dependent: :destroy has_many :todos, as: :target, dependent: :destroy
...@@ -44,6 +49,7 @@ module Issuable ...@@ -44,6 +49,7 @@ module Issuable
scope :without_label, -> { joins("LEFT OUTER JOIN label_links ON label_links.target_type = '#{name}' AND label_links.target_id = #{table_name}.id").where(label_links: { id: nil }) } scope :without_label, -> { joins("LEFT OUTER JOIN label_links ON label_links.target_type = '#{name}' AND label_links.target_id = #{table_name}.id").where(label_links: { id: nil }) }
scope :join_project, -> { joins(:project) } scope :join_project, -> { joins(:project) }
scope :inc_notes_with_associations, -> { includes(notes: :author) }
scope :references_project, -> { references(:project) } scope :references_project, -> { references(:project) }
scope :non_archived, -> { join_project.where(projects: { archived: false }) } scope :non_archived, -> { join_project.where(projects: { archived: false }) }
...@@ -179,8 +185,14 @@ module Issuable ...@@ -179,8 +185,14 @@ module Issuable
end end
def user_notes_count def user_notes_count
if notes.loaded?
# Use the in-memory association to select and count to avoid hitting the db
notes.to_a.count { |note| !note.system? }
else
# do the count query
notes.user.count notes.user.count
end end
end
def subscribed_without_subscriptions?(user) def subscribed_without_subscriptions?(user)
participants(user).include?(user) participants(user).include?(user)
...@@ -239,7 +251,13 @@ module Issuable ...@@ -239,7 +251,13 @@ module Issuable
end end
def notes_with_associations def notes_with_associations
notes.includes(:author, :project) # If A has_many Bs, and B has_many Cs, and you do
# `A.includes(b: :c).each { |a| a.b.includes(:c) }`, sadly ActiveRecord
# will do the inclusion again. So, we check if all notes in the relation
# already have their authors loaded (possibly because the scope
# `inc_notes_with_associations` was used) and skip the inclusion if that's
# the case.
notes.authors_loaded? ? notes : notes.includes(:author)
end end
def updated_tasks def updated_tasks
......
...@@ -102,7 +102,7 @@ class Snippet < ActiveRecord::Base ...@@ -102,7 +102,7 @@ class Snippet < ActiveRecord::Base
end end
def notes_with_associations def notes_with_associations
notes.includes(:author, :project) notes.includes(:author)
end end
class << self class << self
......
...@@ -154,6 +154,11 @@ ...@@ -154,6 +154,11 @@
.col-sm-10 .col-sm-10
= f.text_area :sign_in_text, class: 'form-control', rows: 4 = f.text_area :sign_in_text, class: 'form-control', rows: 4
.help-block Markdown enabled .help-block Markdown enabled
.form-group
= f.label :after_sign_up_text, class: 'control-label col-sm-2'
.col-sm-10
= f.text_area :after_sign_up_text, class: 'form-control', rows: 4
.help-block Markdown enabled
.form-group .form-group
= f.label :help_page_text, class: 'control-label col-sm-2' = f.label :help_page_text, class: 'control-label col-sm-2'
.col-sm-10 .col-sm-10
......
...@@ -9,5 +9,4 @@ ...@@ -9,5 +9,4 @@
- if current_user.can_create_group? - if current_user.can_create_group?
.nav-controls .nav-controls
= link_to new_group_path, class: "btn btn-new" do = link_to new_group_path, class: "btn btn-new" do
= icon('plus')
New Group New Group
...@@ -18,5 +18,4 @@ ...@@ -18,5 +18,4 @@
= render 'shared/projects/dropdown' = render 'shared/projects/dropdown'
- if current_user.can_create_project? - if current_user.can_create_project?
= link_to new_project_path, class: 'btn btn-new' do = link_to new_project_path, class: 'btn btn-new' do
= icon('plus')
New Project New Project
...@@ -3,6 +3,9 @@ ...@@ -3,6 +3,9 @@
Almost there... Almost there...
%p.lead %p.lead
Please check your email to confirm your account Please check your email to confirm your account
- if after_sign_up_text.present?
.well-confirmation.text-center
= markdown(after_sign_up_text)
%p.confirmation-content.text-center %p.confirmation-content.text-center
No confirmation email received? Please check your spam folder or No confirmation email received? Please check your spam folder or
.append-bottom-20.prepend-top-20.text-center .append-bottom-20.prepend-top-20.text-center
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
%div %div
= f.email_field :email, class: "form-control middle", placeholder: "Email", required: true = f.email_field :email, class: "form-control middle", placeholder: "Email", required: true
.form-group.append-bottom-20#password-strength .form-group.append-bottom-20#password-strength
= f.password_field :password, class: "form-control bottom", placeholder: "Password", required: true = f.password_field :password, class: "form-control bottom", placeholder: "Password - minimum length #{@minimum_password_length} characters", required: true, pattern: ".{#{@minimum_password_length},}", title: "Minimum length is #{@minimum_password_length} characters"
%div %div
- if current_application_settings.recaptcha_enabled - if current_application_settings.recaptcha_enabled
= recaptcha_tags = recaptcha_tags
......
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
- if can?(current_user, :update_group_member, member) - if can?(current_user, :update_group_member, member)
= button_tag class: "btn-xs btn js-toggle-button", = button_tag class: "btn-xs btn js-toggle-button",
title: 'Edit access level', type: 'button' do title: 'Edit access level', type: 'button' do
%i.fa.fa-pencil-square-o = icon('pencil')
- if can?(current_user, :destroy_group_member, member) - if can?(current_user, :destroy_group_member, member)
&nbsp; &nbsp;
...@@ -46,7 +46,7 @@ ...@@ -46,7 +46,7 @@
Leave Leave
- else - else
= link_to group_group_member_path(@group, member), data: { confirm: remove_user_from_group_message(@group, member) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from group' do = link_to group_group_member_path(@group, member), data: { confirm: remove_user_from_group_message(@group, member) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from group' do
%i.fa.fa-minus.fa-inverse = icon('trash')
.edit-member.hide.js-toggle-content .edit-member.hide.js-toggle-content
%br %br
......
...@@ -35,7 +35,6 @@ ...@@ -35,7 +35,6 @@
= render 'shared/projects/dropdown' = render 'shared/projects/dropdown'
- if can? current_user, :create_projects, @group - if can? current_user, :create_projects, @group
= link_to new_project_path(namespace_id: @group.id), class: 'btn btn-new pull-right' do = link_to new_project_path(namespace_id: @group.id), class: 'btn btn-new pull-right' do
= icon('plus')
New Project New Project
.tab-content .tab-content
......
...@@ -2,106 +2,102 @@ ...@@ -2,106 +2,102 @@
= nav_link(controller: :dashboard, html_options: {class: 'home'}) do = nav_link(controller: :dashboard, html_options: {class: 'home'}) do
= link_to admin_root_path, title: 'Overview' do = link_to admin_root_path, title: 'Overview' do
= icon('dashboard fw') = icon('dashboard fw')
%span .nav-link-text
Overview Overview
= nav_link(controller: [:admin, :projects]) do = nav_link(controller: [:admin, :projects]) do
= link_to admin_namespaces_projects_path, title: 'Projects' do = link_to admin_namespaces_projects_path, title: 'Projects' do
= icon('cube fw') = icon('cube fw')
%span .nav-link-text
Projects Projects
= nav_link(controller: :users) do = nav_link(controller: :users) do
= link_to admin_users_path, title: 'Users' do = link_to admin_users_path, title: 'Users' do
= icon('user fw') = icon('user fw')
%span .nav-link-text
Users Users
= nav_link(controller: :groups) do = nav_link(controller: :groups) do
= link_to admin_groups_path, title: 'Groups' do = link_to admin_groups_path, title: 'Groups' do
= icon('group fw') = icon('group fw')
%span .nav-link-text
Groups Groups
= nav_link(controller: :deploy_keys) do = nav_link(controller: :deploy_keys) do
= link_to admin_deploy_keys_path, title: 'Deploy Keys' do = link_to admin_deploy_keys_path, title: 'Deploy Keys' do
= icon('key fw') = icon('key fw')
%span .nav-link-text
Deploy Keys Deploy Keys
= nav_link path: ['runners#index', 'runners#show'] do = nav_link path: ['runners#index', 'runners#show'] do
= link_to admin_runners_path, title: 'Runners' do = link_to admin_runners_path, title: 'Runners' do
= icon('cog fw') = icon('cog fw')
%span .nav-link-text
Runners Runners
%span.count= number_with_delimiter(Ci::Runner.count(:all))
= nav_link path: 'builds#index' do = nav_link path: 'builds#index' do
= link_to admin_builds_path, title: 'Builds' do = link_to admin_builds_path, title: 'Builds' do
= icon('link fw') = icon('link fw')
%span .nav-link-text
Builds Builds
%span.count= number_with_delimiter(Ci::Build.count(:all))
= nav_link(controller: :logs) do = nav_link(controller: :logs) do
= link_to admin_logs_path, title: 'Logs' do = link_to admin_logs_path, title: 'Logs' do
= icon('file-text fw') = icon('file-text fw')
%span .nav-link-text
Logs Logs
= nav_link(controller: :health_check) do = nav_link(controller: :health_check) do
= link_to admin_health_check_path, title: 'Health Check' do = link_to admin_health_check_path, title: 'Health Check' do
= icon('medkit fw') = icon('medkit fw')
%span .nav-link-text
Health Check Health Check
= nav_link(controller: :broadcast_messages) do = nav_link(controller: :broadcast_messages) do
= link_to admin_broadcast_messages_path, title: 'Messages' do = link_to admin_broadcast_messages_path, title: 'Messages' do
= icon('bullhorn fw') = icon('bullhorn fw')
%span .nav-link-text
Messages Messages
= nav_link(controller: :hooks) do = nav_link(controller: :hooks) do
= link_to admin_hooks_path, title: 'Hooks' do = link_to admin_hooks_path, title: 'Hooks' do
= icon('external-link fw') = icon('external-link fw')
%span .nav-link-text
Hooks Hooks
= nav_link(controller: :background_jobs) do = nav_link(controller: :background_jobs) do
= link_to admin_background_jobs_path, title: 'Background Jobs' do = link_to admin_background_jobs_path, title: 'Background Jobs' do
= icon('cog fw') = icon('cog fw')
%span .nav-link-text
Background Jobs Background Jobs
= nav_link(controller: :appearances) do = nav_link(controller: :appearances) do
= link_to admin_appearances_path, title: 'Appearances' do = link_to admin_appearances_path, title: 'Appearances' do
= icon('image') = icon('image')
%span .nav-link-text
Appearance Appearance
= nav_link(controller: :applications) do = nav_link(controller: :applications) do
= link_to admin_applications_path, title: 'Applications' do = link_to admin_applications_path, title: 'Applications' do
= icon('cloud fw') = icon('cloud fw')
%span .nav-link-text
Applications Applications
= nav_link(controller: :services) do = nav_link(controller: :services) do
= link_to admin_application_settings_services_path, title: 'Service Templates' do = link_to admin_application_settings_services_path, title: 'Service Templates' do
= icon('copy fw') = icon('copy fw')
%span .nav-link-text
Service Templates Service Templates
= nav_link(controller: :labels) do = nav_link(controller: :labels) do
= link_to admin_labels_path, title: 'Labels' do = link_to admin_labels_path, title: 'Labels' do
= icon('tags fw') = icon('tags fw')
%span .nav-link-text
Labels Labels
= nav_link(controller: :abuse_reports) do = nav_link(controller: :abuse_reports) do
= link_to admin_abuse_reports_path, title: "Abuse Reports" do = link_to admin_abuse_reports_path, title: "Abuse Reports" do
= icon('exclamation-circle fw') = icon('exclamation-circle fw')
%span .nav-link-text
Abuse Reports Abuse Reports
%span.count= number_with_delimiter(AbuseReport.count(:all))
- if askimet_enabled? - if askimet_enabled?
= nav_link(controller: :spam_logs) do = nav_link(controller: :spam_logs) do
= link_to admin_spam_logs_path, title: "Spam Logs" do = link_to admin_spam_logs_path, title: "Spam Logs" do
= icon('exclamation-triangle fw') = icon('exclamation-triangle fw')
%span .nav-link-text
Spam Logs Spam Logs
%span.count= number_with_delimiter(SpamLog.count(:all))
= nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do = nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do
= link_to admin_application_settings_path, title: 'Settings' do = link_to admin_application_settings_path, title: 'Settings' do
= icon('cogs fw') = icon('cogs fw')
%span .nav-link-text
Settings Settings
...@@ -2,20 +2,20 @@ ...@@ -2,20 +2,20 @@
= nav_link(path: ['dashboard#show', 'root#show', 'projects#trending', 'projects#starred', 'projects#index'], html_options: {class: 'home'}) do = nav_link(path: ['dashboard#show', 'root#show', 'projects#trending', 'projects#starred', 'projects#index'], html_options: {class: 'home'}) do
= link_to explore_root_path, title: 'Projects' do = link_to explore_root_path, title: 'Projects' do
= icon('bookmark fw') = icon('bookmark fw')
%span .nav-link-text
Projects Projects
= nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do = nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do
= link_to explore_groups_path, title: 'Groups' do = link_to explore_groups_path, title: 'Groups' do
= icon('group fw') = icon('group fw')
%span .nav-link-text
Groups Groups
= nav_link(controller: :snippets) do = nav_link(controller: :snippets) do
= link_to explore_snippets_path, title: 'Snippets' do = link_to explore_snippets_path, title: 'Snippets' do
= icon('clipboard fw') = icon('clipboard fw')
%span .nav-link-text
Snippets Snippets
= nav_link(controller: :help) do = nav_link(controller: :help) do
= link_to help_path, title: 'Help' do = link_to help_path, title: 'Help' do
= icon('question-circle fw') = icon('question-circle fw')
%span .nav-link-text
Help Help
...@@ -21,12 +21,10 @@ ...@@ -21,12 +21,10 @@
.controls.hidden-xs .controls.hidden-xs
- if create_mr_button?(@repository.root_ref, branch.name) - if create_mr_button?(@repository.root_ref, branch.name)
= link_to create_mr_path(@repository.root_ref, branch.name), class: 'btn btn-grouped btn-xs' do = link_to create_mr_path(@repository.root_ref, branch.name), class: 'btn btn-grouped btn-xs' do
= icon('plus')
Merge Request Merge Request
- if branch.name != @repository.root_ref - if branch.name != @repository.root_ref
= link_to namespace_project_compare_index_path(@project.namespace, @project, from: @repository.root_ref, to: branch.name), class: 'btn btn-grouped btn-xs', method: :post, title: "Compare" do = link_to namespace_project_compare_index_path(@project.namespace, @project, from: @repository.root_ref, to: branch.name), class: 'btn btn-grouped btn-xs', method: :post, title: "Compare" do
= icon("exchange")
Compare Compare
- if can_remove_branch?(@project, branch.name) - if can_remove_branch?(@project, branch.name)
......
- if can?(current_user, :push_code, @project) - if can?(current_user, :push_code, @project)
.pull-right .pull-right
#new-branch{'data-path' => can_create_branch_namespace_project_issue_path(@project.namespace, @project, @issue)} #new-branch{'data-path' => can_create_branch_namespace_project_issue_path(@project.namespace, @project, @issue)}
= link_to namespace_project_branches_path(@project.namespace, @project, branch_name: @issue.to_branch_name, issue_iid: @issue.iid), method: :post, class: 'btn has-tooltip', title: @issue.to_branch_name, disabled: 'disabled' do = link_to namespace_project_branches_path(@project.namespace, @project, branch_name: @issue.to_branch_name, issue_iid: @issue.iid),
method: :post, class: 'btn has-tooltip', title: @issue.to_branch_name, disabled: 'disabled' do
.checking .checking
%i.fa.fa-spinner.fa-spin = icon('spinner spin')
Checking branches Checking branches
.available(style="display: none") .available.hide
%i.fa.fa-code-fork
New branch New branch
.unavailable(style="display: none") .unavailable.hide
%i.fa.fa-exclamation-triangle = icon('exclamation-triangle')
New branch unavailable New branch unavailable
...@@ -15,7 +15,6 @@ ...@@ -15,7 +15,6 @@
= 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, :create_issue, @project - if can? current_user, :create_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", title: "New Issue", id: "new_issue_link" do = 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", title: "New Issue", id: "new_issue_link" do
= icon('plus')
New Issue New Issue
= render 'shared/issuable/filter', type: :issues = render 'shared/issuable/filter', type: :issues
......
...@@ -38,14 +38,12 @@ ...@@ -38,14 +38,12 @@
%li %li
= link_to 'Edit', edit_namespace_project_issue_path(@project.namespace, @project, @issue) = link_to 'Edit', edit_namespace_project_issue_path(@project.namespace, @project, @issue)
- if can?(current_user, :create_issue, @project) - if can?(current_user, :create_issue, @project)
= link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'hidden-xs hidden-sm btn btn-nr btn-grouped new-issue-link btn-success', title: 'New issue', id: 'new_issue_link' do = link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'hidden-xs hidden-sm btn btn-grouped new-issue-link btn-success', title: 'New issue', id: 'new_issue_link' do
= icon('plus')
New issue New issue
- if can?(current_user, :update_issue, @issue) - if can?(current_user, :update_issue, @issue)
= link_to 'Reopen issue', issue_path(@issue, issue: { state_event: :reopen }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue' = link_to 'Reopen issue', issue_path(@issue, issue: { state_event: :reopen }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-grouped btn-reopen #{issue_button_visibility(@issue, false)}", title: 'Reopen issue'
= link_to 'Close issue', issue_path(@issue, issue: { state_event: :close }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-close #{issue_button_visibility(@issue, true)}", title: 'Close issue' = link_to 'Close issue', issue_path(@issue, issue: { state_event: :close }, status_only: true, format: 'json'), data: {no_turbolink: true}, class: "hidden-xs hidden-sm btn btn-grouped btn-close #{issue_button_visibility(@issue, true)}", title: 'Close issue'
= link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'hidden-xs hidden-sm btn btn-nr btn-grouped issuable-edit' do = link_to edit_namespace_project_issue_path(@project.namespace, @project, @issue), class: 'hidden-xs hidden-sm btn btn-grouped issuable-edit' do
= icon('pencil-square-o')
Edit Edit
......
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
.nav-controls .nav-controls
- if can?(current_user, :admin_label, @project) - if can?(current_user, :admin_label, @project)
= link_to new_namespace_project_label_path(@project.namespace, @project), class: "btn btn-new" do = link_to new_namespace_project_label_path(@project.namespace, @project), class: "btn btn-new" do
= icon('plus')
New label New label
.labels .labels
......
...@@ -14,13 +14,11 @@ ...@@ -14,13 +14,11 @@
- if @merge_request.open? - if @merge_request.open?
.pull-right .pull-right
- if @merge_request.source_branch_exists? - if @merge_request.source_branch_exists?
= link_to "#modal_merge_info", class: "btn btn-sm", "data-toggle" => "modal" do = link_to "#modal_merge_info", class: "btn inline btn-grouped btn-sm", "data-toggle" => "modal" do
= icon('cloud-download fw')
Check out branch Check out branch
%span.dropdown %span.dropdown
%a.btn.btn-sm.dropdown-toggle{ data: {toggle: :dropdown} } %a.btn.btn-sm.dropdown-toggle{ data: {toggle: :dropdown} }
= icon('download')
Download as Download as
%span.caret %span.caret
%ul.dropdown-menu %ul.dropdown-menu
......
...@@ -10,7 +10,6 @@ ...@@ -10,7 +10,6 @@
- merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project)) - merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project))
- if merge_project - if merge_project
= link_to new_namespace_project_merge_request_path(merge_project.namespace, merge_project), class: "btn btn-new", title: "New Merge Request" do = link_to new_namespace_project_merge_request_path(merge_project.namespace, merge_project), class: "btn btn-new", title: "New Merge Request" do
= icon('plus')
New Merge Request New Merge Request
= render 'shared/issuable/filter', type: :merge_requests = render 'shared/issuable/filter', type: :merge_requests
......
...@@ -25,8 +25,7 @@ ...@@ -25,8 +25,7 @@
= link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: 'reopen-mr-link', title: 'Reopen merge request' = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: 'reopen-mr-link', title: 'Reopen merge request'
%li %li
= link_to 'Edit', edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'issuable-edit' = link_to 'Edit', edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'issuable-edit'
= link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-close #{issue_button_visibility(@merge_request, true)}", title: 'Close merge request' = link_to 'Close', merge_request_path(@merge_request, merge_request: { state_event: :close }), method: :put, class: "hidden-xs hidden-sm btn btn-grouped btn-close #{issue_button_visibility(@merge_request, true)}", title: 'Close merge request'
= link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "hidden-xs hidden-sm btn btn-nr btn-grouped btn-reopen reopen-mr-link #{issue_button_visibility(@merge_request, false)}", title: 'Reopen merge request' = link_to 'Reopen', merge_request_path(@merge_request, merge_request: {state_event: :reopen }), method: :put, class: "hidden-xs hidden-sm btn btn-grouped btn-reopen reopen-mr-link #{issue_button_visibility(@merge_request, false)}", title: 'Reopen merge request'
= link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: "hidden-xs hidden-sm btn btn-nr btn-grouped issuable-edit" do = link_to edit_namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: "hidden-xs hidden-sm btn btn-grouped issuable-edit" do
= icon('pencil-square-o')
Edit Edit
...@@ -7,7 +7,6 @@ ...@@ -7,7 +7,6 @@
- if can?(current_user, :admin_group_member, @group) - if can?(current_user, :admin_group_member, @group)
.controls .controls
= link_to group_group_members_path(@group), class: 'btn' do = link_to group_group_members_path(@group), class: 'btn' do
= icon('pencil-square-o')
Manage group members Manage group members
%ul.content-list %ul.content-list
- members.limit(20).each do |member| - members.limit(20).each do |member|
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
- if can?(current_user, :update_project_member, member) - if can?(current_user, :update_project_member, member)
= button_tag class: "btn-xs btn js-toggle-button", = button_tag class: "btn-xs btn js-toggle-button",
title: 'Edit access level', type: 'button' do title: 'Edit access level', type: 'button' do
%i.fa.fa-pencil-square-o = icon('pencil')
- if can?(current_user, :destroy_project_member, member) - if can?(current_user, :destroy_project_member, member)
&nbsp; &nbsp;
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
Leave Leave
- else - else
= link_to namespace_project_project_member_path(@project.namespace, @project, member), data: { confirm: remove_from_project_team_message(@project, member) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from team' do = link_to namespace_project_project_member_path(@project.namespace, @project, member), data: { confirm: remove_from_project_team_message(@project, member) }, method: :delete, remote: true, class: "btn-xs btn btn-remove", title: 'Remove user from team' do
%i.fa.fa-minus.fa-inverse = icon('trash')
.edit-member.hide.js-toggle-content .edit-member.hide.js-toggle-content
%br %br
......
- if @projects.any? - if @projects.any?
.prepend-left-10.project-item-select-holder .project-item-select-holder
= project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at' } = project_select_tag :project_path, class: "project-item-select", data: { include_groups: local_assigns[:include_groups], order_by: 'last_activity_at' }
%a.btn.btn-new.new-project-item-select-button %a.btn.btn-new.new-project-item-select-button
= icon('plus')
= local_assigns[:label] = local_assigns[:label]
%b.caret %b.caret
......
...@@ -135,7 +135,7 @@ ...@@ -135,7 +135,7 @@
.title.hide-collapsed .title.hide-collapsed
Notifications Notifications
- subscribtion_status = subscribed ? 'subscribed' : 'unsubscribed' - subscribtion_status = subscribed ? 'subscribed' : 'unsubscribed'
%button.btn.btn-block.btn-gray.js-subscribe-button.issuable-subscribe-button.hide-collapsed{ type: "button" } %button.btn.btn-block.btn-default.js-subscribe-button.issuable-subscribe-button.hide-collapsed{ type: "button" }
%span= subscribed ? 'Unsubscribe' : 'Subscribe' %span= subscribed ? 'Unsubscribe' : 'Subscribe'
.subscription-status.hide-collapsed{data: {status: subscribtion_status}} .subscription-status.hide-collapsed{data: {status: subscribtion_status}}
.unsubscribed{class: ( 'hidden' if subscribed )} .unsubscribed{class: ( 'hidden' if subscribed )}
......
...@@ -441,6 +441,23 @@ Rails.application.routes.draw do ...@@ -441,6 +441,23 @@ Rails.application.routes.draw do
resources :namespaces, path: '/', constraints: { id: /[a-zA-Z.0-9_\-]+/ }, only: [] do resources :namespaces, path: '/', constraints: { id: /[a-zA-Z.0-9_\-]+/ }, only: [] do
resources(:projects, constraints: { id: /[a-zA-Z.0-9_\-]+(?<!\.atom)/ }, except: resources(:projects, constraints: { id: /[a-zA-Z.0-9_\-]+(?<!\.atom)/ }, except:
[:new, :create, :index], path: "/") do [:new, :create, :index], path: "/") do
# Allow /info/refs, /info/refs?service=git-upload-pack, and
# /info/refs?service=git-receive-pack, but nothing else.
#
git_http_handshake = lambda do |request|
request.query_string.blank? ||
request.query_string.match(/\Aservice=git-(upload|receive)-pack\z/)
end
ref_redirect = redirect do |params, request|
path = "#{params[:namespace_id]}/#{params[:project_id]}.git/info/refs"
path << "?#{request.query_string}" unless request.query_string.blank?
path
end
get '/info/refs', constraints: git_http_handshake, to: ref_redirect
member do member do
put :transfer put :transfer
delete :remove_fork delete :remove_fork
......
class RemoveDuplicatedNotificationSettings < ActiveRecord::Migration class RemoveDuplicatedNotificationSettings < ActiveRecord::Migration
def up def up
execute <<-SQL duplicates = exec_query(%Q{
DELETE FROM notification_settings WHERE id NOT IN ( SELECT min_id from (SELECT MIN(id) as min_id FROM notification_settings GROUP BY user_id, source_type, source_id) as dups ) SELECT user_id, source_type, source_id
SQL FROM notification_settings
GROUP BY user_id, source_type, source_id
HAVING COUNT(*) > 1
})
duplicates.each do |row|
uid = row['user_id']
stype = connection.quote(row['source_type'])
sid = row['source_id']
execute(%Q{
DELETE FROM notification_settings
WHERE user_id = #{uid}
AND source_type = #{stype}
AND source_id = #{sid}
AND id != (
SELECT id FROM (
SELECT min(id) AS id
FROM notification_settings
WHERE user_id = #{uid}
AND source_type = #{stype}
AND source_id = #{sid}
) min_ids
)
})
end
end end
end end
class AddAfterSignUpTextToApplicationSettings < ActiveRecord::Migration
def change
add_column :application_settings, :after_sign_up_text, :text
end
end
...@@ -11,7 +11,8 @@ ...@@ -11,7 +11,8 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160530150109) do ActiveRecord::Schema.define(version: 20160608155312) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"
enable_extension "pg_trgm" enable_extension "pg_trgm"
...@@ -83,6 +84,7 @@ ActiveRecord::Schema.define(version: 20160530150109) do ...@@ -83,6 +84,7 @@ ActiveRecord::Schema.define(version: 20160530150109) do
t.string "health_check_access_token" t.string "health_check_access_token"
t.boolean "send_user_confirmation_email", default: false t.boolean "send_user_confirmation_email", default: false
t.integer "container_registry_token_expire_delay", default: 5 t.integer "container_registry_token_expire_delay", default: 5
t.text "after_sign_up_text"
end end
create_table "audit_events", force: :cascade do |t| create_table "audit_events", force: :cascade do |t|
...@@ -676,6 +678,7 @@ ActiveRecord::Schema.define(version: 20160530150109) do ...@@ -676,6 +678,7 @@ ActiveRecord::Schema.define(version: 20160530150109) do
end end
add_index "notification_settings", ["source_id", "source_type"], name: "index_notification_settings_on_source_id_and_source_type", using: :btree add_index "notification_settings", ["source_id", "source_type"], name: "index_notification_settings_on_source_id_and_source_type", using: :btree
add_index "notification_settings", ["user_id", "source_id", "source_type"], name: "index_notifications_on_user_id_and_source_id_and_source_type", unique: true, using: :btree
add_index "notification_settings", ["user_id"], name: "index_notification_settings_on_user_id", using: :btree add_index "notification_settings", ["user_id"], name: "index_notification_settings_on_user_id", using: :btree
create_table "oauth_access_grants", force: :cascade do |t| create_table "oauth_access_grants", force: :cascade do |t|
......
...@@ -49,8 +49,8 @@ information from database or file system ...@@ -49,8 +49,8 @@ information from database or file system
## Buttons ## Buttons
* Button should contain icon or text. Exceptions should be approved by UX designer. * Button should contain icon or text. Exceptions should be approved by UX designer.
* Use gray button on white background or white button on gray background.
* Use red button for destructive actions (not revertable). For example removing issue. * Use red button for destructive actions (not revertable). For example removing issue.
* Use green or blue button for primary action. Primary button should be only one. * Use green or blue button for primary action. Primary button should be only one.
Do not use both green and blue button in one form. Do not use both green and blue button in one form.
* For all other cases use default white button
...@@ -120,7 +120,7 @@ will need to let gitlab-workhorse listen on a TCP port. You can do this ...@@ -120,7 +120,7 @@ will need to let gitlab-workhorse listen on a TCP port. You can do this
via [/etc/default/gitlab]. via [/etc/default/gitlab].
[Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache [Apache templates]: https://gitlab.com/gitlab-org/gitlab-recipes/tree/master/web-server/apache
[/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-8-stable/lib/support/init.d/gitlab.default.example#L37 [/etc/default/gitlab]: https://gitlab.com/gitlab-org/gitlab-ce/blob/8-9-stable/lib/support/init.d/gitlab.default.example#L37
#### Init script #### Init script
...@@ -145,7 +145,7 @@ To make sure you didn't miss anything run a more thorough check: ...@@ -145,7 +145,7 @@ To make sure you didn't miss anything run a more thorough check:
If all items are green, then congratulations, the upgrade is complete! If all items are green, then congratulations, the upgrade is complete!
## Things went south? Revert to previous version (8.7) ## Things went south? Revert to previous version (8.8)
### 1. Revert the code to the previous version ### 1. Revert the code to the previous version
......
...@@ -351,6 +351,7 @@ module API ...@@ -351,6 +351,7 @@ module API
expose :signin_enabled expose :signin_enabled
expose :gravatar_enabled expose :gravatar_enabled
expose :sign_in_text expose :sign_in_text
expose :after_sign_up_text
expose :created_at expose :created_at
expose :updated_at expose :updated_at
expose :home_page_url expose :home_page_url
......
...@@ -51,7 +51,7 @@ module API ...@@ -51,7 +51,7 @@ module API
# GET /issues?labels=foo,bar # GET /issues?labels=foo,bar
# GET /issues?labels=foo,bar&state=opened # GET /issues?labels=foo,bar&state=opened
get do get do
issues = current_user.issues issues = current_user.issues.inc_notes_with_associations
issues = filter_issues_state(issues, params[:state]) unless params[:state].nil? issues = filter_issues_state(issues, params[:state]) unless params[:state].nil?
issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil? issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil?
issues.reorder(issuable_order_by => issuable_sort) issues.reorder(issuable_order_by => issuable_sort)
...@@ -82,7 +82,7 @@ module API ...@@ -82,7 +82,7 @@ module API
# GET /projects/:id/issues?milestone=1.0.0&state=closed # GET /projects/:id/issues?milestone=1.0.0&state=closed
# GET /issues?iid=42 # GET /issues?iid=42
get ":id/issues" do get ":id/issues" do
issues = user_project.issues.visible_to_user(current_user) issues = user_project.issues.inc_notes_with_associations.visible_to_user(current_user)
issues = filter_issues_state(issues, params[:state]) unless params[:state].nil? issues = filter_issues_state(issues, params[:state]) unless params[:state].nil?
issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil? issues = filter_issues_labels(issues, params[:labels]) unless params[:labels].nil?
issues = filter_by_iid(issues, params[:iid]) unless params[:iid].nil? issues = filter_by_iid(issues, params[:iid]) unless params[:iid].nil?
......
...@@ -41,7 +41,7 @@ module API ...@@ -41,7 +41,7 @@ module API
# #
get ":id/merge_requests" do get ":id/merge_requests" do
authorize! :read_merge_request, user_project authorize! :read_merge_request, user_project
merge_requests = user_project.merge_requests merge_requests = user_project.merge_requests.inc_notes_with_associations
unless params[:iid].nil? unless params[:iid].nil?
merge_requests = filter_by_iid(merge_requests, params[:iid]) merge_requests = filter_by_iid(merge_requests, params[:iid])
......
...@@ -15,6 +15,7 @@ module Banzai ...@@ -15,6 +15,7 @@ module Banzai
next if link.start_with?(internal_url) next if link.start_with?(internal_url)
node.set_attribute('rel', 'nofollow noreferrer') node.set_attribute('rel', 'nofollow noreferrer')
node.set_attribute('target', '_blank')
end end
doc doc
......
...@@ -26,7 +26,10 @@ module Gitlab ...@@ -26,7 +26,10 @@ module Gitlab
signup_enabled: Settings.gitlab['signup_enabled'], signup_enabled: Settings.gitlab['signup_enabled'],
signin_enabled: Settings.gitlab['signin_enabled'], signin_enabled: Settings.gitlab['signin_enabled'],
gravatar_enabled: Settings.gravatar['enabled'], gravatar_enabled: Settings.gravatar['enabled'],
sign_in_text: Settings.extra['sign_in_text'], sign_in_text: nil,
after_sign_up_text: nil,
help_page_text: nil,
shared_runners_text: nil,
restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'], restricted_visibility_levels: Settings.gitlab['restricted_visibility_levels'],
max_attachment_size: Settings.gitlab['max_attachment_size'], max_attachment_size: Settings.gitlab['max_attachment_size'],
session_expire_delay: Settings.gitlab['session_expire_delay'], session_expire_delay: Settings.gitlab['session_expire_delay'],
......
...@@ -165,17 +165,27 @@ describe 'GitLab Markdown', feature: true do ...@@ -165,17 +165,27 @@ describe 'GitLab Markdown', feature: true do
describe 'ExternalLinkFilter' do describe 'ExternalLinkFilter' do
it 'adds nofollow to external link' do it 'adds nofollow to external link' do
link = doc.at_css('a:contains("Google")') link = doc.at_css('a:contains("Google")')
expect(link.attr('rel')).to include('nofollow') expect(link.attr('rel')).to include('nofollow')
end end
it 'adds noreferrer to external link' do it 'adds noreferrer to external link' do
link = doc.at_css('a:contains("Google")') link = doc.at_css('a:contains("Google")')
expect(link.attr('rel')).to include('noreferrer') expect(link.attr('rel')).to include('noreferrer')
end end
it 'adds _blank to target attribute for external links' do
link = doc.at_css('a:contains("Google")')
expect(link.attr('target')).to match('_blank')
end
it 'ignores internal link' do it 'ignores internal link' do
link = doc.at_css('a:contains("GitLab Root")') link = doc.at_css('a:contains("GitLab Root")')
expect(link.attr('rel')).not_to match 'nofollow' expect(link.attr('rel')).not_to match 'nofollow'
expect(link.attr('target')).not_to match '_blank'
end end
end end
end end
......
...@@ -136,7 +136,7 @@ But it shouldn't autolink text inside certain tags: ...@@ -136,7 +136,7 @@ But it shouldn't autolink text inside certain tags:
### ExternalLinkFilter ### ExternalLinkFilter
External links get a `rel="nofollow"` attribute: External links get a `rel="nofollow noreferrer"` and `target="_blank"` attributes:
- [Google](https://google.com/) - [Google](https://google.com/)
- [GitLab Root](<%= Gitlab.config.gitlab.url %>) - [GitLab Root](<%= Gitlab.config.gitlab.url %>)
......
...@@ -10,6 +10,16 @@ describe Issue, "Issuable" do ...@@ -10,6 +10,16 @@ describe Issue, "Issuable" do
it { is_expected.to belong_to(:assignee) } it { is_expected.to belong_to(:assignee) }
it { is_expected.to have_many(:notes).dependent(:destroy) } it { is_expected.to have_many(:notes).dependent(:destroy) }
it { is_expected.to have_many(:todos).dependent(:destroy) } it { is_expected.to have_many(:todos).dependent(:destroy) }
context 'Notes' do
let!(:note) { create(:note, noteable: issue, project: issue.project) }
let(:scoped_issue) { Issue.includes(notes: :author).find(issue.id) }
it 'indicates if the notes have their authors loaded' do
expect(issue.notes).not_to be_authors_loaded
expect(scoped_issue.notes).to be_authors_loaded
end
end
end end
describe 'Included modules' do describe 'Included modules' do
...@@ -245,6 +255,22 @@ describe Issue, "Issuable" do ...@@ -245,6 +255,22 @@ describe Issue, "Issuable" do
end end
end end
describe '#user_notes_count' do
let(:project) { create(:project) }
let(:issue1) { create(:issue, project: project) }
let(:issue2) { create(:issue, project: project) }
before do
create_list(:note, 3, noteable: issue1, project: project)
create_list(:note, 6, noteable: issue2, project: project)
end
it 'counts the user notes' do
expect(issue1.user_notes_count).to be(3)
expect(issue2.user_notes_count).to be(6)
end
end
describe "votes" do describe "votes" do
let(:project) { issue.project } let(:project) { issue.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