Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into configure-protection
Conflicts: CHANGELOG db/schema.rb
This commit is contained in:
commit
20e269cb92
17
CHANGELOG
17
CHANGELOG
|
@ -3,10 +3,10 @@ Note: The upcoming release contains empty lines to reduce the number of merge co
|
|||
v 7.8.0
|
||||
- Replace highlight.js with rouge-fork rugments (Stefan Tatschner)
|
||||
- Make project search case insensitive (Hannes Rosenögger)
|
||||
-
|
||||
- Include issue/mr participants in list of recipients for reassign/close/reopen emails
|
||||
- Expose description in groups API
|
||||
-
|
||||
-
|
||||
- Better UI for project services page
|
||||
- Cleaner UI for web editor
|
||||
- Add diff syntax highlighting in email-on-push service notifications (Hannes Rosenögger)
|
||||
-
|
||||
-
|
||||
|
@ -17,8 +17,10 @@ v 7.8.0
|
|||
- Show tags in commit view (Hannes Rosenögger)
|
||||
- Only count a user's vote once on a merge request or issue (Michael Clarke)
|
||||
-
|
||||
- Increate font size when browse source files and diffs
|
||||
- Create new file in empty repository using GitLab UI
|
||||
-
|
||||
-
|
||||
- Ability to clone project using oauth2 token
|
||||
-
|
||||
- Upgrade Sidekiq gem to version 3.3.0
|
||||
- Stop git zombie creation during force push check
|
||||
|
@ -29,11 +31,13 @@ v 7.8.0
|
|||
-
|
||||
-
|
||||
- Allow configuring protection of the default branch upon first push (Marco Wessel)
|
||||
-
|
||||
-
|
||||
- Add a commit calendar to the user profile (Hannes Rosenögger)
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
-
|
||||
- Fix long broadcast message cut-off on left sidebar (Visay Keo)
|
||||
- Add Project Avatars (Steven Thonus and Hannes Rosenögger)
|
||||
-
|
||||
-
|
||||
|
@ -59,6 +63,7 @@ v 7.8.0
|
|||
-
|
||||
-
|
||||
-
|
||||
- Added support for firing system hooks on group create/destroy and adding/removing users to group (Boyan Tabakov)
|
||||
|
||||
v 7.7.1
|
||||
- Improve mention autocomplete performance
|
||||
|
|
5
Gemfile
5
Gemfile
|
@ -154,6 +154,9 @@ gem "slack-notifier", "~> 1.0.0"
|
|||
# d3
|
||||
gem "d3_rails", "~> 3.1.4"
|
||||
|
||||
#cal-heatmap
|
||||
gem "cal-heatmap-rails", "~> 0.0.1"
|
||||
|
||||
# underscore-rails
|
||||
gem "underscore-rails", "~> 1.4.4"
|
||||
|
||||
|
@ -170,7 +173,7 @@ gem 'ace-rails-ap'
|
|||
gem 'mousetrap-rails'
|
||||
|
||||
# Semantic UI Sass for Sidebar
|
||||
gem 'semantic-ui-sass', '~> 0.16.1.0'
|
||||
gem 'semantic-ui-sass', '~> 1.8.0'
|
||||
|
||||
gem "sass-rails", '~> 4.0.2'
|
||||
gem "coffee-rails"
|
||||
|
|
|
@ -52,6 +52,7 @@ GEM
|
|||
sass (~> 3.2)
|
||||
browser (0.7.2)
|
||||
builder (3.2.2)
|
||||
cal-heatmap-rails (0.0.1)
|
||||
capybara (2.2.1)
|
||||
mime-types (>= 1.16)
|
||||
nokogiri (>= 1.3.3)
|
||||
|
@ -490,7 +491,7 @@ GEM
|
|||
activesupport (>= 3.1, < 4.2)
|
||||
select2-rails (3.5.2)
|
||||
thor (~> 0.14)
|
||||
semantic-ui-sass (0.16.1.0)
|
||||
semantic-ui-sass (1.8.0.0)
|
||||
sass (~> 3.2)
|
||||
settingslogic (2.0.9)
|
||||
sexp_processor (4.4.0)
|
||||
|
@ -627,6 +628,7 @@ DEPENDENCIES
|
|||
binding_of_caller
|
||||
bootstrap-sass (~> 3.0)
|
||||
browser
|
||||
cal-heatmap-rails (~> 0.0.1)
|
||||
capybara (~> 2.2.1)
|
||||
carrierwave
|
||||
coffee-rails
|
||||
|
@ -715,7 +717,7 @@ DEPENDENCIES
|
|||
sdoc
|
||||
seed-fu
|
||||
select2-rails
|
||||
semantic-ui-sass (~> 0.16.1.0)
|
||||
semantic-ui-sass (~> 1.8.0)
|
||||
settingslogic
|
||||
shoulda-matchers (~> 2.1.0)
|
||||
sidekiq (~> 3.3)
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 3.3 KiB |
|
@ -39,6 +39,7 @@
|
|||
#= require shortcuts_dashboard_navigation
|
||||
#= require shortcuts_issueable
|
||||
#= require shortcuts_network
|
||||
#= require cal-heatmap
|
||||
#= require_tree .
|
||||
|
||||
window.slugify = (text) ->
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
class @EditBlob
|
||||
constructor: (assets_path, mode)->
|
||||
ace.config.set "modePath", assets_path + '/ace'
|
||||
ace.config.loadModule "ace/ext/searchbox"
|
||||
if mode
|
||||
ace_mode = mode
|
||||
editor = ace.edit("editor")
|
||||
editor.focus()
|
||||
@editor = editor
|
||||
|
||||
if ace_mode
|
||||
editor.getSession().setMode "ace/mode/" + ace_mode
|
||||
|
||||
disableButtonIfEmptyField "#commit_message", ".js-commit-button"
|
||||
$(".js-commit-button").click ->
|
||||
$("#file-content").val editor.getValue()
|
||||
$(".file-editor form").submit()
|
||||
return
|
||||
|
||||
editModePanes = $(".js-edit-mode-pane")
|
||||
editModeLinks = $(".js-edit-mode a")
|
||||
editModeLinks.click (event) ->
|
||||
event.preventDefault()
|
||||
currentLink = $(this)
|
||||
paneId = currentLink.attr("href")
|
||||
currentPane = editModePanes.filter(paneId)
|
||||
editModeLinks.parent().removeClass "active hover"
|
||||
currentLink.parent().addClass "active hover"
|
||||
editModePanes.hide()
|
||||
if paneId is "#preview"
|
||||
currentPane.fadeIn 200
|
||||
$.post currentLink.data("preview-url"),
|
||||
content: editor.getValue()
|
||||
, (response) ->
|
||||
currentPane.empty().append response
|
||||
return
|
||||
|
||||
else
|
||||
currentPane.fadeIn 200
|
||||
editor.focus()
|
||||
return
|
||||
|
||||
editor: ->
|
||||
return @editor
|
|
@ -0,0 +1,21 @@
|
|||
class @NewBlob
|
||||
constructor: (assets_path, mode)->
|
||||
ace.config.set "modePath", assets_path + '/ace'
|
||||
ace.config.loadModule "ace/ext/searchbox"
|
||||
if mode
|
||||
ace_mode = mode
|
||||
editor = ace.edit("editor")
|
||||
editor.focus()
|
||||
@editor = editor
|
||||
|
||||
if ace_mode
|
||||
editor.getSession().setMode "ace/mode/" + ace_mode
|
||||
|
||||
disableButtonIfEmptyField "#commit_message", ".js-commit-button"
|
||||
$(".js-commit-button").click ->
|
||||
$("#file-content").val editor.getValue()
|
||||
$(".file-editor form").submit()
|
||||
return
|
||||
|
||||
editor: ->
|
||||
return @editor
|
|
@ -0,0 +1,35 @@
|
|||
class @calendar
|
||||
options =
|
||||
month: "short"
|
||||
day: "numeric"
|
||||
year: "numeric"
|
||||
|
||||
constructor: (timestamps, starting_year, starting_month) ->
|
||||
cal = new CalHeatMap()
|
||||
cal.init
|
||||
itemName: ["commit"]
|
||||
data: timestamps
|
||||
domain: "year"
|
||||
subDomain: "month"
|
||||
start: new Date(starting_year, starting_month)
|
||||
domainLabelFormat: "%b"
|
||||
id: "cal-heatmap"
|
||||
domain: "month"
|
||||
subDomain: "day"
|
||||
range: 12
|
||||
tooltip: true
|
||||
domainDynamicDimension: false
|
||||
colLimit: 4
|
||||
label:
|
||||
position: "top"
|
||||
domainMargin: 1
|
||||
legend: [
|
||||
0
|
||||
1
|
||||
4
|
||||
7
|
||||
]
|
||||
legendCellPadding: 3
|
||||
onClick: (date, count) ->
|
||||
return
|
||||
return
|
|
@ -9,17 +9,3 @@ class @ProjectNew
|
|||
|
||||
initEvents: ->
|
||||
disableButtonIfEmptyField '#project_name', '.project-submit'
|
||||
|
||||
$('#project_issues_enabled').change ->
|
||||
if ($(this).is(':checked') == true)
|
||||
$('#project_issues_tracker').removeAttr('disabled')
|
||||
else
|
||||
$('#project_issues_tracker').attr('disabled', 'disabled')
|
||||
|
||||
$('#project_issues_tracker').change()
|
||||
|
||||
$('#project_issues_tracker').change ->
|
||||
if ($(this).val() == gon.default_issues_tracker || $(this).is(':disabled'))
|
||||
$('#project_issues_tracker_id').attr('disabled', 'disabled')
|
||||
else
|
||||
$('#project_issues_tracker_id').removeAttr('disabled')
|
||||
|
|
|
@ -6,7 +6,7 @@ class @ProjectShow
|
|||
new Flash('Star toggle failed. Try again later.', 'alert')
|
||||
|
||||
$("a[data-toggle='tab']").on "shown.bs.tab", (e) ->
|
||||
$.cookie "default_view", $(e.target).attr("href")
|
||||
$.cookie "default_view", $(e.target).attr("href"), { expires: 30 }
|
||||
|
||||
defaultView = $.cookie("default_view")
|
||||
if defaultView
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
*= require select2
|
||||
*= require_self
|
||||
*= require dropzone/basic
|
||||
*= require cal-heatmap
|
||||
*/
|
||||
|
||||
@import "main/*";
|
||||
|
|
|
@ -173,6 +173,11 @@
|
|||
margin-right: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
&.btn-lg {
|
||||
font-size: 15px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
}
|
||||
|
||||
.btn-block {
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
.calendar_onclick_placeholder {
|
||||
padding: 0 0 2px 0;
|
||||
}
|
||||
|
||||
.calendar_commit_activity {
|
||||
padding: 5px 0 0;
|
||||
}
|
||||
|
||||
.calendar_onclick_second {
|
||||
font-size: 14px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.calendar_onclick_hr {
|
||||
padding: 0;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.calendar_commit_date {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.calendar_activity_summary {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/**
|
||||
* This overwrites the default values of the cal-heatmap gem
|
||||
*/
|
||||
.calendar {
|
||||
.qi {
|
||||
background-color: #999;
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
.q1 {
|
||||
background-color: #dae289;
|
||||
fill: #ededed;
|
||||
}
|
||||
|
||||
.q2 {
|
||||
background-color: #cedb9c;
|
||||
fill: #ACD5F2;
|
||||
}
|
||||
|
||||
.q3 {
|
||||
background-color: #b5cf6b;
|
||||
fill: #7FA8D1;
|
||||
}
|
||||
|
||||
.q4 {
|
||||
background-color: #637939;
|
||||
fill: #49729B;
|
||||
}
|
||||
|
||||
.q5 {
|
||||
background-color: #3b6427;
|
||||
fill: #254E77;
|
||||
}
|
||||
|
||||
.domain-background {
|
||||
fill: none;
|
||||
shape-rendering: crispedges;
|
||||
}
|
||||
|
||||
.ch-tooltip {
|
||||
position: absolute;
|
||||
display: none;
|
||||
margin-top: 22px;
|
||||
margin-left: 1px;
|
||||
font-size: 13px;
|
||||
padding: 3px;
|
||||
font-weight: 550;
|
||||
background-color: #222;
|
||||
span {
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
text-align: center;
|
||||
visibility: hidden;
|
||||
border-radius: 10px;
|
||||
&:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 50%;
|
||||
margin-left: -8px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: 8px solid #000000;
|
||||
border-right: 8px solid transparent;
|
||||
border-left: 8px solid transparent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,8 +10,8 @@
|
|||
border: none;
|
||||
border-radius: 0;
|
||||
font-family: $monospace_font;
|
||||
font-size: 12px !important;
|
||||
line-height: 16px !important;
|
||||
font-size: $code_font_size !important;
|
||||
line-height: $code_line_height !important;
|
||||
margin: 0;
|
||||
overflow: auto;
|
||||
overflow-y: hidden;
|
||||
|
@ -38,8 +38,8 @@
|
|||
a {
|
||||
font-family: $monospace_font;
|
||||
display: block;
|
||||
font-size: 12px !important;
|
||||
line-height: 16px !important;
|
||||
font-size: $code_font_size !important;
|
||||
line-height: $code_line_height !important;
|
||||
white-space: nowrap;
|
||||
|
||||
i {
|
||||
|
|
|
@ -1,9 +1,6 @@
|
|||
/*
|
||||
* Twitter bootstrap with GitLab customizations/additions
|
||||
*
|
||||
* Some unused bootstrap compontents like panels are not included.
|
||||
* Other components like tabs are modified to GitLab style.
|
||||
*
|
||||
*/
|
||||
|
||||
$font-size-base: 13px !default;
|
||||
|
|
|
@ -139,7 +139,7 @@
|
|||
}
|
||||
|
||||
@mixin panel-colored {
|
||||
border: none;
|
||||
border: 1px solid #EEE;
|
||||
background: $box_bg;
|
||||
@include box-shadow(0 1px 1px rgba(0, 0, 0, 0.09));
|
||||
|
||||
|
|
|
@ -59,3 +59,5 @@ $list-font-size: 15px;
|
|||
$sidebar_width: 230px;
|
||||
|
||||
$avatar_radius: 50%;
|
||||
$code_font_size: 13px;
|
||||
$code_line_height: 1.5;
|
||||
|
|
|
@ -112,3 +112,7 @@
|
|||
color: #FFF;
|
||||
}
|
||||
}
|
||||
|
||||
.dash-list .str-truncated {
|
||||
max-width: 72%;
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
overflow-y: hidden;
|
||||
background: #FFF;
|
||||
color: #333;
|
||||
font-size: 12px;
|
||||
font-size: $code_font_size;
|
||||
.old {
|
||||
span.idiff {
|
||||
background-color: #F99;
|
||||
|
@ -64,8 +64,8 @@
|
|||
margin: 0px;
|
||||
padding: 0px;
|
||||
td {
|
||||
line-height: 18px;
|
||||
font-size: 12px;
|
||||
line-height: $code_line_height;
|
||||
font-size: $code_font_size;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,4 +31,26 @@
|
|||
margin: 5px 8px 0 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.file-title {
|
||||
@extend .monospace;
|
||||
font-size: 14px;
|
||||
padding: 5px;
|
||||
}
|
||||
|
||||
.editor-ref {
|
||||
background: #f5f5f5;
|
||||
padding: 11px 15px;
|
||||
border-right: 1px solid #CCC;
|
||||
display: inline-block;
|
||||
margin: -5px -5px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.editor-file-name {
|
||||
.new-file-name {
|
||||
display: inline-block;
|
||||
width: 200px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -138,9 +138,10 @@ header {
|
|||
top: -1px;
|
||||
padding-right: 0px !important;
|
||||
img {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
@include border-radius($avatar_radius);
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: -15px;
|
||||
margin-left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -163,8 +163,9 @@ form.edit-issue {
|
|||
}
|
||||
}
|
||||
|
||||
.issue-title {
|
||||
h3.issue-title {
|
||||
margin-top: 0;
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.context .select2-container {
|
||||
|
|
|
@ -122,6 +122,7 @@
|
|||
background: $box_bg;
|
||||
margin-bottom: 20px;
|
||||
color: #666;
|
||||
border: 1px solid #EEE;
|
||||
@include box-shadow(0 1px 1px rgba(0, 0, 0, 0.09));
|
||||
|
||||
.ci_widget {
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
|
||||
.project-home-panel {
|
||||
margin-bottom: 15px;
|
||||
position: relative;
|
||||
padding-left: 85px;
|
||||
|
||||
&.empty-project {
|
||||
border-bottom: 0px;
|
||||
|
@ -23,6 +25,22 @@
|
|||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.project-identicon-holder {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
|
||||
.avatar {
|
||||
width: 70px;
|
||||
height: 70px;
|
||||
@include border-radius(0px);
|
||||
}
|
||||
|
||||
.identicon {
|
||||
font-size: 45px;
|
||||
line-height: 1.6;
|
||||
}
|
||||
}
|
||||
|
||||
.project-home-dropdown {
|
||||
margin-left: 10px;
|
||||
float: right;
|
||||
|
|
|
@ -181,7 +181,7 @@ class ApplicationController < ActionController::Base
|
|||
end
|
||||
|
||||
def add_gon_variables
|
||||
gon.default_issues_tracker = Project.issues_tracker.default_value
|
||||
gon.default_issues_tracker = Project.new.default_issue_tracker.to_param
|
||||
gon.api_version = API::API.version
|
||||
gon.relative_url_root = Gitlab.config.gitlab.relative_url_root
|
||||
gon.default_avatar_url = URI::join(Gitlab.config.gitlab.url, ActionController::Base.helpers.image_path('no_avatar.png')).to_s
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
class Projects::BaseTreeController < Projects::ApplicationController
|
||||
include ExtractsPath
|
||||
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project
|
||||
end
|
||||
|
|
@ -2,7 +2,7 @@
|
|||
class Projects::BlameController < Projects::ApplicationController
|
||||
include ExtractsPath
|
||||
|
||||
# Authorize
|
||||
before_filter :assign_ref_vars
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project
|
||||
|
||||
|
|
|
@ -2,16 +2,70 @@
|
|||
class Projects::BlobController < Projects::ApplicationController
|
||||
include ExtractsPath
|
||||
|
||||
# Authorize
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project
|
||||
before_filter :authorize_push_code!, only: [:destroy]
|
||||
# Raised when given an invalid file path
|
||||
class InvalidPathError < StandardError; end
|
||||
|
||||
before_filter :blob
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project, except: [:new, :create]
|
||||
before_filter :authorize_push_code!, only: [:destroy]
|
||||
before_filter :assign_blob_vars
|
||||
before_filter :commit, except: [:new, :create]
|
||||
before_filter :blob, except: [:new, :create]
|
||||
before_filter :from_merge_request, only: [:edit, :update]
|
||||
before_filter :after_edit_path, only: [:edit, :update]
|
||||
before_filter :require_branch_head, only: [:edit, :update]
|
||||
|
||||
def new
|
||||
commit unless @repository.empty?
|
||||
end
|
||||
|
||||
def create
|
||||
file_path = File.join(@path, File.basename(params[:file_name]))
|
||||
result = Files::CreateService.new(@project, current_user, params, @ref, file_path).execute
|
||||
|
||||
if result[:status] == :success
|
||||
flash[:notice] = "Your changes have been successfully committed"
|
||||
redirect_to project_blob_path(@project, File.join(@ref, file_path))
|
||||
else
|
||||
flash[:alert] = result[:message]
|
||||
render :new
|
||||
end
|
||||
end
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def edit
|
||||
@last_commit = Gitlab::Git::Commit.last_for_path(@repository, @ref, @path).sha
|
||||
end
|
||||
|
||||
def update
|
||||
result = Files::UpdateService.
|
||||
new(@project, current_user, params, @ref, @path).execute
|
||||
|
||||
if result[:status] == :success
|
||||
flash[:notice] = "Your changes have been successfully committed"
|
||||
|
||||
if from_merge_request
|
||||
from_merge_request.reload_code
|
||||
end
|
||||
|
||||
redirect_to after_edit_path
|
||||
else
|
||||
flash[:alert] = result[:message]
|
||||
render :edit
|
||||
end
|
||||
end
|
||||
|
||||
def preview
|
||||
@content = params[:content]
|
||||
diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3',
|
||||
include_diff_info: true)
|
||||
@diff_lines = Gitlab::Diff::Parser.new.parse(diffy.diff.scan(/.*\n/))
|
||||
|
||||
render layout: false
|
||||
end
|
||||
|
||||
def destroy
|
||||
result = Files::DeleteService.new(@project, current_user, params, @ref, @path).execute
|
||||
|
||||
|
@ -46,10 +100,44 @@ class Projects::BlobController < Projects::ApplicationController
|
|||
|
||||
if @blob
|
||||
@blob
|
||||
elsif tree.entries.any?
|
||||
redirect_to project_tree_path(@project, File.join(@ref, @path)) and return
|
||||
else
|
||||
if tree = @repository.tree(@commit.id, @path)
|
||||
if tree.entries.any?
|
||||
redirect_to project_tree_path(@project, File.join(@ref, @path)) and return
|
||||
end
|
||||
end
|
||||
|
||||
return not_found!
|
||||
end
|
||||
end
|
||||
|
||||
def commit
|
||||
@commit = @repository.commit(@ref)
|
||||
|
||||
return not_found! unless @commit
|
||||
end
|
||||
|
||||
def assign_blob_vars
|
||||
@id = params[:id]
|
||||
@ref, @path = extract_ref(@id)
|
||||
|
||||
|
||||
rescue InvalidPathError
|
||||
not_found!
|
||||
end
|
||||
|
||||
def after_edit_path
|
||||
@after_edit_path ||=
|
||||
if from_merge_request
|
||||
diffs_project_merge_request_path(from_merge_request.target_project, from_merge_request) +
|
||||
"#file-path-#{hexdigest(@path)}"
|
||||
else
|
||||
project_blob_path(@project, @id)
|
||||
end
|
||||
end
|
||||
|
||||
def from_merge_request
|
||||
# If blob edit was initiated from merge request page
|
||||
@from_merge_request ||= MergeRequest.find_by(id: params[:from_merge_request_id])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,7 +3,7 @@ require "base64"
|
|||
class Projects::CommitsController < Projects::ApplicationController
|
||||
include ExtractsPath
|
||||
|
||||
# Authorize
|
||||
before_filter :assign_ref_vars
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project
|
||||
|
||||
|
|
|
@ -1,60 +0,0 @@
|
|||
class Projects::EditTreeController < Projects::BaseTreeController
|
||||
before_filter :require_branch_head
|
||||
before_filter :blob
|
||||
before_filter :authorize_push_code!
|
||||
before_filter :from_merge_request
|
||||
before_filter :after_edit_path
|
||||
|
||||
def show
|
||||
@last_commit = Gitlab::Git::Commit.last_for_path(@repository, @ref, @path).sha
|
||||
end
|
||||
|
||||
def update
|
||||
result = Files::UpdateService.
|
||||
new(@project, current_user, params, @ref, @path).execute
|
||||
|
||||
if result[:status] == :success
|
||||
flash[:notice] = "Your changes have been successfully committed"
|
||||
|
||||
if from_merge_request
|
||||
from_merge_request.reload_code
|
||||
end
|
||||
|
||||
redirect_to after_edit_path
|
||||
else
|
||||
flash[:alert] = result[:message]
|
||||
render :show
|
||||
end
|
||||
end
|
||||
|
||||
def preview
|
||||
@content = params[:content]
|
||||
|
||||
diffy = Diffy::Diff.new(@blob.data, @content, diff: '-U 3',
|
||||
include_diff_info: true)
|
||||
@diff_lines = Gitlab::Diff::Parser.new.parse(diffy.diff.scan(/.*\n/))
|
||||
|
||||
render layout: false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def blob
|
||||
@blob ||= @repository.blob_at(@commit.id, @path)
|
||||
end
|
||||
|
||||
def after_edit_path
|
||||
@after_edit_path ||=
|
||||
if from_merge_request
|
||||
diffs_project_merge_request_path(from_merge_request.target_project, from_merge_request) +
|
||||
"#file-path-#{hexdigest(@path)}"
|
||||
else
|
||||
project_blob_path(@project, @id)
|
||||
end
|
||||
end
|
||||
|
||||
def from_merge_request
|
||||
# If blob edit was initiated from merge request page
|
||||
@from_merge_request ||= MergeRequest.find_by(id: params[:from_merge_request_id])
|
||||
end
|
||||
end
|
|
@ -2,7 +2,7 @@ class Projects::NetworkController < Projects::ApplicationController
|
|||
include ExtractsPath
|
||||
include ApplicationHelper
|
||||
|
||||
# Authorize
|
||||
before_filter :assign_ref_vars
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project
|
||||
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
class Projects::NewTreeController < Projects::BaseTreeController
|
||||
before_filter :require_branch_head
|
||||
before_filter :authorize_push_code!
|
||||
|
||||
def show
|
||||
end
|
||||
|
||||
def update
|
||||
file_path = File.join(@path, File.basename(params[:file_name]))
|
||||
result = Files::CreateService.new(@project, current_user, params, @ref, file_path).execute
|
||||
|
||||
if result[:status] == :success
|
||||
flash[:notice] = "Your changes have been successfully committed"
|
||||
redirect_to project_blob_path(@project, File.join(@ref, file_path))
|
||||
else
|
||||
flash[:alert] = result[:message]
|
||||
render :show
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,7 +2,7 @@
|
|||
class Projects::RawController < Projects::ApplicationController
|
||||
include ExtractsPath
|
||||
|
||||
# Authorize
|
||||
before_filter :assign_ref_vars
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
class Projects::RefsController < Projects::ApplicationController
|
||||
include ExtractsPath
|
||||
|
||||
# Authorize
|
||||
before_filter :assign_ref_vars
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ class Projects::ServicesController < Projects::ApplicationController
|
|||
|
||||
def index
|
||||
@project.build_missing_services
|
||||
@services = @project.services.reload
|
||||
@services = @project.services.visible.reload
|
||||
end
|
||||
|
||||
def edit
|
||||
|
@ -17,7 +17,8 @@ class Projects::ServicesController < Projects::ApplicationController
|
|||
|
||||
def update
|
||||
if @service.update_attributes(service_params)
|
||||
redirect_to edit_project_service_path(@project, @service.to_param)
|
||||
redirect_to edit_project_service_path(@project, @service.to_param),
|
||||
notice: 'Successfully updated.'
|
||||
else
|
||||
render 'edit'
|
||||
end
|
||||
|
@ -45,7 +46,8 @@ class Projects::ServicesController < Projects::ApplicationController
|
|||
:title, :token, :type, :active, :api_key, :subdomain,
|
||||
:room, :recipients, :project_url, :webhook,
|
||||
:user_key, :device, :priority, :sound, :bamboo_url, :username, :password,
|
||||
:build_key, :server, :teamcity_url, :build_type
|
||||
:build_key, :server, :teamcity_url, :build_type,
|
||||
:description, :issues_url, :new_issue_url
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,12 @@
|
|||
# Controller for viewing a repository's file structure
|
||||
class Projects::TreeController < Projects::BaseTreeController
|
||||
def show
|
||||
class Projects::TreeController < Projects::ApplicationController
|
||||
include ExtractsPath
|
||||
|
||||
before_filter :assign_ref_vars
|
||||
before_filter :authorize_download_code!
|
||||
before_filter :require_non_empty_project, except: [:new, :create]
|
||||
|
||||
def show
|
||||
if tree.entries.empty?
|
||||
if @repository.blob_at(@commit.id, @path)
|
||||
redirect_to project_blob_path(@project, File.join(@ref, @path)) and return
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
class UsersController < ApplicationController
|
||||
skip_before_filter :authenticate_user!, only: [:show]
|
||||
skip_before_filter :authenticate_user!
|
||||
before_filter :set_user
|
||||
layout :determine_layout
|
||||
|
||||
def show
|
||||
@user = User.find_by_username!(params[:username])
|
||||
|
||||
unless current_user || @user.public_profile?
|
||||
return authenticate_user!
|
||||
end
|
||||
|
||||
# Projects user can view
|
||||
authorized_projects_ids = ProjectsFinder.new.execute(current_user).pluck(:id)
|
||||
visible_projects = ProjectsFinder.new.execute(current_user)
|
||||
authorized_projects_ids = visible_projects.pluck(:id)
|
||||
|
||||
@projects = @user.personal_projects.
|
||||
where(id: authorized_projects_ids)
|
||||
|
@ -30,6 +26,19 @@ class UsersController < ApplicationController
|
|||
end
|
||||
end
|
||||
|
||||
def calendar
|
||||
visible_projects = ProjectsFinder.new.execute(current_user)
|
||||
|
||||
# Get user repositories and collect timestamps for commits
|
||||
user_repositories = visible_projects.map(&:repository)
|
||||
calendar = Gitlab::CommitsCalendar.new(user_repositories, @user)
|
||||
@timestamps = calendar.timestamps
|
||||
@starting_year = (Time.now - 1.year).strftime("%Y")
|
||||
@starting_month = Date.today.strftime("%m").to_i
|
||||
|
||||
render 'calendar', layout: false
|
||||
end
|
||||
|
||||
def determine_layout
|
||||
if current_user
|
||||
'navless'
|
||||
|
@ -37,4 +46,14 @@ class UsersController < ApplicationController
|
|||
'public_users'
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def set_user
|
||||
@user = User.find_by_username!(params[:username])
|
||||
|
||||
unless current_user || @user.public_profile?
|
||||
return authenticate_user!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -56,8 +56,6 @@ module ApplicationHelper
|
|||
image_tag project.avatar.url, options
|
||||
elsif project.avatar_in_git
|
||||
image_tag project_avatar_path(project), options
|
||||
elsif options[:only_uploaded]
|
||||
image_tag '/assets/no_project_icon.png', options
|
||||
else # generated icon
|
||||
project_identicon(project, options)
|
||||
end
|
||||
|
|
|
@ -19,4 +19,42 @@ module BlobHelper
|
|||
def no_highlight_files
|
||||
%w(credits changelog copying copyright license authors)
|
||||
end
|
||||
|
||||
def edit_blob_link(project, ref, path, options = {})
|
||||
blob =
|
||||
begin
|
||||
project.repository.blob_at(ref, path)
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
|
||||
if blob && blob.text?
|
||||
text = 'Edit'
|
||||
after = options[:after] || ''
|
||||
from_mr = options[:from_merge_request_id]
|
||||
link_opts = {}
|
||||
link_opts[:from_merge_request_id] = from_mr if from_mr
|
||||
cls = 'btn btn-small'
|
||||
if allowed_tree_edit?(project, ref)
|
||||
link_to text, project_edit_blob_path(project, tree_join(ref, path),
|
||||
link_opts), class: cls
|
||||
else
|
||||
content_tag :span, text, class: cls + ' disabled'
|
||||
end + after.html_safe
|
||||
else
|
||||
''
|
||||
end
|
||||
end
|
||||
|
||||
def leave_edit_message
|
||||
"Leave edit mode?\nAll unsaved changes will be lost."
|
||||
end
|
||||
|
||||
def editing_preview_title(filename)
|
||||
if Gitlab::MarkdownHelper.previewable?(filename)
|
||||
'Preview'
|
||||
else
|
||||
'Preview changes'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -16,45 +16,25 @@ module IssuesHelper
|
|||
def url_for_project_issues(project = @project)
|
||||
return '' if project.nil?
|
||||
|
||||
if project.used_default_issues_tracker? || !external_issues_tracker_enabled?
|
||||
project_issues_path(project)
|
||||
else
|
||||
url = Gitlab.config.issues_tracker[project.issues_tracker]['project_url']
|
||||
url.gsub(':project_id', project.id.to_s).
|
||||
gsub(':issues_tracker_id', project.issues_tracker_id.to_s)
|
||||
end
|
||||
project.issues_tracker.project_url
|
||||
end
|
||||
|
||||
def url_for_new_issue(project = @project)
|
||||
return '' if project.nil?
|
||||
|
||||
if project.used_default_issues_tracker? || !external_issues_tracker_enabled?
|
||||
url = new_project_issue_path project_id: project
|
||||
else
|
||||
issues_tracker = Gitlab.config.issues_tracker[project.issues_tracker]
|
||||
url = issues_tracker['new_issue_url']
|
||||
url.gsub(':project_id', project.id.to_s).
|
||||
gsub(':issues_tracker_id', project.issues_tracker_id.to_s)
|
||||
end
|
||||
project.issues_tracker.new_issue_url
|
||||
end
|
||||
|
||||
def url_for_issue(issue_iid, project = @project)
|
||||
return '' if project.nil?
|
||||
|
||||
if project.used_default_issues_tracker? || !external_issues_tracker_enabled?
|
||||
url = project_issue_url project_id: project, id: issue_iid
|
||||
else
|
||||
url = Gitlab.config.issues_tracker[project.issues_tracker]['issues_url']
|
||||
url.gsub(':id', issue_iid.to_s).
|
||||
gsub(':project_id', project.id.to_s).
|
||||
gsub(':issues_tracker_id', project.issues_tracker_id.to_s)
|
||||
end
|
||||
project.issues_tracker.issue_url(issue_iid)
|
||||
end
|
||||
|
||||
def title_for_issue(issue_iid, project = @project)
|
||||
return '' if project.nil?
|
||||
|
||||
if project.used_default_issues_tracker?
|
||||
if project.default_issues_tracker?
|
||||
issue = project.issues.where(iid: issue_iid).first
|
||||
return issue.title if issue
|
||||
end
|
||||
|
@ -77,11 +57,6 @@ module IssuesHelper
|
|||
ts.html_safe
|
||||
end
|
||||
|
||||
# Checks if issues_tracker setting exists in gitlab.yml
|
||||
def external_issues_tracker_enabled?
|
||||
Gitlab.config.issues_tracker && Gitlab.config.issues_tracker.values.any?
|
||||
end
|
||||
|
||||
def bulk_update_milestone_options
|
||||
options_for_select(['None (backlog)']) +
|
||||
options_from_collection_for_select(project_active_milestones, 'id',
|
||||
|
|
|
@ -72,18 +72,6 @@ module ProjectsHelper
|
|||
@project.milestones.active.order("due_date, title ASC")
|
||||
end
|
||||
|
||||
def project_issues_trackers(current_tracker = nil)
|
||||
values = Project.issues_tracker.values.map do |tracker_key|
|
||||
if tracker_key.to_sym == :gitlab
|
||||
['GitLab', tracker_key]
|
||||
else
|
||||
[Gitlab.config.issues_tracker[tracker_key]['title'] || tracker_key, tracker_key]
|
||||
end
|
||||
end
|
||||
|
||||
options_for_select(values, current_tracker)
|
||||
end
|
||||
|
||||
def link_to_toggle_star(title, starred, signed_in)
|
||||
cls = 'star-btn'
|
||||
cls << ' disabled' unless signed_in
|
||||
|
@ -187,7 +175,13 @@ module ProjectsHelper
|
|||
"Issues - " + title
|
||||
end
|
||||
elsif current_controller?(:blob)
|
||||
"#{@project.path}\/#{@blob.path} at #{@ref} - " + title
|
||||
if current_action?(:new) || current_action?(:create)
|
||||
"New file at #{@ref}"
|
||||
elsif current_action?(:show)
|
||||
"#{@blob.path} at #{@ref}"
|
||||
elsif @blob
|
||||
"Edit file #{@blob.path} at #{@ref}"
|
||||
end
|
||||
elsif current_controller?(:commits)
|
||||
"Commits at #{@ref} - " + title
|
||||
elsif current_controller?(:merge_requests)
|
||||
|
@ -257,7 +251,7 @@ module ProjectsHelper
|
|||
end
|
||||
|
||||
def github_import_enabled?
|
||||
Gitlab.config.omniauth.enabled && enabled_oauth_providers.include?(:github)
|
||||
enabled_oauth_providers.include?(:github)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -64,32 +64,6 @@ module TreeHelper
|
|||
::Gitlab::GitAccess.can_push_to_branch?(current_user, project, ref)
|
||||
end
|
||||
|
||||
def edit_blob_link(project, ref, path, options = {})
|
||||
blob =
|
||||
begin
|
||||
project.repository.blob_at(ref, path)
|
||||
rescue
|
||||
nil
|
||||
end
|
||||
|
||||
if blob && blob.text?
|
||||
text = 'Edit'
|
||||
after = options[:after] || ''
|
||||
from_mr = options[:from_merge_request_id]
|
||||
link_opts = {}
|
||||
link_opts[:from_merge_request_id] = from_mr if from_mr
|
||||
cls = 'btn btn-small'
|
||||
if allowed_tree_edit?(project, ref)
|
||||
link_to text, project_edit_tree_path(project, tree_join(ref, path),
|
||||
link_opts), class: cls
|
||||
else
|
||||
content_tag :span, text, class: cls + ' disabled'
|
||||
end + after.html_safe
|
||||
else
|
||||
''
|
||||
end
|
||||
end
|
||||
|
||||
def tree_breadcrumbs(tree, max_links = 2)
|
||||
if @path.present?
|
||||
part_path = ""
|
||||
|
@ -121,16 +95,4 @@ module TreeHelper
|
|||
return tree.name
|
||||
end
|
||||
end
|
||||
|
||||
def leave_edit_message
|
||||
"Leave edit mode?\nAll unsaved changes will be lost."
|
||||
end
|
||||
|
||||
def editing_preview_title(filename)
|
||||
if Gitlab::MarkdownHelper.previewable?(filename)
|
||||
'Preview'
|
||||
else
|
||||
'Diff'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -25,6 +25,9 @@ class Group < Namespace
|
|||
|
||||
mount_uploader :avatar, AttachmentUploader
|
||||
|
||||
after_create :post_create_hook
|
||||
after_destroy :post_destroy_hook
|
||||
|
||||
def human_name
|
||||
name
|
||||
end
|
||||
|
@ -74,6 +77,18 @@ class Group < Namespace
|
|||
projects.public_only.any?
|
||||
end
|
||||
|
||||
def post_create_hook
|
||||
system_hook_service.execute_hooks_for(self, :create)
|
||||
end
|
||||
|
||||
def post_destroy_hook
|
||||
system_hook_service.execute_hooks_for(self, :destroy)
|
||||
end
|
||||
|
||||
def system_hook_service
|
||||
SystemHooksService.new
|
||||
end
|
||||
|
||||
class << self
|
||||
def search(query)
|
||||
where("LOWER(namespaces.name) LIKE :query", query: "%#{query.downcase}%")
|
||||
|
|
|
@ -27,8 +27,9 @@ class GroupMember < Member
|
|||
scope :with_group, ->(group) { where(source_id: group.id) }
|
||||
scope :with_user, ->(user) { where(user_id: user.id) }
|
||||
|
||||
after_create :notify_create
|
||||
after_create :post_create_hook
|
||||
after_update :notify_update
|
||||
after_destroy :post_destroy_hook
|
||||
|
||||
def self.access_level_roles
|
||||
Gitlab::Access.options_with_owner
|
||||
|
@ -42,8 +43,9 @@ class GroupMember < Member
|
|||
access_level
|
||||
end
|
||||
|
||||
def notify_create
|
||||
def post_create_hook
|
||||
notification_service.new_group_member(self)
|
||||
system_hook_service.execute_hooks_for(self, :create)
|
||||
end
|
||||
|
||||
def notify_update
|
||||
|
@ -52,6 +54,14 @@ class GroupMember < Member
|
|||
end
|
||||
end
|
||||
|
||||
def post_destroy_hook
|
||||
system_hook_service.execute_hooks_for(self, :destroy)
|
||||
end
|
||||
|
||||
def system_hook_service
|
||||
SystemHooksService.new
|
||||
end
|
||||
|
||||
def notification_service
|
||||
NotificationService.new
|
||||
end
|
||||
|
|
|
@ -74,7 +74,13 @@ class Project < ActiveRecord::Base
|
|||
has_one :bamboo_service, dependent: :destroy
|
||||
has_one :teamcity_service, dependent: :destroy
|
||||
has_one :pushover_service, dependent: :destroy
|
||||
has_one :forked_project_link, dependent: :destroy, foreign_key: 'forked_to_project_id'
|
||||
has_one :jira_service, dependent: :destroy
|
||||
has_one :redmine_service, dependent: :destroy
|
||||
has_one :custom_issue_tracker_service, dependent: :destroy
|
||||
has_one :gitlab_issue_tracker_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
|
||||
has_many :merge_requests, dependent: :destroy, foreign_key: 'target_project_id'
|
||||
|
@ -144,8 +150,6 @@ class Project < ActiveRecord::Base
|
|||
scope :public_and_internal_only, -> { where(visibility_level: Project.public_and_internal_levels) }
|
||||
scope :non_archived, -> { where(archived: false) }
|
||||
|
||||
enumerize :issues_tracker, in: (Gitlab.config.issues_tracker.keys).append(:gitlab), default: :gitlab
|
||||
|
||||
state_machine :import_status, initial: :none do
|
||||
event :import_start do
|
||||
transition [:none, :finished] => :started
|
||||
|
@ -305,19 +309,43 @@ class Project < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def issue_exists?(issue_id)
|
||||
if used_default_issues_tracker?
|
||||
if default_issues_tracker?
|
||||
self.issues.where(iid: issue_id).first.present?
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def used_default_issues_tracker?
|
||||
self.issues_tracker == Project.issues_tracker.default_value
|
||||
def default_issue_tracker
|
||||
gitlab_issue_tracker_service ||= create_gitlab_issue_tracker_service
|
||||
end
|
||||
|
||||
def issues_tracker
|
||||
if external_issue_tracker
|
||||
external_issue_tracker
|
||||
else
|
||||
default_issue_tracker
|
||||
end
|
||||
end
|
||||
|
||||
def default_issues_tracker?
|
||||
if external_issue_tracker
|
||||
false
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def external_issues_trackers
|
||||
services.select(&:issue_tracker?).reject(&:default?)
|
||||
end
|
||||
|
||||
def external_issue_tracker
|
||||
@external_issues_tracker ||= external_issues_trackers.select(&:activated?).first
|
||||
end
|
||||
|
||||
def can_have_issues_tracker_id?
|
||||
self.issues_enabled && !self.used_default_issues_tracker?
|
||||
self.issues_enabled && !self.default_issues_tracker?
|
||||
end
|
||||
|
||||
def build_missing_services
|
||||
|
@ -332,7 +360,7 @@ class Project < ActiveRecord::Base
|
|||
|
||||
def available_services_names
|
||||
%w(gitlab_ci campfire hipchat pivotaltracker flowdock assembla
|
||||
emails_on_push gemnasium slack pushover buildbox bamboo teamcity)
|
||||
emails_on_push gemnasium slack pushover buildbox bamboo teamcity jira redmine custom_issue_tracker)
|
||||
end
|
||||
|
||||
def gitlab_ci?
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
class CustomIssueTrackerService < IssueTrackerService
|
||||
|
||||
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
|
||||
|
||||
def title
|
||||
if self.properties && self.properties['title'].present?
|
||||
self.properties['title']
|
||||
else
|
||||
'Custom Issue Tracker'
|
||||
end
|
||||
end
|
||||
|
||||
def description
|
||||
if self.properties && self.properties['description'].present?
|
||||
self.properties['description']
|
||||
else
|
||||
'Custom issue tracker'
|
||||
end
|
||||
end
|
||||
|
||||
def to_param
|
||||
'custom_issue_tracker'
|
||||
end
|
||||
|
||||
def fields
|
||||
[
|
||||
{ type: 'text', name: 'title', placeholder: title },
|
||||
{ type: 'text', name: 'description', placeholder: description },
|
||||
{ type: 'text', name: 'project_url', placeholder: 'Project url' },
|
||||
{ type: 'text', name: 'issues_url', placeholder: 'Issue url'},
|
||||
{ type: 'text', name: 'new_issue_url', placeholder: 'New Issue url'}
|
||||
]
|
||||
end
|
||||
|
||||
def initialize_properties
|
||||
self.properties = {} if properties.nil?
|
||||
end
|
||||
end
|
|
@ -0,0 +1,25 @@
|
|||
class GitlabIssueTrackerService < IssueTrackerService
|
||||
include Rails.application.routes.url_helpers
|
||||
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
|
||||
|
||||
|
||||
def default?
|
||||
true
|
||||
end
|
||||
|
||||
def to_param
|
||||
'gitlab'
|
||||
end
|
||||
|
||||
def project_url
|
||||
project_issues_path(project)
|
||||
end
|
||||
|
||||
def new_issue_url
|
||||
new_project_issue_path project_id: project
|
||||
end
|
||||
|
||||
def issue_url(iid)
|
||||
"#{Gitlab.config.gitlab.url}#{project_issue_path(project_id: project, id: iid)}"
|
||||
end
|
||||
end
|
|
@ -0,0 +1,74 @@
|
|||
class IssueTrackerService < Service
|
||||
|
||||
validates :project_url, :issues_url, :new_issue_url, presence: true, if: :activated?
|
||||
|
||||
def category
|
||||
:issue_tracker
|
||||
end
|
||||
|
||||
def default?
|
||||
false
|
||||
end
|
||||
|
||||
def project_url
|
||||
# implement inside child
|
||||
end
|
||||
|
||||
def issues_url
|
||||
# implement inside child
|
||||
end
|
||||
|
||||
def new_issue_url
|
||||
# implement inside child
|
||||
end
|
||||
|
||||
def issue_url(iid)
|
||||
self.issues_url.gsub(':id', iid.to_s)
|
||||
end
|
||||
|
||||
def fields
|
||||
[
|
||||
{ type: 'text', name: 'description', placeholder: description },
|
||||
{ type: 'text', name: 'project_url', placeholder: 'Project url' },
|
||||
{ type: 'text', name: 'issues_url', placeholder: 'Issue url'},
|
||||
{ type: 'text', name: 'new_issue_url', placeholder: 'New Issue url'}
|
||||
]
|
||||
end
|
||||
|
||||
def initialize_properties
|
||||
if properties.nil?
|
||||
if enabled_in_gitlab_config
|
||||
self.properties = {
|
||||
title: issues_tracker['title'],
|
||||
project_url: set_project_url,
|
||||
issues_url: issues_tracker['issues_url'],
|
||||
new_issue_url: issues_tracker['new_issue_url']
|
||||
}
|
||||
else
|
||||
self.properties = {}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def enabled_in_gitlab_config
|
||||
Gitlab.config.issues_tracker &&
|
||||
Gitlab.config.issues_tracker.values.any? &&
|
||||
issues_tracker
|
||||
end
|
||||
|
||||
def issues_tracker
|
||||
Gitlab.config.issues_tracker[to_param]
|
||||
end
|
||||
|
||||
def set_project_url
|
||||
id = self.project.issues_tracker_id
|
||||
|
||||
if id
|
||||
issues_tracker['project_url'].gsub(":issues_tracker_id", id)
|
||||
else
|
||||
issues_tracker['project_url']
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,24 @@
|
|||
class JiraService < IssueTrackerService
|
||||
|
||||
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
|
||||
|
||||
def title
|
||||
if self.properties && self.properties['title'].present?
|
||||
self.properties['title']
|
||||
else
|
||||
'JIRA'
|
||||
end
|
||||
end
|
||||
|
||||
def description
|
||||
if self.properties && self.properties['description'].present?
|
||||
self.properties['description']
|
||||
else
|
||||
'Jira issue tracker'
|
||||
end
|
||||
end
|
||||
|
||||
def to_param
|
||||
'jira'
|
||||
end
|
||||
end
|
|
@ -0,0 +1,24 @@
|
|||
class RedmineService < IssueTrackerService
|
||||
|
||||
prop_accessor :title, :description, :project_url, :issues_url, :new_issue_url
|
||||
|
||||
def title
|
||||
if self.properties && self.properties['title'].present?
|
||||
self.properties['title']
|
||||
else
|
||||
'Redmine'
|
||||
end
|
||||
end
|
||||
|
||||
def description
|
||||
if self.properties && self.properties['description'].present?
|
||||
self.properties['description']
|
||||
else
|
||||
'Redmine issue tracker'
|
||||
end
|
||||
end
|
||||
|
||||
def to_param
|
||||
'redmine'
|
||||
end
|
||||
end
|
|
@ -139,8 +139,10 @@ class Repository
|
|||
|
||||
def graph_log
|
||||
Rails.cache.fetch(cache_key(:graph_log)) do
|
||||
commits = raw_repository.log(limit: 6000, skip_merges: true,
|
||||
commits = raw_repository.log(limit: 6000,
|
||||
skip_merges: true,
|
||||
ref: root_ref)
|
||||
|
||||
commits.map do |rugged_commit|
|
||||
commit = Gitlab::Git::Commit.new(rugged_commit)
|
||||
|
||||
|
@ -148,12 +150,32 @@ class Repository
|
|||
author_name: commit.author_name.force_encoding('UTF-8'),
|
||||
author_email: commit.author_email.force_encoding('UTF-8'),
|
||||
additions: commit.stats.additions,
|
||||
deletions: commit.stats.deletions
|
||||
deletions: commit.stats.deletions,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def timestamps_by_user_log(user)
|
||||
args = %W(git log --author=#{user.email} --since=#{(Date.today - 1.year).to_s} --pretty=format:%cd --date=short)
|
||||
dates = Gitlab::Popen.popen(args, path_to_repo).first.split("\n")
|
||||
|
||||
if dates.present?
|
||||
dates
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def commits_per_day_for_user(user)
|
||||
timestamps_by_user_log(user).
|
||||
group_by { |commit_date| commit_date }.
|
||||
inject({}) do |hash, (timestamp_date, commits)|
|
||||
hash[timestamp_date] = commits.count
|
||||
hash
|
||||
end
|
||||
end
|
||||
|
||||
def cache_key(type)
|
||||
"#{type}:#{path_with_namespace}"
|
||||
end
|
||||
|
|
|
@ -26,6 +26,8 @@ class Service < ActiveRecord::Base
|
|||
|
||||
validates :project_id, presence: true
|
||||
|
||||
scope :visible, -> { where.not(type: 'GitlabIssueTrackerService') }
|
||||
|
||||
def activated?
|
||||
active
|
||||
end
|
||||
|
@ -86,4 +88,12 @@ class Service < ActiveRecord::Base
|
|||
def async_execute(data)
|
||||
Sidekiq::Client.enqueue(ProjectServiceWorker, id, data)
|
||||
end
|
||||
|
||||
def issue_tracker?
|
||||
self.category == :issue_tracker
|
||||
end
|
||||
|
||||
def self.issue_tracker_service_list
|
||||
Service.select(&:issue_tracker?).map{ |s| s.to_param }
|
||||
end
|
||||
end
|
||||
|
|
|
@ -9,10 +9,6 @@ module Files
|
|||
return error("You are not allowed to create file in this branch")
|
||||
end
|
||||
|
||||
unless repository.branch_names.include?(ref)
|
||||
return error("You can only create files if you are on top of a branch")
|
||||
end
|
||||
|
||||
file_name = File.basename(path)
|
||||
file_path = path
|
||||
|
||||
|
@ -23,12 +19,21 @@ module Files
|
|||
)
|
||||
end
|
||||
|
||||
blob = repository.blob_at_branch(ref, file_path)
|
||||
if project.empty_repo?
|
||||
# everything is ok because repo does not have a commits yet
|
||||
else
|
||||
unless repository.branch_names.include?(ref)
|
||||
return error("You can only create files if you are on top of a branch")
|
||||
end
|
||||
|
||||
if blob
|
||||
return error("Your changes could not be committed, because file with such name exists")
|
||||
blob = repository.blob_at_branch(ref, file_path)
|
||||
|
||||
if blob
|
||||
return error("Your changes could not be committed, because file with such name exists")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
new_file_action = Gitlab::Satellite::NewFileAction.new(current_user, project, ref, file_path)
|
||||
created_successfully = new_file_action.commit!(
|
||||
params[:content],
|
||||
|
|
|
@ -2,9 +2,9 @@ module Issues
|
|||
class CloseService < Issues::BaseService
|
||||
def execute(issue, commit = nil)
|
||||
if issue.close
|
||||
notification_service.close_issue(issue, current_user)
|
||||
event_service.close_issue(issue, current_user)
|
||||
create_note(issue, commit)
|
||||
notification_service.close_issue(issue, current_user)
|
||||
execute_hooks(issue, 'close')
|
||||
end
|
||||
|
||||
|
|
|
@ -23,8 +23,8 @@ module Issues
|
|||
end
|
||||
|
||||
if issue.previous_changes.include?('assignee_id')
|
||||
notification_service.reassigned_issue(issue, current_user)
|
||||
create_assignee_note(issue)
|
||||
notification_service.reassigned_issue(issue, current_user)
|
||||
end
|
||||
|
||||
issue.notice_added_references(issue.project, current_user)
|
||||
|
|
|
@ -11,9 +11,9 @@ module MergeRequests
|
|||
if Gitlab::Satellite::MergeAction.new(current_user, merge_request).merge!(commit_message)
|
||||
merge_request.merge
|
||||
|
||||
notification_service.merge_mr(merge_request, current_user)
|
||||
create_merge_event(merge_request, current_user)
|
||||
create_note(merge_request)
|
||||
notification_service.merge_mr(merge_request, current_user)
|
||||
execute_hooks(merge_request)
|
||||
|
||||
true
|
||||
|
|
|
@ -7,8 +7,8 @@ module MergeRequests
|
|||
|
||||
if merge_request.close
|
||||
event_service.close_mr(merge_request, current_user)
|
||||
notification_service.close_mr(merge_request, current_user)
|
||||
create_note(merge_request)
|
||||
notification_service.close_mr(merge_request, current_user)
|
||||
execute_hooks(merge_request, 'close')
|
||||
end
|
||||
|
||||
|
|
|
@ -9,9 +9,9 @@ module MergeRequests
|
|||
def execute(merge_request, commit_message)
|
||||
merge_request.merge
|
||||
|
||||
notification_service.merge_mr(merge_request, current_user)
|
||||
create_merge_event(merge_request, current_user)
|
||||
create_note(merge_request)
|
||||
notification_service.merge_mr(merge_request, current_user)
|
||||
execute_hooks(merge_request, 'merge')
|
||||
|
||||
true
|
||||
|
|
|
@ -3,8 +3,8 @@ module MergeRequests
|
|||
def execute(merge_request)
|
||||
if merge_request.reopen
|
||||
event_service.reopen_mr(merge_request, current_user)
|
||||
notification_service.reopen_mr(merge_request, current_user)
|
||||
create_note(merge_request)
|
||||
notification_service.reopen_mr(merge_request, current_user)
|
||||
execute_hooks(merge_request, 'reopen')
|
||||
merge_request.reload_code
|
||||
merge_request.mark_as_unchecked
|
||||
|
|
|
@ -33,8 +33,8 @@ module MergeRequests
|
|||
end
|
||||
|
||||
if merge_request.previous_changes.include?('assignee_id')
|
||||
notification_service.reassigned_merge_request(merge_request, current_user)
|
||||
create_assignee_note(merge_request)
|
||||
notification_service.reassigned_merge_request(merge_request, current_user)
|
||||
end
|
||||
|
||||
merge_request.notice_added_references(merge_request.project, current_user)
|
||||
|
|
|
@ -314,15 +314,7 @@ class NotificationService
|
|||
end
|
||||
|
||||
def new_resource_email(target, project, method)
|
||||
if target.respond_to?(:participants)
|
||||
recipients = target.participants
|
||||
else
|
||||
recipients = []
|
||||
end
|
||||
|
||||
recipients = reject_muted_users(recipients, project)
|
||||
recipients = reject_mention_users(recipients, project)
|
||||
recipients = recipients.concat(project_watchers(project)).uniq
|
||||
recipients = build_recipients(target, project)
|
||||
recipients.delete(target.author)
|
||||
|
||||
recipients.each do |recipient|
|
||||
|
@ -331,9 +323,7 @@ class NotificationService
|
|||
end
|
||||
|
||||
def close_resource_email(target, project, current_user, method)
|
||||
recipients = reject_muted_users([target.author, target.assignee], project)
|
||||
recipients = reject_mention_users(recipients, project)
|
||||
recipients = recipients.concat(project_watchers(project)).uniq
|
||||
recipients = build_recipients(target, project)
|
||||
recipients.delete(current_user)
|
||||
|
||||
recipients.each do |recipient|
|
||||
|
@ -343,17 +333,7 @@ class NotificationService
|
|||
|
||||
def reassign_resource_email(target, project, current_user, method)
|
||||
assignee_id_was = previous_record(target, "assignee_id")
|
||||
|
||||
recipients = User.where(id: [target.assignee_id, assignee_id_was])
|
||||
|
||||
# Add watchers to email list
|
||||
recipients = recipients.concat(project_watchers(project))
|
||||
|
||||
# reject users with disabled notifications
|
||||
recipients = reject_muted_users(recipients, project)
|
||||
recipients = reject_mention_users(recipients, project)
|
||||
|
||||
# Reject me from recipients if I reassign an item
|
||||
recipients = build_recipients(target, project)
|
||||
recipients.delete(current_user)
|
||||
|
||||
recipients.each do |recipient|
|
||||
|
@ -362,9 +342,7 @@ class NotificationService
|
|||
end
|
||||
|
||||
def reopen_resource_email(target, project, current_user, method, status)
|
||||
recipients = reject_muted_users([target.author, target.assignee], project)
|
||||
recipients = reject_mention_users(recipients, project)
|
||||
recipients = recipients.concat(project_watchers(project)).uniq
|
||||
recipients = build_recipients(target, project)
|
||||
recipients.delete(current_user)
|
||||
|
||||
recipients.each do |recipient|
|
||||
|
@ -372,6 +350,20 @@ class NotificationService
|
|||
end
|
||||
end
|
||||
|
||||
def build_recipients(target, project)
|
||||
recipients =
|
||||
if target.respond_to?(:participants)
|
||||
target.participants
|
||||
else
|
||||
[target.author, target.assignee]
|
||||
end
|
||||
|
||||
recipients = reject_muted_users(recipients, project)
|
||||
recipients = reject_mention_users(recipients, project)
|
||||
recipients = recipients.concat(project_watchers(project)).uniq
|
||||
recipients
|
||||
end
|
||||
|
||||
def mailer
|
||||
Notify.delay
|
||||
end
|
||||
|
|
|
@ -60,6 +60,26 @@ class SystemHooksService
|
|||
access_level: model.human_access,
|
||||
project_visibility: Project.visibility_levels.key(model.project.visibility_level_field).downcase
|
||||
})
|
||||
when Group
|
||||
owner = model.owner
|
||||
|
||||
data.merge!(
|
||||
name: model.name,
|
||||
path: model.path,
|
||||
group_id: model.id,
|
||||
owner_name: owner.respond_to?(:name) ? owner.name : nil,
|
||||
owner_email: owner.respond_to?(:email) ? owner.email : nil,
|
||||
)
|
||||
when GroupMember
|
||||
data.merge!(
|
||||
group_name: model.group.name,
|
||||
group_path: model.group.path,
|
||||
group_id: model.group.id,
|
||||
user_name: model.user.name,
|
||||
user_email: model.user.email,
|
||||
user_id: model.user.id,
|
||||
group_access: model.human_access,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -68,6 +88,9 @@ class SystemHooksService
|
|||
when ProjectMember
|
||||
return "user_add_to_team" if event == :create
|
||||
return "user_remove_from_team" if event == :destroy
|
||||
when GroupMember
|
||||
return 'user_add_to_group' if event == :create
|
||||
return 'user_remove_from_group' if event == :destroy
|
||||
else
|
||||
"#{model.class.name.downcase}_#{event.to_s}"
|
||||
end
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
%span.light.pull-right
|
||||
= Milestone.count
|
||||
%p
|
||||
Active users last 30 days
|
||||
Users who signed in during last 30 days
|
||||
%span.light.pull-right
|
||||
= User.where("current_sign_in_at > ?", 30.days.ago).count
|
||||
.col-md-4
|
||||
|
|
|
@ -11,5 +11,4 @@
|
|||
- elsif event.note?
|
||||
= render "events/event/note", event: event
|
||||
- else
|
||||
= render "events/event/common", event: event
|
||||
|
||||
= render "events/event/common", event: event
|
|
@ -5,7 +5,11 @@
|
|||
|
||||
.form-group
|
||||
= f.label :access_level, "Group Access", class: 'control-label'
|
||||
.col-sm-10= select_tag :access_level, options_for_select(GroupMember.access_level_roles, @users_group.access_level), class: "project-access-select select2"
|
||||
.col-sm-10
|
||||
= select_tag :access_level, options_for_select(GroupMember.access_level_roles, @users_group.access_level), class: "project-access-select select2"
|
||||
.help-block
|
||||
Read more about role permissions
|
||||
%strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink"
|
||||
|
||||
.form-actions
|
||||
= f.submit 'Add users into group', class: "btn btn-create"
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
%ul.sidebar-subnav
|
||||
= nav_link(path: 'groups#edit') do
|
||||
= link_to edit_group_path(@group) do
|
||||
= link_to edit_group_path(@group), title: 'Group' do
|
||||
%i.fa.fa-pencil-square-o
|
||||
%span
|
||||
Group
|
||||
= nav_link(path: 'groups#projects') do
|
||||
= link_to projects_group_path(@group) do
|
||||
= link_to projects_group_path(@group), title: 'Projects' do
|
||||
%i.fa.fa-folder
|
||||
%span
|
||||
Projects
|
||||
|
|
|
@ -43,6 +43,6 @@
|
|||
%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'
|
||||
= image_tag avatar_icon(current_user.email, 60), alt: 'User activity'
|
||||
|
||||
= render 'shared/outdated_browser'
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
- if defined?(sidebar)
|
||||
.page-with-sidebar
|
||||
= render "layouts/broadcast"
|
||||
.sidebar-wrapper
|
||||
= render(sidebar)
|
||||
.content-wrapper
|
||||
|
|
|
@ -2,6 +2,5 @@
|
|||
%html{ lang: "en"}
|
||||
= render "layouts/head", title: "Admin area"
|
||||
%body{class: "#{app_theme} #{theme_type} admin", :'data-page' => body_data_page}
|
||||
= render "layouts/broadcast"
|
||||
= render "layouts/head_panel", title: "Admin area"
|
||||
= render 'layouts/page', sidebar: 'layouts/nav/admin'
|
||||
|
|
|
@ -2,6 +2,5 @@
|
|||
%html{ lang: "en"}
|
||||
= render "layouts/head", title: "Dashboard"
|
||||
%body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page }
|
||||
= render "layouts/broadcast"
|
||||
= render "layouts/head_panel", title: "Dashboard"
|
||||
= render 'layouts/page', sidebar: 'layouts/nav/dashboard'
|
||||
|
|
|
@ -2,6 +2,5 @@
|
|||
%html{ lang: "en"}
|
||||
= render "layouts/head", title: group_head_title
|
||||
%body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
|
||||
= render "layouts/broadcast"
|
||||
= render "layouts/head_panel", title: @group.name
|
||||
= render 'layouts/page', sidebar: 'layouts/nav/group'
|
||||
|
|
|
@ -5,49 +5,50 @@
|
|||
%span
|
||||
Overview
|
||||
= nav_link(controller: :projects) do
|
||||
= link_to admin_projects_path do
|
||||
= link_to admin_projects_path, title: 'Projects' do
|
||||
%i.fa.fa-cube
|
||||
%span
|
||||
Projects
|
||||
= nav_link(controller: :users) do
|
||||
= link_to admin_users_path do
|
||||
= link_to admin_users_path, title: 'Users' do
|
||||
%i.fa.fa-user
|
||||
%span
|
||||
Users
|
||||
= nav_link(controller: :groups) do
|
||||
= link_to admin_groups_path do
|
||||
= link_to admin_groups_path, title: 'Groups' do
|
||||
%i.fa.fa-group
|
||||
%span
|
||||
Groups
|
||||
= nav_link(controller: :logs) do
|
||||
= link_to admin_logs_path do
|
||||
= link_to admin_logs_path, title: 'Logs' do
|
||||
%i.fa.fa-file-text
|
||||
%span
|
||||
Logs
|
||||
= nav_link(controller: :broadcast_messages) do
|
||||
= link_to admin_broadcast_messages_path do
|
||||
= link_to admin_broadcast_messages_path, title: 'Broadcast Messages' do
|
||||
%i.fa.fa-bullhorn
|
||||
%span
|
||||
Messages
|
||||
= nav_link(controller: :hooks) do
|
||||
= link_to admin_hooks_path do
|
||||
= link_to admin_hooks_path, title: 'Hooks' do
|
||||
%i.fa.fa-external-link
|
||||
%span
|
||||
Hooks
|
||||
= nav_link(controller: :background_jobs) do
|
||||
= link_to admin_background_jobs_path do
|
||||
= link_to admin_background_jobs_path, title: 'Background Jobs' do
|
||||
%i.fa.fa-cog
|
||||
%span
|
||||
Background Jobs
|
||||
|
||||
= nav_link(controller: :application_settings) do
|
||||
= link_to admin_application_settings_path do
|
||||
= nav_link(controller: :applications) do
|
||||
= link_to admin_applications_path, title: 'Applications' do
|
||||
%i.fa.fa-cloud
|
||||
%span
|
||||
Applications
|
||||
|
||||
= nav_link(controller: :application_settings, html_options: { class: 'separate-item'}) do
|
||||
= link_to admin_application_settings_path, title: 'Settings' do
|
||||
%i.fa.fa-cogs
|
||||
%span
|
||||
Settings
|
||||
|
||||
= nav_link(controller: :applications) do
|
||||
= link_to admin_applications_path do
|
||||
%i.fa.fa-cloud
|
||||
%span
|
||||
Applications
|
||||
|
|
|
@ -5,24 +5,24 @@
|
|||
%span
|
||||
Activity
|
||||
= nav_link(path: 'dashboard#projects') do
|
||||
= link_to projects_dashboard_path, class: 'shortcuts-projects' do
|
||||
= link_to projects_dashboard_path, title: 'Projects', class: 'shortcuts-projects' do
|
||||
%i.fa.fa-cube
|
||||
%span
|
||||
Projects
|
||||
= nav_link(path: 'dashboard#issues') do
|
||||
= link_to assigned_issues_dashboard_path, class: 'shortcuts-issues' do
|
||||
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'shortcuts-issues' do
|
||||
%i.fa.fa-exclamation-circle
|
||||
%span
|
||||
Issues
|
||||
%span.count= current_user.assigned_issues.opened.count
|
||||
= nav_link(path: 'dashboard#merge_requests') do
|
||||
= link_to assigned_mrs_dashboard_path, class: 'shortcuts-merge_requests' do
|
||||
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'shortcuts-merge_requests' do
|
||||
%i.fa.fa-tasks
|
||||
%span
|
||||
Merge Requests
|
||||
%span.count= current_user.assigned_merge_requests.opened.count
|
||||
= nav_link(controller: :help) do
|
||||
= link_to help_path do
|
||||
= link_to help_path, title: 'Help' do
|
||||
%i.fa.fa-question-circle
|
||||
%span
|
||||
Help
|
||||
|
|
|
@ -6,33 +6,33 @@
|
|||
Activity
|
||||
- if current_user
|
||||
= nav_link(controller: [:group, :milestones]) do
|
||||
= link_to group_milestones_path(@group) do
|
||||
= link_to group_milestones_path(@group), title: 'Milestones' do
|
||||
%i.fa.fa-clock-o
|
||||
%span
|
||||
Milestones
|
||||
= nav_link(path: 'groups#issues') do
|
||||
= link_to issues_group_path(@group) do
|
||||
= link_to issues_group_path(@group), title: 'Issues' do
|
||||
%i.fa.fa-exclamation-circle
|
||||
%span
|
||||
Issues
|
||||
- if current_user
|
||||
%span.count= Issue.opened.of_group(@group).count
|
||||
= nav_link(path: 'groups#merge_requests') do
|
||||
= link_to merge_requests_group_path(@group) do
|
||||
= link_to merge_requests_group_path(@group), title: 'Merge Requests' do
|
||||
%i.fa.fa-tasks
|
||||
%span
|
||||
Merge Requests
|
||||
- if current_user
|
||||
%span.count= MergeRequest.opened.of_group(@group).count
|
||||
= nav_link(path: 'groups#members') do
|
||||
= link_to members_group_path(@group) do
|
||||
= link_to members_group_path(@group), title: 'Members' do
|
||||
%i.fa.fa-users
|
||||
%span
|
||||
Members
|
||||
|
||||
- if can?(current_user, :manage_group, @group)
|
||||
= nav_link(html_options: { class: "#{"active" if group_settings_page?} separate-item" }) do
|
||||
= link_to edit_group_path(@group), class: "tab no-highlight" do
|
||||
= link_to edit_group_path(@group), title: 'Settings', class: "tab no-highlight" do
|
||||
%i.fa.fa-cogs
|
||||
%span
|
||||
Settings
|
||||
|
|
|
@ -5,52 +5,51 @@
|
|||
%span
|
||||
Profile
|
||||
= nav_link(controller: :accounts) do
|
||||
= link_to profile_account_path do
|
||||
= link_to profile_account_path, title: 'Account' do
|
||||
%i.fa.fa-gear
|
||||
%span
|
||||
Account
|
||||
= nav_link(path: ['profiles#applications', 'applications#edit', 'applications#show', 'applications#new']) do
|
||||
= link_to applications_profile_path do
|
||||
= link_to applications_profile_path, title: 'Applications' do
|
||||
%i.fa.fa-cloud
|
||||
%span
|
||||
Applications
|
||||
= nav_link(controller: :emails) do
|
||||
= link_to profile_emails_path do
|
||||
= link_to profile_emails_path, title: 'Emails' do
|
||||
%i.fa.fa-envelope-o
|
||||
%span
|
||||
Emails
|
||||
%span.count= current_user.emails.count + 1
|
||||
- unless current_user.ldap_user?
|
||||
= nav_link(controller: :passwords) do
|
||||
= link_to edit_profile_password_path do
|
||||
= link_to edit_profile_password_path, title: 'Password' do
|
||||
%i.fa.fa-lock
|
||||
%span
|
||||
Password
|
||||
= nav_link(controller: :notifications) do
|
||||
= link_to profile_notifications_path do
|
||||
= link_to profile_notifications_path, title: 'Notifications' do
|
||||
%i.fa.fa-inbox
|
||||
%span
|
||||
Notifications
|
||||
|
||||
= nav_link(controller: :keys) do
|
||||
= link_to profile_keys_path do
|
||||
= link_to profile_keys_path, title: 'SSH Keys' do
|
||||
%i.fa.fa-key
|
||||
%span
|
||||
SSH Keys
|
||||
%span.count= current_user.keys.count
|
||||
= nav_link(path: 'profiles#design') do
|
||||
= link_to design_profile_path do
|
||||
= link_to design_profile_path, title: 'Design' do
|
||||
%i.fa.fa-image
|
||||
%span
|
||||
Design
|
||||
= nav_link(controller: :groups) do
|
||||
= link_to profile_groups_path do
|
||||
= link_to profile_groups_path, title: 'Groups' do
|
||||
%i.fa.fa-group
|
||||
%span
|
||||
Groups
|
||||
= nav_link(path: 'profiles#history') do
|
||||
= link_to history_profile_path do
|
||||
= link_to history_profile_path, title: 'History' do
|
||||
%i.fa.fa-history
|
||||
%span
|
||||
History
|
||||
|
||||
|
|
|
@ -6,45 +6,44 @@
|
|||
Project
|
||||
- if project_nav_tab? :files
|
||||
= nav_link(controller: %w(tree blob blame edit_tree new_tree)) do
|
||||
= link_to project_tree_path(@project, @ref || @repository.root_ref), class: 'shortcuts-tree' do
|
||||
= link_to project_tree_path(@project, @ref || @repository.root_ref), title: 'Files', class: 'shortcuts-tree' do
|
||||
%i.fa.fa-files-o
|
||||
%span
|
||||
Files
|
||||
|
||||
|
||||
- if project_nav_tab? :commits
|
||||
= nav_link(controller: %w(commit commits compare repositories tags branches)) do
|
||||
= link_to project_commits_path(@project, @ref || @repository.root_ref), class: 'shortcuts-commits' do
|
||||
= link_to project_commits_path(@project, @ref || @repository.root_ref), title: 'Commits', class: 'shortcuts-commits' do
|
||||
%i.fa.fa-history
|
||||
%span
|
||||
Commits
|
||||
|
||||
- if project_nav_tab? :network
|
||||
= nav_link(controller: %w(network)) do
|
||||
= link_to project_network_path(@project, @ref || @repository.root_ref), class: 'shortcuts-network' do
|
||||
= link_to project_network_path(@project, @ref || @repository.root_ref), title: 'Network', class: 'shortcuts-network' do
|
||||
%i.fa.fa-code-fork
|
||||
%span
|
||||
Network
|
||||
|
||||
- if project_nav_tab? :graphs
|
||||
= nav_link(controller: %w(graphs)) do
|
||||
= link_to project_graph_path(@project, @ref || @repository.root_ref), class: 'shortcuts-graphs' do
|
||||
= link_to project_graph_path(@project, @ref || @repository.root_ref), title: 'Graphs', class: 'shortcuts-graphs' do
|
||||
%i.fa.fa-area-chart
|
||||
%span
|
||||
Graphs
|
||||
|
||||
- if project_nav_tab? :issues
|
||||
= nav_link(controller: %w(issues milestones labels)) do
|
||||
= link_to url_for_project_issues, class: 'shortcuts-issues' do
|
||||
= link_to url_for_project_issues, title: 'Issues', class: 'shortcuts-issues' do
|
||||
%i.fa.fa-exclamation-circle
|
||||
%span
|
||||
Issues
|
||||
- if @project.used_default_issues_tracker?
|
||||
- if @project.default_issues_tracker?
|
||||
%span.count.issue_counter= @project.issues.opened.count
|
||||
|
||||
- if project_nav_tab? :merge_requests
|
||||
= nav_link(controller: :merge_requests) do
|
||||
= link_to project_merge_requests_path(@project), class: 'shortcuts-merge_requests' do
|
||||
= link_to project_merge_requests_path(@project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do
|
||||
%i.fa.fa-tasks
|
||||
%span
|
||||
Merge Requests
|
||||
|
@ -52,21 +51,21 @@
|
|||
|
||||
- if project_nav_tab? :wiki
|
||||
= nav_link(controller: :wikis) do
|
||||
= link_to project_wiki_path(@project, :home), class: 'shortcuts-wiki' do
|
||||
= link_to project_wiki_path(@project, :home), title: 'Wiki', class: 'shortcuts-wiki' do
|
||||
%i.fa.fa-book
|
||||
%span
|
||||
Wiki
|
||||
|
||||
- if project_nav_tab? :snippets
|
||||
= nav_link(controller: :snippets) do
|
||||
= link_to project_snippets_path(@project), class: 'shortcuts-snippets' do
|
||||
= link_to project_snippets_path(@project), title: 'Snippets', class: 'shortcuts-snippets' do
|
||||
%i.fa.fa-file-text-o
|
||||
%span
|
||||
Snippets
|
||||
|
||||
- if project_nav_tab? :settings
|
||||
= nav_link(html_options: {class: "#{project_tab_class} separate-item"}) do
|
||||
= link_to edit_project_path(@project), class: "stat-tab tab no-highlight" do
|
||||
= link_to edit_project_path(@project), title: 'Settings', class: "stat-tab tab no-highlight" do
|
||||
%i.fa.fa-cogs
|
||||
%span
|
||||
Settings
|
||||
|
|
|
@ -2,6 +2,5 @@
|
|||
%html{ lang: "en"}
|
||||
= render "layouts/head", title: "Profile"
|
||||
%body{class: "#{app_theme} #{theme_type} profile", :'data-page' => body_data_page}
|
||||
= render "layouts/broadcast"
|
||||
= render "layouts/head_panel", title: "Profile"
|
||||
= render 'layouts/page', sidebar: 'layouts/nav/profile'
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
%html{ lang: "en"}
|
||||
= render "layouts/head", title: @project.name_with_namespace
|
||||
%body{class: "#{app_theme} #{theme_type} project", :'data-page' => body_data_page, :'data-project-id' => @project.id }
|
||||
= render "layouts/broadcast"
|
||||
= render "layouts/head_panel", title: project_title(@project)
|
||||
= render "layouts/init_auto_complete"
|
||||
- @project_settings_nav = true
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
%html{ lang: "en"}
|
||||
= render "layouts/head", title: project_head_title
|
||||
%body{class: "#{app_theme} #{theme_type} project", :'data-page' => body_data_page, :'data-project-id' => @project.id }
|
||||
= render "layouts/broadcast"
|
||||
= render "layouts/head_panel", title: project_title(@project)
|
||||
= render "layouts/init_auto_complete"
|
||||
= render 'layouts/page', sidebar: 'layouts/nav/project'
|
||||
|
|
|
@ -2,6 +2,5 @@
|
|||
%html{ lang: "en"}
|
||||
= render "layouts/head", title: group_head_title
|
||||
%body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
|
||||
= render "layouts/broadcast"
|
||||
= render "layouts/public_head_panel", title: "group: #{@group.name}"
|
||||
= render 'layouts/page', sidebar: 'layouts/nav/group'
|
||||
|
|
|
@ -2,6 +2,5 @@
|
|||
%html{ lang: "en"}
|
||||
= render "layouts/head", title: @project.name_with_namespace
|
||||
%body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
|
||||
= render "layouts/broadcast"
|
||||
= render "layouts/public_head_panel", title: project_title(@project)
|
||||
= render 'layouts/page', sidebar: 'layouts/nav/project'
|
||||
|
|
|
@ -2,6 +2,5 @@
|
|||
%html{ lang: "en"}
|
||||
= render "layouts/head", title: @title
|
||||
%body{class: "#{app_theme} #{theme_type} application", :'data-page' => body_data_page}
|
||||
= render "layouts/broadcast"
|
||||
= render "layouts/public_head_panel", title: @title
|
||||
= render 'layouts/page'
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
.file-holder.file
|
||||
.file-title
|
||||
%i.icon-file
|
||||
%span.file_name
|
||||
%span.monospace.light #{ref}
|
||||
- if local_assigns[:path]
|
||||
= ': ' + local_assigns[:path]
|
||||
.file-content.code
|
||||
%pre.js-edit-mode-pane#editor
|
||||
= params[:content] || local_assigns[:blob_data]
|
||||
- if local_assigns[:path]
|
||||
.js-edit-mode-pane#preview.hide
|
||||
.center
|
||||
%h2
|
||||
%i.icon-spinner.icon-spin
|
|
@ -1,8 +1,9 @@
|
|||
- empty_repo = @project.empty_repo?
|
||||
.project-home-panel{:class => ("empty-project" if empty_repo)}
|
||||
.project-identicon-holder
|
||||
= project_icon(@project.to_param, alt: '', class: 'avatar')
|
||||
.project-home-row
|
||||
.project-home-desc
|
||||
= project_icon(@project.to_param, alt: '', class: 'avatar s32')
|
||||
- if @project.description.present?
|
||||
= escaped_autolink(@project.description)
|
||||
- if can?(current_user, :admin_project, @project)
|
||||
|
|
|
@ -1,31 +1,31 @@
|
|||
%ul.project-settings-nav.sidebar-subnav
|
||||
= nav_link(path: 'projects#edit') do
|
||||
= link_to edit_project_path(@project), class: "stat-tab tab " do
|
||||
= link_to edit_project_path(@project), title: 'Project', class: "stat-tab tab " do
|
||||
%i.fa.fa-pencil-square-o
|
||||
%span
|
||||
Project
|
||||
= nav_link(controller: [:team_members, :teams]) do
|
||||
= link_to project_team_index_path(@project), class: "team-tab tab" do
|
||||
= link_to project_team_index_path(@project), title: 'Members', class: "team-tab tab" do
|
||||
%i.fa.fa-users
|
||||
%span
|
||||
Members
|
||||
= nav_link(controller: :deploy_keys) do
|
||||
= link_to project_deploy_keys_path(@project) do
|
||||
= link_to project_deploy_keys_path(@project), title: 'Deploy Keys' do
|
||||
%i.fa.fa-key
|
||||
%span
|
||||
Deploy Keys
|
||||
= nav_link(controller: :hooks) do
|
||||
= link_to project_hooks_path(@project) do
|
||||
= link_to project_hooks_path(@project), title: 'Web Hooks' do
|
||||
%i.fa.fa-link
|
||||
%span
|
||||
Web Hooks
|
||||
= nav_link(controller: :services) do
|
||||
= link_to project_services_path(@project) do
|
||||
= link_to project_services_path(@project), title: 'Services' do
|
||||
%i.fa.fa-cogs
|
||||
%span
|
||||
Services
|
||||
= nav_link(controller: :protected_branches) do
|
||||
= link_to project_protected_branches_path(@project) do
|
||||
= link_to project_protected_branches_path(@project), title: 'Protected Branches' do
|
||||
%i.fa.fa-lock
|
||||
%span
|
||||
Protected branches
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
.file-holder.file
|
||||
.file-title
|
||||
.editor-ref
|
||||
%i.fa.fa-code-fork
|
||||
= ref
|
||||
%span.editor-file-name
|
||||
- if @path
|
||||
%span.monospace
|
||||
= @path
|
||||
|
||||
- if current_action?(:new) || current_action?(:create)
|
||||
\/
|
||||
= text_field_tag 'file_name', params[:file_name], placeholder: "File name",
|
||||
required: true, class: 'form-control new-file-name'
|
||||
.pull-right
|
||||
= select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'form-control'
|
||||
|
||||
.file-content.code
|
||||
%pre.js-edit-mode-pane#editor
|
||||
= params[:content] || local_assigns[:blob_data]
|
||||
- if local_assigns[:path]
|
||||
.js-edit-mode-pane#preview.hide
|
||||
.center
|
||||
%h2
|
||||
%i.icon-spinner.icon-spin
|
|
@ -0,0 +1,24 @@
|
|||
.file-editor
|
||||
%ul.nav.nav-tabs.js-edit-mode
|
||||
%li.active
|
||||
= link_to '#editor' do
|
||||
%i.fa.fa-edit
|
||||
Edit file
|
||||
|
||||
%li
|
||||
= link_to '#preview', 'data-preview-url' => project_preview_blob_path(@project, @id) do
|
||||
%i.fa.fa-eye
|
||||
= editing_preview_title(@blob.name)
|
||||
|
||||
= form_tag(project_update_blob_path(@project, @id), method: :put, class: "form-horizontal") do
|
||||
= render 'projects/blob/editor', ref: @ref, path: @path, blob_data: @blob.data
|
||||
= render 'shared/commit_message_container', params: params,
|
||||
placeholder: "Update #{@blob.name}"
|
||||
= hidden_field_tag 'last_commit', @last_commit
|
||||
= hidden_field_tag 'content', '', id: "file-content"
|
||||
= hidden_field_tag 'from_merge_request_id', params[:from_merge_request_id]
|
||||
= render 'projects/commit_button', ref: @ref,
|
||||
cancel_path: @after_edit_path
|
||||
|
||||
:javascript
|
||||
blob = new EditBlob(gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}", "#{@blob.language.try(:ace_mode)}")
|
|
@ -0,0 +1,12 @@
|
|||
%h3.page-title New file
|
||||
.file-editor
|
||||
= form_tag(project_create_blob_path(@project, @id), method: :post, class: 'form-horizontal form-new-file') do
|
||||
= render 'projects/blob/editor', ref: @ref
|
||||
= render 'shared/commit_message_container', params: params,
|
||||
placeholder: 'Add new file'
|
||||
= hidden_field_tag 'content', '', id: 'file-content'
|
||||
= render 'projects/commit_button', ref: @ref,
|
||||
cancel_path: project_tree_path(@project, @id)
|
||||
|
||||
:javascript
|
||||
blob = new NewBlob(gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}", null)
|
|
@ -51,15 +51,6 @@
|
|||
= f.check_box :issues_enabled
|
||||
%span.descr Lightweight issue tracking system for this project
|
||||
|
||||
- if Project.issues_tracker.values.count > 1
|
||||
.form-group
|
||||
= f.label :issues_tracker, "Issues tracker", class: 'control-label'
|
||||
.col-sm-10= f.select(:issues_tracker, project_issues_trackers(@project.issues_tracker), {}, { disabled: !@project.issues_enabled })
|
||||
|
||||
.form-group
|
||||
= f.label :issues_tracker_id, "Project name or id in issues tracker", class: 'control-label'
|
||||
.col-sm-10= f.text_field :issues_tracker_id, disabled: !@project.can_have_issues_tracker_id?, class: 'form-control'
|
||||
|
||||
.form-group
|
||||
= f.label :merge_requests_enabled, "Merge Requests", class: 'control-label'
|
||||
.col-sm-10
|
||||
|
@ -89,8 +80,6 @@
|
|||
.col-sm-10
|
||||
- if @project.avatar?
|
||||
= project_icon(@project.to_param, alt: '', class: 'avatar s160')
|
||||
- else
|
||||
= project_icon(@project.to_param, alt: '', class: 'avatar s160', only_uploaded: true)
|
||||
%p.light
|
||||
- if @project.avatar_in_git
|
||||
Project avatar in repository: #{ @project.avatar_in_git }
|
||||
|
|
|
@ -1,57 +0,0 @@
|
|||
.file-editor
|
||||
%ul.nav.nav-tabs.js-edit-mode
|
||||
%li.active
|
||||
= link_to 'Edit', '#editor'
|
||||
%li
|
||||
= link_to editing_preview_title(@blob.name), '#preview', 'data-preview-url' => preview_project_edit_tree_path(@project, @id)
|
||||
|
||||
= form_tag(project_edit_tree_path(@project, @id), method: :put, class: "form-horizontal") do
|
||||
= render 'projects/blob_editor', ref: @ref, path: @path, blob_data: @blob.data
|
||||
= render 'shared/commit_message_container', params: params,
|
||||
placeholder: "Update #{@blob.name}"
|
||||
= hidden_field_tag 'last_commit', @last_commit
|
||||
= hidden_field_tag 'content', '', id: "file-content"
|
||||
= hidden_field_tag 'from_merge_request_id', params[:from_merge_request_id]
|
||||
= render 'projects/commit_button', ref: @ref,
|
||||
cancel_path: @after_edit_path
|
||||
|
||||
:javascript
|
||||
ace.config.set("modePath", gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}/ace")
|
||||
ace.config.loadModule("ace/ext/searchbox");
|
||||
var ace_mode = "#{@blob.language.try(:ace_mode)}";
|
||||
var editor = ace.edit("editor");
|
||||
if (ace_mode) {
|
||||
editor.getSession().setMode('ace/mode/' + ace_mode);
|
||||
}
|
||||
|
||||
disableButtonIfEmptyField("#commit_message", ".js-commit-button");
|
||||
|
||||
$(".js-commit-button").click(function(){
|
||||
$("#file-content").val(editor.getValue());
|
||||
$(".file-editor form").submit();
|
||||
});
|
||||
|
||||
var editModePanes = $('.js-edit-mode-pane'),
|
||||
editModeLinks = $('.js-edit-mode a');
|
||||
|
||||
editModeLinks.click(function(event) {
|
||||
event.preventDefault();
|
||||
|
||||
var currentLink = $(this),
|
||||
paneId = currentLink.attr('href'),
|
||||
currentPane = editModePanes.filter(paneId);
|
||||
|
||||
editModeLinks.parent().removeClass('active hover');
|
||||
currentLink.parent().addClass('active hover');
|
||||
editModePanes.hide();
|
||||
|
||||
if (paneId == '#preview') {
|
||||
currentPane.fadeIn(200);
|
||||
$.post(currentLink.data('preview-url'), { content: editor.getValue() }, function(response) {
|
||||
currentPane.empty().append(response);
|
||||
})
|
||||
} else {
|
||||
currentPane.fadeIn(200);
|
||||
editor.focus()
|
||||
}
|
||||
})
|
|
@ -3,6 +3,17 @@
|
|||
|
||||
= render "home_panel"
|
||||
|
||||
.center.well
|
||||
%h3
|
||||
The repository for this project is empty
|
||||
%h4
|
||||
You can
|
||||
= link_to project_new_blob_path(@project, 'master'), class: 'btn btn-new btn-lg' do
|
||||
add a file
|
||||
or push it via command line.
|
||||
|
||||
%h4
|
||||
%strong Command line instructions
|
||||
%div.git-empty
|
||||
%fieldset
|
||||
%legend Git global setup
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
%h3.page-title Fork project
|
||||
%p.lead Select namespace where to fork this project
|
||||
%p.lead
|
||||
Click to fork the project to a user or group
|
||||
%hr
|
||||
|
||||
.fork-namespaces
|
||||
|
|
|
@ -45,10 +45,17 @@
|
|||
.automerge_widget.cannot_be_merged.hide
|
||||
%h4
|
||||
This request can't be merged with GitLab.
|
||||
%p
|
||||
You should do it manually with
|
||||
%strong
|
||||
= link_to "command line", "#modal_merge_info", class: "how_to_merge_link", title: "How To Merge", "data-toggle" => "modal"
|
||||
= link_to "#modal_merge_info", class: "underlined-link how_to_merge_link", title: "How To Merge", "data-toggle" => "modal" do
|
||||
command line
|
||||
|
||||
%p
|
||||
%button.btn.disabled
|
||||
%i.fa.fa-warning
|
||||
Accept Merge Request
|
||||
|
||||
This usually happens when git can not resolve conflicts between branches automatically.
|
||||
|
||||
.automerge_widget.unchecked
|
||||
%p
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
%h3.page-title New file
|
||||
%hr
|
||||
.file-editor
|
||||
= form_tag(project_new_tree_path(@project, @id), method: :put, class: 'form-horizontal form-new-file') do
|
||||
.form-group.commit_message-group
|
||||
= label_tag 'file_name', class: 'control-label' do
|
||||
File name
|
||||
.col-sm-10
|
||||
.input-group
|
||||
%span.input-group-addon
|
||||
= @path[-1] == "/" ? @path : @path + "/"
|
||||
= text_field_tag 'file_name', params[:file_name], placeholder: "sample.rb", required: true, class: 'form-control'
|
||||
%span.input-group-addon
|
||||
on
|
||||
%span= @ref
|
||||
|
||||
.form-group.commit_message-group
|
||||
= label_tag :encoding, class: "control-label" do
|
||||
Encoding
|
||||
.col-sm-10
|
||||
= select_tag :encoding, options_for_select([ "base64", "text" ], "text"), class: 'form-control'
|
||||
= render 'projects/blob_editor', ref: @ref
|
||||
= render 'shared/commit_message_container', params: params,
|
||||
placeholder: 'Add new file'
|
||||
= hidden_field_tag 'content', '', id: 'file-content'
|
||||
= render 'projects/commit_button', ref: @ref,
|
||||
cancel_path: project_tree_path(@project, @id)
|
||||
|
||||
:javascript
|
||||
ace.config.set("modePath", gon.relative_url_root + "#{Gitlab::Application.config.assets.prefix}/ace-src-noconflict")
|
||||
var editor = ace.edit("editor");
|
||||
|
||||
disableButtonIfAnyEmptyField($('.form-new-file'), '.form-control', '.btn-create')
|
||||
|
||||
$(".js-commit-button").click(function(){
|
||||
$("#file-content").val(editor.getValue());
|
||||
$(".file-editor form").submit();
|
||||
});
|
|
@ -17,7 +17,12 @@
|
|||
%p 2. Set access level for them
|
||||
.form-group
|
||||
= f.label :access_level, "Project Access", class: 'control-label'
|
||||
.col-sm-10= select_tag :access_level, options_for_select(Gitlab::Access.options, @user_project_relation.access_level), class: "project-access-select select2"
|
||||
.col-sm-10
|
||||
= select_tag :access_level, options_for_select(Gitlab::Access.options, @user_project_relation.access_level), class: "project-access-select select2"
|
||||
.help-block
|
||||
Read more about role permissions
|
||||
%strong= link_to "here", help_page_path("permissions", "permissions"), class: "vlink"
|
||||
|
||||
|
||||
.form-actions
|
||||
= f.submit 'Add users', class: "btn btn-create"
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
= link_to title, '#'
|
||||
- if current_user && can_push_branch?(@project, @ref)
|
||||
%li
|
||||
= link_to project_new_tree_path(@project, @id), title: 'New file', id: 'new-file-link' do
|
||||
= link_to project_new_blob_path(@project, @id), title: 'New file', id: 'new-file-link' do
|
||||
%small
|
||||
%i.fa.fa-plus
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
%h4 Calendar:
|
||||
#cal-heatmap.calendar
|
||||
:javascript
|
||||
new calendar(
|
||||
#{@timestamps.to_json},
|
||||
#{@starting_year},
|
||||
#{@starting_month}
|
||||
);
|
|
@ -18,6 +18,11 @@
|
|||
%h4 Groups:
|
||||
= render 'groups', groups: @groups
|
||||
%hr
|
||||
|
||||
.user-calendar
|
||||
%h4.center.light
|
||||
%i.fa.fa-spinner.fa-spin
|
||||
%hr
|
||||
%h4
|
||||
User Activity:
|
||||
|
||||
|
@ -32,3 +37,8 @@
|
|||
= render 'profile', user: @user
|
||||
- if @projects.present?
|
||||
= render 'projects', projects: @projects
|
||||
|
||||
|
||||
:coffeescript
|
||||
$ ->
|
||||
$(".user-calendar").load("#{user_calendar_path}")
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue