Commit 4c7da578 authored by Keith Pitt's avatar Keith Pitt

Merge branch 'master' into buildbox-service

Conflicts:
	app/models/project.rb
parents 76594d47 928178de
......@@ -12,7 +12,14 @@ v 7.4.0
- API: Add support for forking a project via the API (Bernhard Kaindl)
- API: filter project issues by milestone (Julien Bianchi)
- Fail harder in the backup script
- Changes to Slack service structure, only webhook url needed
- Zen mode for wiki and milestones (Robert Schilling)
- Move Emoji parsing to html-pipeline-gitlab (Robert Schilling)
- Font Awesome 4.2 integration (Sullivan Senechal)
- Add Pushover service integration (Sullivan Senechal)
- Add select field type for services options (Sullivan Senechal)
- Add cross-project references to the Markdown parser (Vinnie Okada)
- Add task lists to issue and merge request descriptions (Vinnie Okada)
v 7.3.2
- Fix creating new file via web editor
......
......@@ -10,7 +10,7 @@ By submitting code as an individual you agree to the [individual contributor lic
## Security vulnerability disclosure
Please report suspected security vulnerabilities in private to support@gitlab.com, also see the [disclosure section on the GitLab.com website](http://www.gitlab.com/disclosure/). Please do NOT create publicly viewable issues for suspected security vulnerabilities.
Please report suspected security vulnerabilities in private to support@gitlab.com, also see the [disclosure section on the GitLab.com website](http://about.gitlab.com/disclosure/). Please do NOT create publicly viewable issues for suspected security vulnerabilities.
## Closing policy for issues and merge requests
......@@ -22,7 +22,7 @@ Issues and merge requests should be in English and contain appropriate language
## Issue tracker
To get support for your particular problem please use the channels as detailed in the [getting help section of the readme](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/README.md#getting-help). Professional [support subscriptions](http://www.gitlab.com/subscription/) and [consulting services](http://www.gitlab.com/consultancy/) are available from [GitLab.com](http://www.gitlab.com/).
To get support for your particular problem please use the channels as detailed in the [getting help section of the readme](https://gitlab.com/gitlab-org/gitlab-ce/blob/master/README.md#getting-help). Professional [support subscriptions](http://about.gitlab.com/subscription/) and [consulting services](http://about.gitlab.com/consultancy/) are available from [GitLab.com](http://about.gitlab.com/).
The [issue tracker](https://gitlab.com/gitlab-org/gitlab-ce/issues) is only for obvious errors in the latest [stable or development release of GitLab](MAINTENANCE.md). If something is wrong but it is not a regression compared to older versions of GitLab please do not open an issue but a feature request. When submitting an issue please conform to the issue submission guidelines listed below. Not all issues will be addressed and your issue is more likely to be addressed if you submit a merge request which partially or fully addresses the issue.
......
......@@ -31,7 +31,7 @@ gem 'omniauth-shibboleth'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
gem "gitlab_git", '7.0.0.rc8'
gem "gitlab_git", '7.0.0.rc9'
# Ruby/Rack Git Smart-HTTP Server Handler
gem 'gitlab-grack', '~> 2.0.0.pre', require: 'grack'
......@@ -89,7 +89,7 @@ gem "github-markup"
gem 'redcarpet', '~> 3.1.2'
gem 'RedCloth'
gem 'rdoc', '~>3.6'
gem 'org-ruby'
gem 'org-ruby', '= 0.9.9'
gem 'creole', '~>0.3.6'
gem 'wikicloth', '=0.8.1'
gem 'asciidoctor', '= 0.1.4'
......@@ -180,7 +180,7 @@ gem "jquery-ui-rails"
gem "jquery-scrollto-rails"
gem "raphael-rails", "~> 2.1.2"
gem 'bootstrap-sass', '~> 3.0'
gem "font-awesome-rails", '~> 3.2'
gem "font-awesome-rails", '~> 4.2'
gem "gitlab_emoji", "~> 0.0.1.1"
gem "gon", '~> 5.0.0'
gem 'nprogress-rails'
......
......@@ -152,7 +152,7 @@ GEM
net-ssh (>= 2.1.3)
fog-json (1.0.0)
multi_json (~> 1.0)
font-awesome-rails (3.2.1.3)
font-awesome-rails (4.2.0.0)
railties (>= 3.2, < 5.0)
foreman (0.63.0)
dotenv (>= 0.7)
......@@ -179,7 +179,7 @@ GEM
mime-types (~> 1.19)
gitlab_emoji (0.0.1.1)
emoji (~> 1.0.1)
gitlab_git (7.0.0.rc8)
gitlab_git (7.0.0.rc9)
activesupport (~> 4.0)
charlock_holmes (~> 0.6)
gitlab-linguist (~> 3.0)
......@@ -332,7 +332,7 @@ GEM
omniauth-twitter (1.0.1)
multi_json (~> 1.3)
omniauth-oauth (~> 1.0)
org-ruby (0.9.8)
org-ruby (0.9.9)
rubypants (~> 0.2)
orm_adapter (0.5.0)
pg (0.15.1)
......@@ -614,7 +614,7 @@ DEPENDENCIES
factory_girl_rails
ffaker
fog (~> 1.14)
font-awesome-rails (~> 3.2)
font-awesome-rails (~> 4.2)
foreman
gemnasium-gitlab-service (~> 0.2)
github-markup
......@@ -622,7 +622,7 @@ DEPENDENCIES
gitlab-grack (~> 2.0.0.pre)
gitlab-linguist (~> 3.0.0)
gitlab_emoji (~> 0.0.1.1)
gitlab_git (= 7.0.0.rc8)
gitlab_git (= 7.0.0.rc9)
gitlab_meta (= 7.0)
gitlab_omniauth-ldap (= 1.1.0)
gollum-lib (~> 3.0.0)
......@@ -655,7 +655,7 @@ DEPENDENCIES
omniauth-google-oauth2
omniauth-shibboleth
omniauth-twitter
org-ruby
org-ruby (= 0.9.9)
pg
poltergeist (~> 1.5.1)
pry
......
......@@ -18,7 +18,7 @@ Below we describe the contributing process to GitLab for two reasons. So that co
- Responds to merge requests the issue team mentions them in and monitors for new merge requests
- Provides feedback to the merge request submitter to improve the merge request (style, tests, etc.)
- Mark merge requests 'ready-for-merge' when they meet the contribution guidelines
- Mention developer(s) based on the [list of members and their specialities](https://www.gitlab.com/core-team/)
- Mention developer(s) based on the [list of members and their specialities](https://about.gitlab.com/core-team/)
- Closes merge requests with no feedback from the reporter for two weeks
## Priorities of the issue team
......@@ -30,7 +30,7 @@ Below we describe the contributing process to GitLab for two reasons. So that co
## Mentioning people
The most important thing is making sure valid issues receive feedback from the development team. Therefore the priority is mentioning developers that can help on those issue. Please select someone with relevant experience from [GitLab core team](https://www.gitlab.com/core-team/). If there is nobody mentioned with that expertise look in the commit history for the affected files to find someone. Avoid mentioning the lead developer, this is the person that is least likely to give a timely response. If the involvement of the lead developer is needed the other core team members will mention this person.
The most important thing is making sure valid issues receive feedback from the development team. Therefore the priority is mentioning developers that can help on those issue. Please select someone with relevant experience from [GitLab core team](https://about.gitlab.com/core-team/). If there is nobody mentioned with that expertise look in the commit history for the affected files to find someone. Avoid mentioning the lead developer, this is the person that is least likely to give a timely response. If the involvement of the lead developer is needed the other core team members will mention this person.
## Workflow labels
......@@ -79,7 +79,7 @@ Thanks for the issue report but we only support issues for the latest stable ver
### Support requests and configuration questions
Thanks for your interest in GitLab. We don't use the issue tracker for support requests and configuration questions. Please use the \[support forum\]\(https://groups.google.com/forum/#!forum/gitlabhq), \[Stack Overflow\]\(http://stackoverflow.com/questions/tagged/gitlab), the #gitlab IRC channel on Freenode or the http://www.gitlab.com paid services for this purpose. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information.
Thanks for your interest in GitLab. We don't use the issue tracker for support requests and configuration questions. Please use the \[support forum\]\(https://groups.google.com/forum/#!forum/gitlabhq), \[Stack Overflow\]\(http://stackoverflow.com/questions/tagged/gitlab), the #gitlab IRC channel on Freenode or the http://about.gitlab.com paid services for this purpose. Have a look at the \[contribution guidelines\]\(https://gitlab.com/gitlab-org/gitlab-ce/blob/master/CONTRIBUTING.md) for more information.
### Code format
......
......@@ -172,8 +172,8 @@ $ ->
# Show/hide comments on diff
$("body").on "click", ".js-toggle-diff-comments", (e) ->
$(@).find('i').
toggleClass('icon-chevron-down').
toggleClass('icon-chevron-up')
toggleClass('fa fa-chevron-down').
toggleClass('fa fa-chevron-up')
$(@).closest(".diff-file").find(".notes_holder").toggle()
e.preventDefault()
......
......@@ -8,7 +8,7 @@ $ ->
#
$("body").on "click", ".js-toggle-button", (e) ->
$(@).find('i').
toggleClass('icon-chevron-down').
toggleClass('icon-chevron-up')
toggleClass('fa fa-chevron-down').
toggleClass('fa fa-chevron-up')
$(@).closest(".js-toggle-container").find(".js-toggle-content").toggle()
e.preventDefault()
......@@ -6,4 +6,28 @@ class Issue
$(".issue-box .inline-update").on "change", "#issue_assignee_id", ->
$(this).submit()
if $("a.btn-close").length
$("li.task-list-item input:checkbox").prop("disabled", false)
$(".task-list-item input:checkbox").on "click", ->
is_checked = $(this).prop("checked")
if $(this).is(":checked")
state_event = "task_check"
else
state_event = "task_uncheck"
mr_url = $("form.edit-issue").first().attr("action")
mr_num = mr_url.match(/\d+$/)
task_num = 0
$("li.task-list-item input:checkbox").each( (index, e) =>
if e == this
task_num = index + 1
)
$.ajax
type: "PATCH"
url: mr_url
data: "issue[state_event]=" + state_event +
"&issue[task_num]=" + task_num
@Issue = Issue
......@@ -7,8 +7,8 @@ $(document).ready ->
divHover = "<div class=\"div-dropzone-hover\"></div>"
divSpinner = "<div class=\"div-dropzone-spinner\"></div>"
divAlert = "<div class=\"" + alertClass + "\"></div>"
iconPicture = "<i class=\"icon-picture div-dropzone-icon\"></i>"
iconSpinner = "<i class=\"icon-spinner icon-spin div-dropzone-icon\"></i>"
iconPicture = "<i class=\"fa fa-picture-o div-dropzone-icon\"></i>"
iconSpinner = "<i class=\"fa fa-spinner fa-spin div-dropzone-icon\"></i>"
btnAlert = "<button type=\"button\"" + alertAttr + ">&times;</button>"
project_image_path_upload = window.project_image_path_upload or null
......
......@@ -15,8 +15,10 @@ class MergeRequest
modal = $('#modal_merge_info').modal(show: false)
disableButtonIfEmptyField '#merge_commit_message', '.accept_merge_request'
disableButtonIfEmptyField '#commit_message', '.accept_merge_request'
if $("a.close-mr-link").length
$("li.task-list-item input:checkbox").prop("disabled", false)
# Local jQuery finder
$: (selector) ->
......@@ -72,6 +74,27 @@ class MergeRequest
this.$('.remove_source_branch_in_progress').hide()
this.$('.remove_source_branch_widget.failed').show()
this.$(".task-list-item input:checkbox").on "click", ->
is_checked = $(this).prop("checked")
if $(this).is(":checked")
state_event = "task_check"
else
state_event = "task_uncheck"
mr_url = $("form.edit-merge_request").first().attr("action")
mr_num = mr_url.match(/\d+$/)
task_num = 0
$("li.task-list-item input:checkbox").each( (index, e) =>
if e == this
task_num = index + 1
)
$.ajax
type: "PATCH"
url: mr_url
data: "merge_request[state_event]=" + state_event +
"&merge_request[task_num]=" + task_num
activateTab: (action) ->
this.$('.merge-request-tabs li').removeClass 'active'
this.$('.tab-content').hide()
......@@ -96,14 +119,6 @@ class MergeRequest
else
$('.ci_widget.ci-error').show()
switch state
when "success"
$('.mr-state-widget').addClass("panel-success")
when "failed"
$('.mr-state-widget').addClass("panel-danger")
when "running", "pending"
$('.mr-state-widget').addClass("panel-warning")
showCiCoverage: (coverage) ->
cov_html = $('<span>')
cov_html.addClass('ci-coverage')
......
......@@ -356,3 +356,6 @@ table {
font-size: 42px;
}
.task-status {
margin-left: 10px;
}
......@@ -122,3 +122,7 @@ ul.bordered-list {
}
}
}
li.task-list-item {
list-style-type: none;
}
......@@ -124,7 +124,7 @@ $list-group-active-bg: $bg_primary;
color: #888;
text-shadow: 0 1px 1px #fff;
}
i[class^="icon-"] {
i[class~="fa"] {
line-height: 14px;
}
}
......
......@@ -104,7 +104,44 @@
}
.mr-state-widget {
.panel-body {
background: #f9f9f9;
margin-bottom: 20px;
@include box-shadow(0 1px 1px rgba(0, 0, 0, 0.09));
.ci_widget {
padding: 10px 15px;
font-size: 15px;
border-bottom: 1px dashed #AAA;
&.ci-success {
color: $bg_success;
border-color: $border_success;
}
&.ci-pending {
color: #548;
border-color: #548;
}
&.ci-running {
color: $bg_warning;
border-color: $border_warning;
}
&.ci-failed {
color: $bg_danger;
border-color: $border_danger;
}
&.ci-error {
color: $bg_danger;
border-color: $border_danger;
}
}
.mr-widget-body {
padding: 10px 15px;
h4 {
margin-top: 0px;
}
......@@ -114,6 +151,11 @@
}
}
.mr-widget-footer {
padding: 10px 15px;
border-top: 1px solid #EEE;
}
.ci-coverage {
float: right;
}
......
......@@ -8,8 +8,6 @@
ul {
padding: 0;
margin: auto;
height: 40px;
overflow: hidden;
.count {
font-weight: normal;
display: inline-block;
......@@ -37,53 +35,28 @@
a {
color: $link_color;
font-weight: bold;
&:after {
content: '';
display: block;
position: relative;
bottom: -1px;
border-color: $link_color;
border-style: solid;
border-width: 2px;
}
border-bottom: 3px solid $link_color;
}
}
&:hover {
a {
color: $link_hover_color;
&:after {
content: '';
display: block;
position: relative;
bottom: -1px;
border-color: $link_hover_color;
border-style: solid;
border-width: 2px;
}
}
}
&.home {
a {
i {
font-size: 20px;
position: relative;
top: 4px;
}
border-bottom: 3px solid $link_hover_color;
}
}
}
a {
display: block;
text-align: center;
font-weight: 500;
height: 38px;
line-height: 34px;
font-weight: bold;
height: 42px;
line-height: 39px;
color: #777;
text-shadow: 0 1px 1px white;
text-decoration: none;
padding-top: 2px;
overflow: hidden;
margin-bottom: -1px;
}
}
......
......@@ -119,8 +119,7 @@ ul.notes {
display: none;
float: right;
[class^="icon-"],
[class*="icon-"] {
[class~="fa"] {
font-size: 16px;
line-height: 16px;
vertical-align: middle;
......
......@@ -13,7 +13,7 @@ class ApplicationController < ActionController::Base
before_filter :configure_permitted_parameters, if: :devise_controller?
before_filter :require_email, unless: :devise_controller?
protect_from_forgery
protect_from_forgery with: :exception
helper_method :abilities, :can?
......@@ -62,7 +62,7 @@ class ApplicationController < ActionController::Base
end
end
def after_sign_in_path_for resource
def after_sign_in_path_for(resource)
if resource.is_a?(User) && resource.respond_to?(:blocked?) && resource.blocked?
sign_out resource
flash[:alert] = "Your account is blocked. Retry when an admin has unblocked it."
......
class ConfirmationsController < Devise::ConfirmationsController
protected
def after_confirmation_path_for(resource_name, resource)
if signed_in?(resource_name)
signed_in_root_path(resource)
else
sign_in(resource)
if signed_in?(resource_name)
signed_in_root_path(resource)
else
new_session_path(resource_name)
end
end
end
end
......@@ -17,7 +17,7 @@ class Projects::CommitsController < Projects::ApplicationController
group(:commit_id).count
respond_to do |format|
format.html # index.html.erb
format.html
format.json { pager_json("projects/commits/_commits", @commits.size) }
format.atom { render layout: false }
end
......
......@@ -152,7 +152,7 @@ class Projects::IssuesController < Projects::ApplicationController
def issue_params
params.require(:issue).permit(
:title, :assignee_id, :position, :description,
:milestone_id, :state_event, label_ids: []
:milestone_id, :state_event, :task_num, label_ids: []
)
end
end
......@@ -122,7 +122,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
if @merge_request.open? && @merge_request.can_be_merged?
@merge_request.should_remove_source_branch = params[:should_remove_source_branch]
@merge_request.automerge!(current_user, params[:merge_commit_message])
@merge_request.automerge!(current_user, params[:commit_message])
@status = true
else
@status = false
......@@ -250,7 +250,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
params.require(:merge_request).permit(
:title, :assignee_id, :source_project_id, :source_branch,
:target_project_id, :target_branch, :milestone_id,
:state_event, :description, label_ids: []
:state_event, :description, :task_num, label_ids: []
)
end
end
......@@ -40,7 +40,8 @@ class Projects::ServicesController < Projects::ApplicationController
def service_params
params.require(:service).permit(
:title, :token, :type, :active, :api_key, :subdomain,
:room, :recipients, :project_url
:room, :recipients, :project_url, :webhook,
:user_key, :device, :priority, :sound
)
end
end
......@@ -15,11 +15,11 @@ class RegistrationsController < Devise::RegistrationsController
super
end
def after_sign_up_path_for resource
def after_sign_up_path_for(resource)
new_user_session_path
end
def after_inactive_sign_up_path_for resource
def after_inactive_sign_up_path_for(resource)
new_user_session_path
end
......
......@@ -14,7 +14,7 @@ class SnippetsController < ApplicationController
layout 'navless'
def index
@snippets = Snippet.are_public.fresh.non_expired.page(params[:page]).per(20)
@snippets = Snippet.are_internal.fresh.non_expired.page(params[:page]).per(20)
end
def user_index
......@@ -26,15 +26,15 @@ class SnippetsController < ApplicationController
if @user == current_user
@snippets = case params[:scope]
when 'are_public' then
@snippets.are_public
when 'are_internal' then
@snippets.are_internal
when 'are_private' then
@snippets.are_private
else
@snippets
end
else
@snippets = @snippets.are_public
@snippets = @snippets.are_internal
end
@snippets = @snippets.page(params[:page]).per(20)
......
# Finders
This type of classes responsible for collectiong items based on different conditions.
To prevent lookup methods in models like this:
This type of classes responsible for collection items based on different conditions.
To prevent lookup methods in models like this:
```ruby
class Project
......@@ -13,10 +13,10 @@ end
issues = project.issues_for_user_filtered_by(user, params)
```
Better use this:
Better use this:
```ruby
issues = IssuesFinder.new.execute(project, user, filter)
```
It will help keep models thiner
It will help keep models thiner.
......@@ -229,7 +229,7 @@ module ApplicationHelper
css_class << " hide" unless visible
content_tag :div, class: css_class do
content_tag(:i, nil, class: 'icon-spinner icon-spin') + text
content_tag(:i, nil, class: 'fa fa-spinner fa-spin') + text
end
end
......@@ -259,4 +259,16 @@ module ApplicationHelper
super
end
def escaped_autolink(text)
auto_link ERB::Util.html_escape(text), link: :urls
end
def promo_host
'about.gitlab.com'
end
def promo_url
'https://' + promo_host
end
end
......@@ -19,7 +19,7 @@ module EventsHelper
[event.action_name, target].join(" ")
end
def event_filter_link key, tooltip
def event_filter_link(key, tooltip)
key = key.to_s
inactive = if @event_filter.active? key
nil
......@@ -36,10 +36,10 @@ module EventsHelper
def icon_for_event
{
EventFilter.push => "icon-upload-alt",
EventFilter.merged => "icon-check",
EventFilter.comments => "icon-comments",
EventFilter.team => "icon-user",
EventFilter.push => 'fa fa-upload',
EventFilter.merged => 'fa fa-check-square-o',
EventFilter.comments => 'fa fa-comments',
EventFilter.team => 'fa fa-user',
}
end
......
module IconsHelper
def boolean_to_icon(value)
if value.to_s == "true"
content_tag :i, nil, class: 'icon-circle cgreen'
content_tag :i, nil, class: 'fa fa-circle cgreen'
else
content_tag :i, nil, class: 'icon-off clgray'
content_tag :i, nil, class: 'fa fa-power-off clgray'
end
end
def public_icon
content_tag :i, nil, class: 'icon-globe'
content_tag :i, nil, class: 'fa fa-globe'
end
def internal_icon
content_tag :i, nil, class: 'icon-shield'
content_tag :i, nil, class: 'fa fa-shield'
end
def private_icon
content_tag :i, nil, class: 'icon-lock'
content_tag :i, nil, class: 'fa fa-lock'
end
end
module IssuesHelper
def issue_css_classes issue
def issue_css_classes(issue)
classes = "issue"
classes << " closed" if issue.closed?
classes << " today" if issue.today?
......@@ -84,7 +84,7 @@ module IssuesHelper
'id', 'name', object.assignee_id)
end
def milestone_options object
def milestone_options(object)
options_from_collection_for_select(object.project.milestones.active,
'id', 'title', object.milestone_id)
end
......
......@@ -19,19 +19,18 @@ module MergeRequestsHelper
source_project_id: event.project.id,
target_project_id: target_project.id,
source_branch: event.branch_name,
target_branch: target_project.repository.root_ref,
title: event.branch_name.titleize.humanize
target_branch: target_project.repository.root_ref
}
end
def mr_css_classes mr
def mr_css_classes(mr)
classes = "merge-request"
classes << " closed" if mr.closed?
classes << " merged" if mr.merged?
classes
end
def ci_build_details_path merge_request
def ci_build_details_path(merge_request)
merge_request.source_project.ci_service.build_page(merge_request.last_commit.sha)
end
......
......@@ -69,7 +69,7 @@ module NotesHelper
button_tag class: 'btn reply-btn js-discussion-reply-button',
data: data, title: 'Add a reply' do
link_text = content_tag(:i, nil, class: 'icon-comment')
link_text = content_tag(:i, nil, class: 'fa fa-comment')
link_text << ' Reply'
end
end
......
module NotificationsHelper
def notification_icon(notification)
if notification.disabled?
content_tag :i, nil, class: 'icon-volume-off ns-mute'
content_tag :i, nil, class: 'fa fa-volume-off ns-mute'
elsif notification.participating?
content_tag :i, nil, class: 'icon-volume-down ns-part'
content_tag :i, nil, class: 'fa fa-volume-down ns-part'
elsif notification.watch?
content_tag :i, nil, class: 'icon-volume-up ns-watch'
content_tag :i, nil, class: 'fa fa-volume-up ns-watch'
else
content_tag :i, nil, class: 'icon-circle-blank ns-default'
content_tag :i, nil, class: 'fa fa-circle-o ns-default'
end
end
end
module ProfileHelper
def oauth_active_class provider
def oauth_active_class(provider)
if current_user.provider == provider.to_s
'active'
end
......
......@@ -3,7 +3,7 @@ module ProjectsHelper
"You are going to remove #{user.name} from #{project.name} project team. Are you sure?"
end
def link_to_project project
def link_to_project(project)
link_to project do
title = content_tag(:span, project.name, class: 'project-name')
......@@ -39,7 +39,7 @@ module ProjectsHelper
end
end
def project_title project
def project_title(project)
if project.group
content_tag :span do
link_to(simple_sanitize(project.group.name), group_path(project.group)) + " / " + project.name
......@@ -128,12 +128,12 @@ module ProjectsHelper
toggle_html = content_tag('span', class: 'toggle') do
toggle_text = if starred
'Unstar'
' Unstar'
else
'Star'
' Star'
end
content_tag('i', ' ', class: 'icon-star') + toggle_text
content_tag('i', ' ', class: 'fa fa-star') + toggle_text
end
count_html = content_tag('span', class: 'count') do
......@@ -157,7 +157,7 @@ module ProjectsHelper
end
def link_to_toggle_fork
out = content_tag(:i, '', class: 'icon-code-fork')
out = content_tag(:i, '', class: 'fa fa-code-fork')
out << ' Fork'
out << content_tag(:span, class: 'count') do
@project.forks_count.to_s
......
......@@ -89,7 +89,7 @@ module TabHelper
end
# Use nav_tab for save controller/action but different params
def nav_tab key, value, &block
def nav_tab(key, value, &block)
o = {}
o[:class] = ""
......
module TagsHelper
def tag_path tag
def tag_path(tag)
"/tags/#{tag}"
end
def tag_list project
def tag_list(project)
html = ''
project.tag_list.each do |tag|
html += link_to tag, tag_path(tag)
......
......@@ -36,9 +36,9 @@ module TreeHelper
# type - String type of the tree item; either 'folder' or 'file'
def tree_icon(type)
icon_class = if type == 'folder'
'icon-folder-close'
'fa fa-folder'
else
'icon-file-alt'
'fa fa-file-o'
end
content_tag :i, nil, class: icon_class
......@@ -80,7 +80,7 @@ module TreeHelper
end
end
def up_dir_path tree
def up_dir_path(tree)
file = File.join(@path, "..")
tree_join(@ref, file)
end
......@@ -90,7 +90,7 @@ module TreeHelper
end
def editing_preview_title(filename)
if gitlab_markdown?(filename) || markup?(filename)
if Gitlab::MarkdownHelper.previewable?(filename)
'Preview'
else
'Diff'
......
......@@ -184,7 +184,7 @@ class Ability
]
end
def group_abilities user, group
def group_abilities(user, group)
rules = []
if user.admin? || group.users.include?(user) || ProjectsFinder.new.execute(user, group: group).any?
......@@ -209,7 +209,7 @@ class Ability
rules.flatten
end
def namespace_abilities user, namespace
def namespace_abilities(user, namespace)
rules = []
# Only namespace owner and administrators can manage it
......
......@@ -88,9 +88,24 @@ class Commit
description.present?
end
def hook_attrs(project)
path_with_namespace = project.path_with_namespace
{
id: id,
message: safe_message,
timestamp: committed_date.xmlschema,
url: "#{Gitlab.config.gitlab.url}/#{path_with_namespace}/commit/#{id}",
author: {
name: author_name,
email: author_email
}
}
end
# Discover issues should be closed when this commit is pushed to a project's
# default branch.
def closes_issues project
def closes_issues(project)
Gitlab::ClosingIssueExtractor.closed_by_message_in_project(safe_message, project)
end
......
......@@ -134,7 +134,7 @@ module Issuable
def to_hook_data
{
object_kind: self.class.name.underscore,
object_attributes: self.attributes
object_attributes: hook_attrs
}
end
......
......@@ -10,7 +10,7 @@ module Mentionable
module ClassMethods
# Indicate which attributes of the Mentionable to search for GFM references.
def attr_mentionable *attrs
def attr_mentionable(*attrs)
mentionable_attrs.concat(attrs.map(&:to_s))
end
......@@ -38,7 +38,7 @@ module Mentionable
# Determine whether or not a cross-reference Note has already been created between this Mentionable and
# the specified target.
def has_mentioned? target
def has_mentioned?(target)
Note.cross_reference_exists?(target, local_reference)
end
......@@ -64,15 +64,17 @@ module Mentionable
end
# Extract GFM references to other Mentionables from this Mentionable. Always excludes its #local_reference.
def references p = project, text = mentionable_text
def references(p = project, text = mentionable_text)
return [] if text.blank?
ext = Gitlab::ReferenceExtractor.new
ext.analyze(text)
(ext.issues_for(p) + ext.merge_requests_for(p) + ext.commits_for(p)).uniq - [local_reference]
ext.analyze(text, p)
(ext.issues_for +
ext.merge_requests_for +
ext.commits_for).uniq - [local_reference]
end
# Create a cross-reference Note for each GFM reference to another Mentionable found in +mentionable_text+.
def create_cross_references! p = project, a = author, without = []
def create_cross_references!(p = project, a = author, without = [])
refs = references(p) - without
refs.each do |ref|
Note.create_cross_reference_note(ref, local_reference, a, p)
......@@ -81,7 +83,7 @@ module Mentionable
# If the mentionable_text field is about to change, locate any *added* references and create cross references for
# them. Invoke from an observer's #before_save implementation.
def notice_added_references p = project, a = author
def notice_added_references(p = project, a = author)
ch = changed_attributes
original, mentionable_changed = "", false
self.class.mentionable_attrs.each do |attr|
......
# Contains functionality for objects that can have task lists in their
# descriptions. Task list items can be added with Markdown like "* [x] Fix
# bugs".
#
# Used by MergeRequest and Issue
module Taskable
TASK_PATTERN_MD = /^(?<bullet> *[*-] *)\[(?<checked>[ xX])\]/.freeze
TASK_PATTERN_HTML = /^<li>\[(?<checked>[ xX])\]/.freeze
# Change the state of a task list item for this Taskable. Edit the object's
# description by finding the nth task item and changing its checkbox
# placeholder to "[x]" if +checked+ is true, or "[ ]" if it's false.
# Note: task numbering starts with 1
def update_nth_task(n, checked)
index = 0
check_char = checked ? 'x' : ' '
# Do this instead of using #gsub! so that ActiveRecord detects that a field
# has changed.
self.description = self.description.gsub(TASK_PATTERN_MD) do |match|
index += 1
case index
when n then "#{$LAST_MATCH_INFO[:bullet]}[#{check_char}]"
else match
end
end
save
end
# Return true if this object's description has any task list items.
def tasks?
description && description.match(TASK_PATTERN_MD)
end
# Return a string that describes the current state of this Taskable's task
# list items, e.g. "20 tasks (12 done, 8 unfinished)"
def task_status
return nil unless description
num_tasks = 0
num_done = 0
description.scan(TASK_PATTERN_MD) do
num_tasks += 1
num_done += 1 unless $LAST_MATCH_INFO[:checked] == ' '
end
"#{num_tasks} tasks (#{num_done} done, #{num_tasks - num_done} unfinished)"
end
end
......@@ -21,6 +21,7 @@ class WebHook < ActiveRecord::Base
default_value_for :push_events, true
default_value_for :issues_events, false
default_value_for :merge_requests_events, false
default_value_for :tag_push_events, false
# HTTParty timeout
default_timeout Gitlab.config.gitlab.webhook_timeout
......
......@@ -23,6 +23,7 @@ require 'file_size_validator'
class Issue < ActiveRecord::Base
include Issuable
include InternalId
include Taskable
ActsAsTaggableOn.strict_case_match = true
......@@ -48,6 +49,10 @@ class Issue < ActiveRecord::Base
state :closed
end
def hook_attrs
attributes
end
# Mentionable overrides.
def gfm_reference
......
......@@ -77,7 +77,7 @@ class ProjectMember < Member
false
end
def truncate_team project
def truncate_team(project)
truncate_teams [project.id]
end
......
......@@ -25,6 +25,7 @@ require Rails.root.join("lib/static_model")
class MergeRequest < ActiveRecord::Base
include Issuable
include Taskable
include InternalId
belongs_to :target_project, foreign_key: :target_project_id, class_name: "Project"
......@@ -211,6 +212,20 @@ class MergeRequest < ActiveRecord::Base
Gitlab::Satellite::MergeAction.new(current_user, self).format_patch
end
def hook_attrs
attrs = {
source: source_project.hook_attrs,
target: target_project.hook_attrs,
last_commit: nil
}
unless last_commit.nil?
attrs.merge!(last_commit: last_commit.hook_attrs(source_project))
end
attributes.merge!(attrs)
end
def for_fork?
target_project != source_project
end
......
......@@ -38,7 +38,7 @@ class Namespace < ActiveRecord::Base
scope :root, -> { where('type IS NULL') }
def self.search query
def self.search(query)
where("name LIKE :query OR path LIKE :query", query: "%#{query}%")
end
......
......@@ -6,7 +6,7 @@ module Network
@max_count ||= 650
end
def initialize project, ref, commit, filter_ref
def initialize(project, ref, commit, filter_ref)
@project = project
@ref = ref
@commit = commit
......
......@@ -47,7 +47,7 @@ class Note < ActiveRecord::Base
scope :for_commit_id, ->(commit_id) { where(noteable_type: "Commit", commit_id: commit_id) }
scope :inline, ->{ where("line_code IS NOT NULL") }
scope :not_inline, ->{ where(line_code: [nil, '']) }
scope :system, ->{ where(system: true) }
scope :common, ->{ where(noteable_type: ["", nil]) }
scope :fresh, ->{ order("created_at ASC, id ASC") }
scope :inc_author_project, ->{ includes(:project, :author) }
......@@ -70,13 +70,17 @@ class Note < ActiveRecord::Base
)
end
# +noteable+ was referenced from +mentioner+, by including GFM in either +mentioner+'s description or an associated Note.
# Create a system Note associated with +noteable+ with a GFM back-reference to +mentioner+.
# +noteable+ was referenced from +mentioner+, by including GFM in either
# +mentioner+'s description or an associated Note.
# Create a system Note associated with +noteable+ with a GFM back-reference
# to +mentioner+.
def create_cross_reference_note(noteable, mentioner, author, project)
gfm_reference = mentioner_gfm_ref(noteable, mentioner, project)
note_options = {
project: project,
author: author,
note: "_mentioned in #{mentioner.gfm_reference}_",
note: "_mentioned in #{gfm_reference}_",
system: true
}
......@@ -163,12 +167,78 @@ class Note < ActiveRecord::Base
# Determine whether or not a cross-reference note already exists.
def cross_reference_exists?(noteable, mentioner)
where(noteable_id: noteable.id, system: true, note: "_mentioned in #{mentioner.gfm_reference}_").any?
gfm_reference = mentioner_gfm_ref(noteable, mentioner)
notes = if noteable.is_a?(Commit)
where(commit_id: noteable.id)
else
where(noteable_id: noteable.id)
end
notes.where('note like ?', "_mentioned in #{gfm_reference}_").
system.any?
end
def search(query)
where("note like :query", query: "%#{query}%")
end
private
# Prepend the mentioner's namespaced project path to the GFM reference for
# cross-project references. For same-project references, return the
# unmodified GFM reference.
def mentioner_gfm_ref(noteable, mentioner, project = nil)
if mentioner.is_a?(Commit)
if project.nil?
return mentioner.gfm_reference.sub('commit ', 'commit %')
else
mentioning_project = project
end
else
mentioning_project = mentioner.project
end
noteable_project_id = noteable_project_id(noteable, mentioning_project)
full_gfm_reference(mentioning_project, noteable_project_id, mentioner)
end
# Return the ID of the project that +noteable+ belongs to, or nil if
# +noteable+ is a commit and is not part of the project that owns
# +mentioner+.
def noteable_project_id(noteable, mentioning_project)
if noteable.is_a?(Commit)
if mentioning_project.repository.commit(noteable.id)
# The noteable commit belongs to the mentioner's project
mentioning_project.id
else
nil
end
else
noteable.project.id
end
end
# Return the +mentioner+ GFM reference. If the mentioner and noteable
# projects are not the same, add the mentioning project's path to the
# returned value.
def full_gfm_reference(mentioning_project, noteable_project_id, mentioner)
if mentioning_project.id == noteable_project_id
mentioner.gfm_reference
else
if mentioner.is_a?(Commit)
mentioner.gfm_reference.sub(
/(commit )/,
"\\1#{mentioning_project.path_with_namespace}@"
)
else
mentioner.gfm_reference.sub(
/(issue |merge request )/,
"\\1#{mentioning_project.path_with_namespace}"
)
end
end
end
end
def commit_author
......
......@@ -65,6 +65,7 @@ class Project < ActiveRecord::Base
has_one :gemnasium_service, dependent: :destroy
has_one :slack_service, dependent: :destroy
has_one :buildbox_service, dependent: :destroy
has_one :pushover_service, dependent: :destroy
has_one :forked_project_link, dependent: :destroy, foreign_key: "forked_to_project_id"
has_one :forked_from_project, through: :forked_project_link
# Merge Requests for target project should be removed with it
......@@ -312,8 +313,7 @@ class Project < ActiveRecord::Base
end
def available_services_names
%w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla
emails_on_push gemnasium slack buildbox)
%w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla emails_on_push gemnasium slack pushover buildbox)
end
def gitlab_ci?
......@@ -333,7 +333,7 @@ class Project < ActiveRecord::Base
path
end
def items_for entity
def items_for(entity)
case entity
when 'issue' then
issues
......@@ -506,7 +506,7 @@ class Project < ActiveRecord::Base
end
# Check if current branch name is marked as protected in the system
def protected_branch? branch_name
def protected_branch?(branch_name)
protected_branches_names.include?(branch_name)
end
......@@ -546,6 +546,16 @@ class Project < ActiveRecord::Base
end
end
def hook_attrs
{
name: name,
ssh_url: ssh_url_to_repo,
http_url: http_url_to_repo,
namespace: namespace.name,
visibility_level: visibility_level
}
end
# Reset events cache related to this project
#
# Since we do cache @event we need to reset cache in special cases:
......
......@@ -27,7 +27,7 @@ class GitlabCiService < CiService
hook.save
end
def commit_status_path sha
def commit_status_path(sha)
project_url + "/builds/#{sha}/status.json?token=#{token}"
end
......@@ -54,7 +54,7 @@ class GitlabCiService < CiService
end
end
def build_page sha
def build_page(sha)
project_url + "/builds/#{sha}"
end
......
# == Schema Information
#
# Table name: services
#
# id :integer not null, primary key
# type :string(255)
# title :string(255)
# project_id :integer not null
# created_at :datetime
# updated_at :datetime
# active :boolean default(FALSE), not null
# properties :text
#
class PushoverService < Service
include HTTParty
base_uri 'https://api.pushover.net/1'
prop_accessor :api_key, :user_key, :device, :priority, :sound
validates :api_key, :user_key, :priority, presence: true, if: :activated?
def title
'Pushover'
end
def description
'Pushover makes it easy to get real-time notifications on your Android device, iPhone, iPad, and Desktop.'
end
def to_param
'pushover'
end
def fields
[
{ type: 'text', name: 'api_key', placeholder: 'Your application key' },
{ type: 'text', name: 'user_key', placeholder: 'Your user key' },
{ type: 'text', name: 'device', placeholder: 'Leave blank for all active devices' },
{ type: 'select', name: 'priority', choices:
[
['Lowest Priority', -2],
['Low Priority', -1],
['Normal Priority', 0],
['High Priority', 1]
],
default_choice: 0
},
{ type: 'select', name: 'sound', choices:
[
['Device default sound', nil],
['Pushover (default)', 'pushover'],
['Bike', 'bike'],
['Bugle', 'bugle'],
['Cash Register', 'cashregister'],
['Classical', 'classical'],
['Cosmic', 'cosmic'],
['Falling', 'falling'],
['Gamelan', 'gamelan'],
['Incoming', 'incoming'],
['Intermission', 'intermission'],
['Magic', 'magic'],
['Mechanical', 'mechanical'],
['Piano Bar', 'pianobar'],
['Siren', 'siren'],
['Space Alarm', 'spacealarm'],
['Tug Boat', 'tugboat'],
['Alien Alarm (long)', 'alien'],
['Climb (long)', 'climb'],
['Persistent (long)', 'persistent'],
['Pushover Echo (long)', 'echo'],
['Up Down (long)', 'updown'],
['None (silent)', 'none']
]
},
]
end
def execute(push_data)
ref = push_data[:ref].gsub('refs/heads/', '')
before = push_data[:before]
after = push_data[:after]
if before =~ /000000/
message = "#{push_data[:user_name]} pushed new branch \"#{ref}\"."
elsif after =~ /000000/
message = "#{push_data[:user_name]} deleted branch \"#{ref}\"."
else
message = "#{push_data[:user_name]} push to branch \"#{ref}\"."
end
if push_data[:total_commits_count] > 0
message << "\nTotal commits count: #{push_data[:total_commits_count]}"
end
pushover_data = {
token: api_key,
user: user_key,
device: device,
priority: priority,
title: "#{project.name_with_namespace}",
message: message,
url: push_data[:repository][:homepage],
url_title: "See project #{project.name_with_namespace}"
}
# Sound parameter MUST NOT be sent to API if not selected
if sound
pushover_data.merge!(sound: sound)
end
PushoverService.post('/messages.json', body: pushover_data)
end
end
......@@ -13,10 +13,8 @@
#
class SlackService < Service
prop_accessor :room, :subdomain, :token
validates :room, presence: true, if: :activated?
validates :subdomain, presence: true, if: :activated?
validates :token, presence: true, if: :activated?
prop_accessor :webhook
validates :webhook, presence: true, if: :activated?
def title
'Slack'
......@@ -32,9 +30,7 @@ class SlackService < Service
def fields
[
{ type: 'text', name: 'subdomain', placeholder: '' },
{ type: 'text', name: 'token', placeholder: '' },
{ type: 'text', name: 'room', placeholder: 'Ex. #general' },
{ type: 'text', name: 'webhook', placeholder: '' }
]
end
......@@ -44,10 +40,13 @@ class SlackService < Service
project_name: project_name
))
notifier = Slack::Notifier.new(subdomain, token)
notifier.channel = room
notifier.username = 'GitLab'
notifier.ping(message.pretext, attachments: message.attachments)
credentials = webhook.match(/(\w*).slack.com.*services\/(.*)/)
if credentials.present?
subdomain = credentials[1]
token = credentials[2].split("token=").last
notifier = Slack::Notifier.new(subdomain, token)
notifier.ping(message.pretext, attachments: message.attachments)
end
end
private
......
......@@ -11,7 +11,7 @@ class ProjectTeam
# @team << [@user, :master]
# @team << [@users, :master]
#
def << args
def <<(args)
users = args.first
if users.respond_to?(:each)
......
......@@ -32,7 +32,7 @@ class Snippet < ActiveRecord::Base
validates :content, presence: true
# Scopes
scope :are_public, -> { where(private: false) }
scope :are_internal, -> { where(private: false) }
scope :are_private, -> { where(private: true) }
scope :fresh, -> { order("created_at DESC") }
scope :expired, -> { where(["expires_at IS NOT NULL AND expires_at < ?", Time.current]) }
......
......@@ -15,7 +15,7 @@ class Tree
# by markup renderer.
if available_readmes.length > 1
supported_readmes = available_readmes.select do |readme|
gitlab_markdown?(readme.name) || markup?(readme.name)
previewable?(readme.name)
end
# Take the first supported readme, or the first available readme, if we
......
......@@ -203,7 +203,7 @@ class User < ActiveRecord::Base
User.where(name: name).first
end
def filter filter_name
def filter(filter_name)
case filter_name
when "admins"; self.admins
when "blocked"; self.blocked
......@@ -213,7 +213,7 @@ class User < ActiveRecord::Base
end
end
def search query
def search(query)
where("lower(name) LIKE :query OR lower(email) LIKE :query OR lower(username) LIKE :query", query: "%#{query.downcase}%")
end
......@@ -332,7 +332,7 @@ class User < ActiveRecord::Base
several_namespaces? || admin
end
def can? action, subject
def can?(action, subject)
abilities.allowed?(self, action, subject)
end
......@@ -353,7 +353,7 @@ class User < ActiveRecord::Base
(personal_projects.count.to_f / projects_limit) * 100
end
def recent_push project_id = nil
def recent_push(project_id = nil)
# Get push events not earlier than 2 hours ago
events = recent_events.code_push.where("created_at > ?", Time.now - 2.hours)
events = events.where(project_id: project_id) if project_id
......@@ -382,11 +382,11 @@ class User < ActiveRecord::Base
project.team_member_by_id(self.id)
end
def already_forked? project
def already_forked?(project)
!!fork_of(project)
end
def fork_of project
def fork_of(project)
links = ForkedProjectLink.where(forked_from_project_id: project, forked_to_project_id: personal_projects)
if links.any?
......@@ -512,7 +512,7 @@ class User < ActiveRecord::Base
NotificationService.new
end
def log_info message
def log_info(message)
Gitlab::AppLogger.info message
end
......
......@@ -25,7 +25,7 @@ class BaseService
EventCreateService.new
end
def log_info message
def log_info(message)
Gitlab::AppLogger.info message
end
......
......@@ -75,7 +75,7 @@ class GitPushService
# Extract any GFM references from the pushed commit messages. If the configured issue-closing regex is matched,
# close the referenced Issue. Create cross-reference Notes corresponding to any other referenced Mentionables.
def process_commit_messages ref
def process_commit_messages(ref)
is_default_branch = is_default_branch?(ref)
@push_commits.each do |commit|
......@@ -150,49 +150,40 @@ class GitPushService
# will be passed as post receive hook data.
#
push_commits_limited.each do |commit|
data[:commits] << {
id: commit.id,
message: commit.safe_message,
timestamp: commit.committed_date.xmlschema,
url: "#{Gitlab.config.gitlab.url}/#{project.path_with_namespace}/commit/#{commit.id}",
author: {
name: commit.author_name,
email: commit.author_email
}
}
data[:commits] << commit.hook_attrs(project)
end
data
end
def push_to_existing_branch? ref, oldrev
def push_to_existing_branch?(ref, oldrev)
ref_parts = ref.split('/')
# Return if this is not a push to a branch (e.g. new commits)
ref_parts[1] =~ /heads/ && oldrev != "0000000000000000000000000000000000000000"
end
def push_to_new_branch? ref, oldrev
def push_to_new_branch?(ref, oldrev)
ref_parts = ref.split('/')
ref_parts[1] =~ /heads/ && oldrev == "0000000000000000000000000000000000000000"
end
def push_remove_branch? ref, newrev
def push_remove_branch?(ref, newrev)
ref_parts = ref.split('/')
ref_parts[1] =~ /heads/ && newrev == "0000000000000000000000000000000000000000"
end
def push_to_branch? ref
def push_to_branch?(ref)
ref =~ /refs\/heads/
end
def is_default_branch? ref
def is_default_branch?(ref)
ref == "refs/heads/#{project.default_branch}"
end
def commit_user commit
def commit_user(commit)
User.find_for_commit(commit.author_email, commit.author_name) || user
end
end
......@@ -8,9 +8,14 @@ module Issues
Issues::ReopenService.new(project, current_user, {}).execute(issue)
when 'close'
Issues::CloseService.new(project, current_user, {}).execute(issue)
when 'task_check'
issue.update_nth_task(params[:task_num].to_i, true)
when 'task_uncheck'
issue.update_nth_task(params[:task_num].to_i, false)
end
if params.present? && issue.update_attributes(params.except(:state_event))
if params.present? && issue.update_attributes(params.except(:state_event,
:task_num))
issue.reset_events_cache
if issue.previous_changes.include?('milestone_id')
......@@ -28,5 +33,12 @@ module Issues
issue
end
private
def update_task(issue, params, checked)
issue.update_nth_task(params[:task_num].to_i, checked)
params.except!(:task_num)
end
end
end
......@@ -17,9 +17,15 @@ module MergeRequests
MergeRequests::ReopenService.new(project, current_user, {}).execute(merge_request)
when 'close'
MergeRequests::CloseService.new(project, current_user, {}).execute(merge_request)
when 'task_check'
merge_request.update_nth_task(params[:task_num].to_i, true)
when 'task_uncheck'
merge_request.update_nth_task(params[:task_num].to_i, false)
end
if params.present? && merge_request.update_attributes(params.except(:state_event))
if params.present? && merge_request.update_attributes(
params.except(:state_event, :task_num)
)
merge_request.reset_events_cache
if merge_request.previous_changes.include?('milestone_id')
......
......@@ -8,7 +8,7 @@
.panel-body
- if @sidekiq_processes.empty?
%h4.cred
%i.icon-warning-sign
%i.fa.fa-exclamation-triangle
There are no running sidekiq processes. Please restart GitLab
- else
%table.table
......@@ -32,10 +32,10 @@
.clearfix
%p
%i.icon-exclamation-sign
%i.fa.fa-exclamation-circle
If '[25 of 25 busy]' is shown, restart GitLab with 'sudo service gitlab reload'.
%p
%i.icon-exclamation-sign
%i.fa.fa-exclamation-circle
If more than one sidekiq process is listed, stop GitLab, kill the remaining sidekiq processes (sudo pkill -u #{Settings.gitlab.user} -f sidekiq) and restart GitLab.
......
......@@ -3,7 +3,7 @@
%p.light
Broadcast messages are displayed for every user and can be used to notify users about scheduled maintenance, recent upgrades and more.
.broadcast-message-preview
%i.icon-bullhorn
%i.fa.fa-bullhorn
%span Your message here
= form_for [:admin, @broadcast_message], html: { class: 'broadcast-message-form form-horizontal'} do |f|
......@@ -53,7 +53,7 @@
#{broadcast_message.ends_at.to_s(:short)}
&nbsp;
= link_to [:admin, broadcast_message], method: :delete, remote: true, class: 'remove-row btn btn-tiny' do
%i.icon-remove.cred
%i.fa.fa-times.cred
.message= broadcast_message.message
......
......@@ -17,7 +17,7 @@
= f.label :avatar, "Group avatar", class: 'control-label'
.col-sm-10
%a.choose-btn.btn.btn-small.js-choose-group-avatar-button
%i.icon-paper-clip
%i.fa.fa-paperclip
%span Choose File ...
&nbsp;
%span.file_name.js-avatar-filename File name...
......
......@@ -24,7 +24,7 @@
%h4
= link_to [:admin, group] do
%i.icon-folder-close
%i.fa.fa-folder
= group.name
&rarr;
......
......@@ -2,7 +2,7 @@
Group: #{@group.name}
= link_to edit_admin_group_path(@group), class: "btn pull-right" do
%i.icon-edit
%i.fa.fa-pencil-square-o
Edit
%hr
.row
......@@ -81,6 +81,6 @@
%span.pull-right.light
= member.human_access
= link_to group_group_members_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
%i.icon-minus.icon-white
%i.fa.fa-minus.fa-inverse
.panel-footer
= paginate @members, param_name: 'members_page', theme: 'gitlab'
......@@ -13,11 +13,11 @@
.tab-pane.active#githost
.file-holder#README
.file-title
%i.icon-file
%i.fa.fa-file
githost.log
.pull-right
= link_to '#', class: 'log-bottom' do
%i.icon-arrow-down
%i.fa.fa-arrow-down
Scroll down
.file-content.logs
%ol
......@@ -27,11 +27,11 @@
.tab-pane#application
.file-holder#README
.file-title
%i.icon-file
%i.fa.fa-file
application.log
.pull-right
= link_to '#', class: 'log-bottom' do
%i.icon-arrow-down
%i.fa.fa-arrow-down
Scroll down
.file-content.logs
%ol
......@@ -41,11 +41,11 @@
.tab-pane#production
.file-holder#README
.file-title
%i.icon-file
%i.fa.fa-file
production.log
.pull-right
= link_to '#', class: 'log-bottom' do
%i.icon-arrow-down
%i.fa.fa-arrow-down
Scroll down
.file-content.logs
%ol
......@@ -55,11 +55,11 @@
.tab-pane#sidekiq
.file-holder#README
.file-title
%i.icon-file
%i.fa.fa-file
sidekiq.log
.pull-right
= link_to '#', class: 'log-bottom' do
%i.icon-arrow-down
%i.fa.fa-arrow-down
Scroll down
.file-content.logs
%ol
......
%h3.page-title
Project: #{@project.name_with_namespace}
= link_to edit_project_path(@project), class: "btn pull-right" do
%i.icon-edit
%i.fa.fa-pencil-square-o
Edit
%hr
.row
......@@ -98,7 +98,7 @@
group members (#{@group.group_members.count})
.pull-right
= link_to admin_group_path(@group), class: 'btn btn-small' do
%i.icon-edit
%i.fa.fa-pencil-square-o
%ul.well-list
- @group_members.each do |member|
= render 'groups/group_members/group_member', member: member, show_controls: false
......@@ -112,7 +112,7 @@
(#{@project.users.count})
.pull-right
= link_to project_team_index_path(@project), class: "btn btn-tiny" do
%i.icon-edit
%i.fa.fa-pencil-square-o
Manage Access
%ul.well-list.team_members
- @project_members.each do |project_member|
......@@ -127,6 +127,6 @@
- else
%span.light= project_member.human_access
= link_to project_team_member_path(@project, user), data: { confirm: remove_from_project_team_message(@project, user)}, method: :delete, remote: true, class: "btn btn-small btn-remove" do
%i.icon-remove
%i.fa.fa-times
.panel-footer
= paginate @project_members, param_name: 'project_members_page', theme: 'gitlab'
......@@ -23,7 +23,7 @@
.form-group
= search_field_tag :name, params[:name], placeholder: 'Name, email or username', class: 'form-control'
= button_tag class: 'btn btn-primary' do
%i.icon-search
%i.fa.fa-search
%hr
= link_to 'Reset', admin_users_path, class: "btn btn-cancel"
......@@ -38,9 +38,9 @@
%li
.list-item-name
- if user.blocked?
%i.icon-lock.cred
%i.fa.fa-lock.cred
- else
%i.icon-user.cgreen
%i.fa.fa-user.cgreen
= link_to user.name, [:admin, user]
- if user.admin?
%strong.cred (Admin)
......@@ -48,7 +48,7 @@
%span.cred It's you!
.pull-right
%span.light
%i.icon-envelope
%i.fa.fa-envelope
= mail_to user.email, user.email, class: 'light'
&nbsp;
= link_to 'Edit', edit_admin_user_path(user), id: "edit_#{dom_id(user)}", class: "btn btn-small"
......
......@@ -8,7 +8,7 @@
.pull-right
= link_to edit_admin_user_path(@user), class: "btn btn-grouped" do
%i.icon-edit
%i.fa.fa-pencil-square-o
Edit
%hr
%ul.nav.nav-tabs
......@@ -45,7 +45,7 @@
%span.light Secondary email:
%strong= email.email
= link_to remove_email_admin_user_path(@user, email), data: { confirm: "Are you sure you want to remove #{email.email}?" }, method: :delete, class: "btn-tiny btn btn-remove pull-right", title: 'Remove secondary email', id: "remove_email_#{email.id}" do
%i.icon-remove
%i.fa.fa-times
%li
%span.light Can create groups:
......@@ -86,6 +86,11 @@
- else
never
%li
%span.light Sign-in count:
%strong
= @user.sign_in_count
- if @user.ldap_user?
%li
%span.light LDAP uid:
......@@ -172,7 +177,7 @@
%span.light= user_group.human_access
- unless user_group.owner?
= link_to group_group_member_path(group, user_group), data: { confirm: remove_user_from_group_message(group, @user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
%i.icon-remove.icon-white
%i.fa.fa-times.fa-inverse
- else
.nothing-here-block This user has no groups.
......@@ -211,4 +216,4 @@
- if tm.respond_to? :project
= link_to project_team_member_path(project, @user), data: { confirm: remove_from_project_team_message(project, @user) }, remote: true, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from project' do
%i.icon-remove
%i.fa.fa-times
......@@ -3,7 +3,7 @@
= search_field_tag :filter_group, nil, placeholder: 'Filter by name', class: 'dash-filter form-control'
- if current_user.can_create_group?
= link_to new_group_path, class: "btn btn-new pull-right" do
%i.icon-plus
%i.fa.fa-plus
New group
%ul.well-list.dash-list
- groups.each do |group|
......@@ -13,7 +13,7 @@
%span.group-name.filter-title
= truncate(group.name, length: 35)
%span.arrow
%i.icon-angle-right
%i.fa.fa-angle-right
- if groups.blank?
%li
.nothing-here-block You have no groups yet.
......@@ -9,4 +9,4 @@
%span.project-name.filter-title
= project.name
%span.arrow
%i.icon-angle-right
%i.fa.fa-angle-right
......@@ -3,7 +3,7 @@
= search_field_tag :filter_projects, nil, placeholder: 'Filter by name', class: 'dash-filter form-control'
- if current_user.can_create_project?
= link_to new_project_path, class: "btn btn-new pull-right" do
%i.icon-plus
%i.fa.fa-plus
New project
%ul.well-list.dash-list
......@@ -21,4 +21,4 @@
.pull-right
= link_to projects_dashboard_path do
Show all
%i.icon-angle-right
%i.fa.fa-angle-right
......@@ -37,7 +37,7 @@
- @groups.each do |group|
%li{ class: (group.name == params[:group]) ? 'active' : 'light' }
= link_to projects_dashboard_filter_path(group: group.name) do
%i.icon-folder-close-alt
%i.fa.fa-folder-o
= group.name
%small.pull-right
= group.projects.count
......@@ -51,5 +51,5 @@
- @tags.each do |tag|
%li{ class: (tag.name == params[:tag]) ? 'active' : 'light' }
= link_to projects_dashboard_filter_path(scope: params[:scope], tag: tag.name) do
%i.icon-tag
%i.fa.fa-tag
= tag.name
......@@ -18,7 +18,7 @@
%span.rss-icon
= link_to dashboard_path(:atom, { private_token: current_user.private_token }) do
%strong
%i.icon-rss
%i.fa.fa-rss
News Feed
%hr
......
......@@ -3,7 +3,7 @@
%hr
%div
.dashboard-intro-icon
%i.icon-bookmark-empty
%i.fa.fa-bookmark-o
%div
%p.slead
You don't have access to any projects right now.
......@@ -23,7 +23,7 @@
%hr
%div
.dashboard-intro-icon
%i.icon-group
%i.fa.fa-users
%div
%p.slead
You can create a group for several dependent projects.
......@@ -37,7 +37,7 @@
%hr
%div
.dashboard-intro-icon
%i.icon-globe
%i.fa.fa-globe
%div
%p.slead
There are
......
......@@ -7,7 +7,7 @@
.row
.fixed.sidebar-expand-button.hidden-lg.hidden-md
%i.icon-list.icon-2x
%i.fa.fa-list.fa-2x
.col-md-3.responsive-side
= render 'shared/filter', entity: 'issue'
.col-md-9
......
......@@ -7,7 +7,7 @@
%hr
.row
.fixed.sidebar-expand-button.hidden-lg.hidden-md
%i.icon-list.icon-2x
%i.fa.fa-list.fa-2x
.col-md-3.responsive-side
= render 'shared/filter', entity: 'merge_request'
.col-md-9
......
......@@ -40,23 +40,23 @@
- if current_user.can_leave_project?(project)
.pull-right
= link_to leave_project_team_members_path(project), data: { confirm: "Leave project?"}, method: :delete, remote: true, class: "btn-tiny btn remove-row", title: 'Leave project' do
%i.icon-signout
%i.fa.fa-sign-out
Leave
- if project.forked_from_project
%small.pull-right
%i.icon-code-fork
%i.fa.fa-code-fork
Forked from:
= link_to project.forked_from_project.name_with_namespace, project_path(project.forked_from_project)
.project-info
.pull-right
- if project.archived?
%span.label
%i.icon-archive
%i.fa.fa-archive
Archived
- project.tags.each do |tag|
%span.label.label-info
%i.icon-tag
%i.fa.fa-tag
= tag.name
- if project.description.present?
%p= truncate project.description, length: 100
......
......@@ -6,7 +6,7 @@
= render 'sidebar'
.fixed.sidebar-expand-button.hidden-lg.hidden-md
%i.icon-list.icon-2x
%i.fa.fa-list.fa-2x
- else
= render "zero_authorized_projects"
......@@ -9,7 +9,7 @@
.event-body
.event-note
.md
%i.icon-comment-alt.event-note-icon
%i.fa.fa-comment-o.event-note-icon
= event_note(event.target.note)
- note = event.target
- if note.attachment.url
......@@ -18,5 +18,5 @@
= image_tag note.attachment.secure_url, class: 'note-image-attach'
- else
= link_to note.attachment.secure_url, target: "_blank", class: 'note-file-attach' do
%i.icon-paper-clip
%i.fa.fa-paperclip
= note.attachment_identifier
......@@ -36,7 +36,7 @@
.clearfix
%h4
= link_to group_path(id: group.path) do
%i.icon-group
%i.fa.fa-users
= group.name
.clearfix
%p
......
......@@ -21,5 +21,5 @@
&middot;
= link_to pluralize(project.repository.tag_names.count, 'tag'), project_tags_path(project)
- else
%i.icon-warning-sign
%i.fa.fa-exclamation-triangle
Empty repository
.explore-trending-block
%p.lead
%i.icon-comments-alt
%i.fa.fa-comments-o
See most starred projects
%hr
.public-projects
......
.explore-trending-block
%p.lead
%i.icon-comments-alt
%i.fa.fa-comments-o
See most discussed projects for last month
%hr
.public-projects
......
......@@ -4,7 +4,7 @@
- if can? current_user, :create_projects, @group
.panel-head-actions
= link_to new_project_path(namespace_id: @group.id), class: "btn btn-new" do
%i.icon-plus
%i.fa.fa-plus
New project
%ul.well-list
- if projects.blank?
......@@ -18,4 +18,4 @@
%span.project-name
= project.name
%span.arrow
%i.icon-angle-right
%i.fa.fa-angle-right
%ul.nav.nav-pills.nav-stacked.nav-stacked-menu
= nav_link(path: 'groups#edit') do
= link_to edit_group_path(@group) do
%i.icon-edit
%i.fa.fa-pencil-square-o
Group
= nav_link(path: 'groups#projects') do
= link_to projects_group_path(@group) do
%i.icon-folder-close
%i.fa.fa-folder
Projects
......@@ -32,7 +32,7 @@
- else
You can upload a group avatar here
%a.choose-btn.btn.btn-small.js-choose-group-avatar-button
%i.icon-paper-clip
%i.fa.fa-paperclip
%span Choose File ...
&nbsp;
%span.file_name.js-avatar-filename File name...
......
......@@ -15,14 +15,14 @@
- if show_controls
- if can?(current_user, :modify, member)
= link_to '#', class: "btn-tiny btn js-toggle-button", title: 'Edit access level' do
%i.icon-edit
%i.fa.fa-pencil-square-o
- if can?(current_user, :destroy, member)
- if current_user == member.user
= link_to leave_profile_group_path(@group), data: { confirm: leave_group_message(@group.name)}, method: :delete, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
%i.icon-minus.icon-white
%i.fa.fa-minus.fa-inverse
- else
= link_to group_group_member_path(@group, member), data: { confirm: remove_user_from_group_message(@group, user) }, method: :delete, remote: true, class: "btn-tiny btn btn-remove", title: 'Remove user from group' do
%i.icon-minus.icon-white
%i.fa.fa-minus.fa-inverse
.edit-member.hide.js-toggle-content
= form_for [@group, member], remote: true do |f|
......
......@@ -11,7 +11,7 @@
.row
.fixed.sidebar-expand-button.hidden-lg.hidden-md
%i.icon-list.icon-2x
%i.fa.fa-list.fa-2x
.col-md-3.responsive-side
= render 'shared/filter', entity: 'issue'
.col-md-9
......
......@@ -19,7 +19,7 @@
.pull-right
= link_to '#', class: 'btn btn-new js-toggle-button' do
Add members
%i.icon-chevron-down
%i.fa.fa-chevron-down
.js-toggle-content.hide.new-group-member-holder
= render "new_group_member"
......
......@@ -10,7 +10,7 @@
%hr
.row
.fixed.sidebar-expand-button.hidden-lg.hidden-md
%i.icon-list.icon-2x
%i.fa.fa-list.fa-2x
.col-md-3.responsive-side
= render 'shared/filter', entity: 'merge_request'
.col-md-9
......
......@@ -11,7 +11,7 @@
.row
.fixed.sidebar-expand-button.hidden-lg.hidden-md
%i.icon-list.icon-2x
%i.fa.fa-list.fa-2x
.col-md-3.responsive-side
= render 'groups/filter', entity: 'milestone'
.col-md-9
......
......@@ -17,7 +17,7 @@
= f.label :avatar, "Group avatar", class: 'control-label'
.col-sm-10
%a.choose-btn.btn.btn-small.js-choose-group-avatar-button
%i.icon-paper-clip
%i.fa.fa-paperclip
%span Choose File ...
&nbsp;
%span.file_name.js-avatar-filename File name...
......
......@@ -9,7 +9,7 @@
- if can? current_user, :manage_group, @group
.panel-head-actions
= link_to new_project_path(namespace_id: @group.id), class: "btn btn-new" do
%i.icon-plus
%i.fa.fa-plus
New Project
%ul.well-list
- @projects.each do |project|
......
......@@ -24,13 +24,13 @@
= @group.name
- if @group.description.present?
%p
= auto_link @group.description, link: :urls
= escaped_autolink(@group.description)
= render "projects", projects: @projects
- if current_user
.prepend-top-20
= link_to group_path(@group, { format: :atom, private_token: current_user.private_token }), title: "Feed" do
%strong
%i.icon-rss
%i.fa.fa-rss
News Feed
%hr
......
......@@ -29,12 +29,12 @@
%tr
%td.shortcut
.key
%i.icon-arrow-up
%i.fa.fa-arrow-up
%td Move selection up
%tr
%td.shortcut
.key
%i.icon-arrow-down
%i.fa.fa-arrow-down
%td Move selection down
%tr
%td.shortcut
......@@ -132,28 +132,28 @@
%tr
%td.shortcut
.key
%i.icon-arrow-left
%i.fa.fa-arrow-left
\/
.key h
%td Scroll left
%tr
%td.shortcut
.key
%i.icon-arrow-right
%i.fa.fa-arrow-right
\/
.key l
%td Scroll right
%tr
%td.shortcut
.key
%i.icon-arrow-up
%i.fa.fa-arrow-up
\/
.key k
%td Scroll up
%tr
%td.shortcut
.key
%i.icon-arrow-down
%i.fa.fa-arrow-down
\/
.key j
%td Scroll down
......@@ -161,7 +161,7 @@
%td.shortcut
.key
shift
%i.icon-arrow-up
%i.fa.fa-arrow-up
\/
.key
shift k
......@@ -170,7 +170,7 @@
%td.shortcut
.key
shift
%i.icon-arrow-down
%i.fa.fa-arrow-down
\/
.key
shift j
......
......@@ -14,7 +14,7 @@
%br
Used by more than 100,000 organizations, GitLab is the most popular solution to manage git repositories on-premises.
%br
Read more about GitLab at #{link_to "www.gitlab.com", "https://www.gitlab.com/", target: "_blank"}.
Read more about GitLab at #{link_to promo_host, promo_url, target: '_blank'}.
%hr
......@@ -34,7 +34,7 @@
%ul.well-list
%li
See our website for
= link_to "getting help", "https://www.gitlab.com/getting-help/"
= link_to 'getting help', promo_url + '/getting-help/'
%li
Use the
= link_to 'search bar', '#', onclick: 'Shortcuts.focusSearch(event)'
......
- if broadcast_message.present?
.broadcast-message{ style: broadcast_styling(broadcast_message) }
%i.icon-bullhorn
%i.fa.fa-bullhorn
= broadcast_message.message
......@@ -10,7 +10,7 @@
%button.navbar-toggle{"data-target" => ".navbar-collapse", "data-toggle" => "collapse", type: "button"}
%span.sr-only Toggle navigation
%i.icon-reorder
%i.fa.fa-bars
.navbar-collapse.collapse
%ul.nav.navbar-nav
......@@ -18,31 +18,31 @@
= render "layouts/search"
%li.visible-sm.visible-xs
= link_to search_path, title: "Search", class: 'has_bottom_tooltip', 'data-original-title' => 'Search area' do
%i.icon-search
%i.fa.fa-search
%li
= link_to help_path, title: 'Help', class: 'has_bottom_tooltip',
'data-original-title' => 'Help' do
%i.icon-question-sign
%i.fa.fa-question-circle
%li
= link_to explore_root_path, title: "Explore", class: 'has_bottom_tooltip', 'data-original-title' => 'Public area' do
%i.icon-globe
%i.fa.fa-globe
%li
= link_to user_snippets_path(current_user), title: "My snippets", class: 'has_bottom_tooltip', 'data-original-title' => 'My snippets' do
%i.icon-paste
%i.fa.fa-clipboard
- if current_user.is_admin?
%li
= link_to admin_root_path, title: "Admin area", class: 'has_bottom_tooltip', 'data-original-title' => 'Admin area' do
%i.icon-cogs
%i.fa.fa-cogs
- if current_user.can_create_project?
%li
= link_to new_project_path, title: "New project", class: 'has_bottom_tooltip', 'data-original-title' => 'New project' do
%i.icon-plus
%i.fa.fa-plus
%li
= link_to profile_path, title: "Profile settings", class: 'has_bottom_tooltip', 'data-original-title' => 'Profile settings"' do
%i.icon-user
%i.fa.fa-user
%li
= link_to destroy_user_session_path, class: "logout", method: :delete, title: "Logout", class: 'has_bottom_tooltip', 'data-original-title' => 'Logout' do
%i.icon-signout
%i.fa.fa-sign-out
%li.hidden-xs
= link_to current_user, class: "profile-pic", id: 'profile-pic' do
= image_tag avatar_icon(current_user.email, 26), alt: 'User activity'
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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