Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce into sidebar-expand-collapse
This commit is contained in:
commit
272d482f17
69 changed files with 890 additions and 450 deletions
|
@ -1,7 +1,10 @@
|
|||
Please view this file on the master branch, on stable branches it's out of date.
|
||||
|
||||
v 8.9.0 (unreleased)
|
||||
- Allow forking projects with restricted visibility level
|
||||
- Redesign navigation for project pages
|
||||
- Fix groups API to list only user's accessible projects
|
||||
- Redesign account and email confirmation emails
|
||||
- Use gitlab-shell v3.0.0
|
||||
- Add rake task 'gitlab:db:configure' for conditionally seeding or migrating the database
|
||||
- Changed the Slack build message to use the singular duration if necessary (Aran Koning)
|
||||
|
@ -38,6 +41,7 @@ v 8.8.0
|
|||
- Added inline diff styling for `change_title` system notes. (Adam Butler)
|
||||
- Project#open_branches has been cleaned up and no longer loads entire records into memory.
|
||||
- Escape HTML in commit titles in system note messages
|
||||
- Improve design of Pipeline View
|
||||
- Fix scope used when accessing container registry
|
||||
- Fix creation of Ci::Commit object which can lead to pending, failed in some scenarios
|
||||
- Improve multiple branch push performance by memoizing permission checking
|
||||
|
@ -99,6 +103,9 @@ v 8.8.0
|
|||
- Allows MR authors to have the source branch removed when merging the MR. !2801 (Jeroen Jacobs)
|
||||
- When creating a .gitignore file a dropdown with templates will be provided
|
||||
|
||||
v 8.7.7
|
||||
- Fix import by `Any Git URL` broken if the URL contains a space
|
||||
|
||||
v 8.7.6
|
||||
- Fix links on wiki pages for relative url setups. !4131 (Artem Sidorenko)
|
||||
- Fix import from GitLab.com to a private instance failure. !4181
|
||||
|
|
5
Gemfile
5
Gemfile
|
@ -121,7 +121,7 @@ group :unicorn do
|
|||
end
|
||||
|
||||
# State machine
|
||||
gem "state_machines-activerecord", '~> 0.3.0'
|
||||
gem "state_machines-activerecord", '~> 0.4.0'
|
||||
# Run events after state machine commits
|
||||
gem 'after_commit_queue'
|
||||
|
||||
|
@ -178,9 +178,6 @@ gem 'ruby-fogbugz', '~> 0.2.1'
|
|||
# d3
|
||||
gem 'd3_rails', '~> 3.5.0'
|
||||
|
||||
#cal-heatmap
|
||||
gem 'cal-heatmap-rails', '~> 3.6.0'
|
||||
|
||||
# underscore-rails
|
||||
gem "underscore-rails", "~> 1.8.0"
|
||||
|
||||
|
|
12
Gemfile.lock
12
Gemfile.lock
|
@ -102,7 +102,6 @@ GEM
|
|||
bundler (~> 1.2)
|
||||
thor (~> 0.18)
|
||||
byebug (8.2.1)
|
||||
cal-heatmap-rails (3.6.0)
|
||||
capybara (2.6.2)
|
||||
addressable
|
||||
mime-types (>= 1.16)
|
||||
|
@ -790,11 +789,11 @@ GEM
|
|||
activesupport (>= 4.0)
|
||||
sprockets (>= 3.0.0)
|
||||
state_machines (0.4.0)
|
||||
state_machines-activemodel (0.3.0)
|
||||
activemodel (~> 4.1)
|
||||
state_machines-activemodel (0.4.0)
|
||||
activemodel (>= 4.1, < 5.1)
|
||||
state_machines (>= 0.4.0)
|
||||
state_machines-activerecord (0.3.0)
|
||||
activerecord (~> 4.1)
|
||||
state_machines-activerecord (0.4.0)
|
||||
activerecord (>= 4.1, < 5.1)
|
||||
state_machines-activemodel (>= 0.3.0)
|
||||
stringex (2.5.2)
|
||||
systemu (2.6.5)
|
||||
|
@ -908,7 +907,6 @@ DEPENDENCIES
|
|||
bullet
|
||||
bundler-audit
|
||||
byebug
|
||||
cal-heatmap-rails (~> 3.6.0)
|
||||
capybara (~> 2.6.2)
|
||||
capybara-screenshot (~> 1.0.0)
|
||||
carrierwave (~> 0.10.0)
|
||||
|
@ -1043,7 +1041,7 @@ DEPENDENCIES
|
|||
spring-commands-spinach (~> 1.1.0)
|
||||
spring-commands-teaspoon (~> 0.0.2)
|
||||
sprockets (~> 3.6.0)
|
||||
state_machines-activerecord (~> 0.3.0)
|
||||
state_machines-activerecord (~> 0.4.0)
|
||||
task_list (~> 1.0.2)
|
||||
teaspoon (~> 1.1.0)
|
||||
teaspoon-jasmine (~> 2.2.0)
|
||||
|
|
BIN
app/assets/images/mailers/gitlab_header_logo.png
Normal file
BIN
app/assets/images/mailers/gitlab_header_logo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.9 KiB |
BIN
app/assets/images/mailers/gitlab_tanuki_2x.png
Normal file
BIN
app/assets/images/mailers/gitlab_tanuki_2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
|
@ -19,7 +19,6 @@
|
|||
#= require jquery.scrollTo
|
||||
#= require jquery.turbolinks
|
||||
#= require d3
|
||||
#= require cal-heatmap
|
||||
#= require turbolinks
|
||||
#= require autosave
|
||||
#= require bootstrap/affix
|
||||
|
|
|
@ -1,34 +1,198 @@
|
|||
class @Calendar
|
||||
constructor: (timestamps, starting_year, starting_month, calendar_activities_path) ->
|
||||
cal = new CalHeatMap()
|
||||
cal.init
|
||||
itemName: ["contribution"]
|
||||
data: timestamps
|
||||
start: new Date(starting_year, starting_month)
|
||||
domainLabelFormat: "%b"
|
||||
id: "cal-heatmap"
|
||||
domain: "month"
|
||||
subDomain: "day"
|
||||
range: 12
|
||||
tooltip: true
|
||||
label:
|
||||
position: "top"
|
||||
legend: [
|
||||
0
|
||||
10
|
||||
20
|
||||
30
|
||||
]
|
||||
legendCellPadding: 3
|
||||
cellSize: $('.user-calendar').width() / 73
|
||||
onClick: (date, count) ->
|
||||
formated_date = date.getFullYear() + "-" + (date.getMonth()+1) + "-" + date.getDate()
|
||||
$.ajax
|
||||
url: calendar_activities_path
|
||||
data:
|
||||
date: formated_date
|
||||
cache: false
|
||||
dataType: "html"
|
||||
success: (data) ->
|
||||
$(".user-calendar-activities").html data
|
||||
constructor: (timestamps, @calendar_activities_path) ->
|
||||
@currentSelectedDate = ''
|
||||
@daySpace = 1
|
||||
@daySize = 15
|
||||
@daySizeWithSpace = @daySize + (@daySpace * 2)
|
||||
@monthNames = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
|
||||
@months = []
|
||||
@highestValue = 0
|
||||
|
||||
# Get the highest value from the timestampes
|
||||
_.each timestamps, (count) =>
|
||||
if count > @highestValue
|
||||
@highestValue = count
|
||||
|
||||
# Loop through the timestamps to create a group of objects
|
||||
# The group of objects will be grouped based on the day of the week they are
|
||||
@timestampsTmp = []
|
||||
i = 0
|
||||
group = 0
|
||||
_.each timestamps, (count, date) =>
|
||||
newDate = new Date parseInt(date) * 1000
|
||||
day = newDate.getDay()
|
||||
|
||||
# Create a new group array if this is the first day of the week
|
||||
# or if is first object
|
||||
if (day is 0 and i isnt 0) or i is 0
|
||||
@timestampsTmp.push []
|
||||
group++
|
||||
|
||||
innerArray = @timestampsTmp[group-1]
|
||||
|
||||
# Push to the inner array the values that will be used to render map
|
||||
innerArray.push
|
||||
count: count
|
||||
date: newDate
|
||||
day: day
|
||||
|
||||
i++
|
||||
|
||||
# Init color functions
|
||||
@color = @initColor()
|
||||
@colorKey = @initColorKey()
|
||||
|
||||
# Init the svg element
|
||||
@renderSvg(group)
|
||||
@renderDays()
|
||||
@renderMonths()
|
||||
@renderDayTitles()
|
||||
@renderKey()
|
||||
|
||||
@initTooltips()
|
||||
|
||||
renderSvg: (group) ->
|
||||
@svg = d3.select '.js-contrib-calendar'
|
||||
.append 'svg'
|
||||
.attr 'width', (group + 1) * @daySizeWithSpace
|
||||
.attr 'height', 167
|
||||
.attr 'class', 'contrib-calendar'
|
||||
|
||||
renderDays: ->
|
||||
@svg.selectAll 'g'
|
||||
.data @timestampsTmp
|
||||
.enter()
|
||||
.append 'g'
|
||||
.attr 'transform', (group, i) =>
|
||||
_.each group, (stamp, a) =>
|
||||
if a is 0 and stamp.day is 0
|
||||
month = stamp.date.getMonth()
|
||||
x = (@daySizeWithSpace * i + 1) + @daySizeWithSpace
|
||||
lastMonth = _.last(@months)
|
||||
if lastMonth?
|
||||
lastMonthX = lastMonth.x
|
||||
|
||||
if !lastMonth?
|
||||
@months.push
|
||||
month: month
|
||||
x: x
|
||||
else if month isnt lastMonth.month and x - @daySizeWithSpace isnt lastMonthX
|
||||
@months.push
|
||||
month: month
|
||||
x: x
|
||||
|
||||
"translate(#{(@daySizeWithSpace * i + 1) + @daySizeWithSpace}, 18)"
|
||||
.selectAll 'rect'
|
||||
.data (stamp) ->
|
||||
stamp
|
||||
.enter()
|
||||
.append 'rect'
|
||||
.attr 'x', '0'
|
||||
.attr 'y', (stamp, i) =>
|
||||
(@daySizeWithSpace * stamp.day)
|
||||
.attr 'width', @daySize
|
||||
.attr 'height', @daySize
|
||||
.attr 'title', (stamp) =>
|
||||
contribText = 'No contributions'
|
||||
|
||||
if stamp.count > 0
|
||||
contribText = "#{stamp.count} contribution#{if stamp.count > 1 then 's' else ''}"
|
||||
|
||||
date = dateFormat(stamp.date, 'mmm d, yyyy')
|
||||
|
||||
"#{contribText}<br />#{date}"
|
||||
.attr 'class', 'user-contrib-cell js-tooltip'
|
||||
.attr 'fill', (stamp) =>
|
||||
if stamp.count isnt 0
|
||||
@color(stamp.count)
|
||||
else
|
||||
'#ededed'
|
||||
.attr 'data-container', 'body'
|
||||
.on 'click', @clickDay
|
||||
|
||||
renderDayTitles: ->
|
||||
days = [{
|
||||
text: 'M'
|
||||
y: 29 + (@daySizeWithSpace * 1)
|
||||
}, {
|
||||
text: 'W'
|
||||
y: 29 + (@daySizeWithSpace * 3)
|
||||
}, {
|
||||
text: 'F'
|
||||
y: 29 + (@daySizeWithSpace * 5)
|
||||
}]
|
||||
@svg.append 'g'
|
||||
.selectAll 'text'
|
||||
.data days
|
||||
.enter()
|
||||
.append 'text'
|
||||
.attr 'text-anchor', 'middle'
|
||||
.attr 'x', 8
|
||||
.attr 'y', (day) ->
|
||||
day.y
|
||||
.text (day) ->
|
||||
day.text
|
||||
.attr 'class', 'user-contrib-text'
|
||||
|
||||
renderMonths: ->
|
||||
@svg.append 'g'
|
||||
.selectAll 'text'
|
||||
.data @months
|
||||
.enter()
|
||||
.append 'text'
|
||||
.attr 'x', (date) ->
|
||||
date.x
|
||||
.attr 'y', 10
|
||||
.attr 'class', 'user-contrib-text'
|
||||
.text (date) =>
|
||||
@monthNames[date.month]
|
||||
|
||||
renderKey: ->
|
||||
keyColors = ['#ededed', @colorKey(0), @colorKey(1), @colorKey(2), @colorKey(3)]
|
||||
@svg.append 'g'
|
||||
.attr 'transform', "translate(18, #{@daySizeWithSpace * 8 + 16})"
|
||||
.selectAll 'rect'
|
||||
.data keyColors
|
||||
.enter()
|
||||
.append 'rect'
|
||||
.attr 'width', @daySize
|
||||
.attr 'height', @daySize
|
||||
.attr 'x', (color, i) =>
|
||||
@daySizeWithSpace * i
|
||||
.attr 'y', 0
|
||||
.attr 'fill', (color) ->
|
||||
color
|
||||
|
||||
initColor: ->
|
||||
d3.scale
|
||||
.linear()
|
||||
.range(['#acd5f2', '#254e77'])
|
||||
.domain([0, @highestValue])
|
||||
|
||||
initColorKey: ->
|
||||
d3.scale
|
||||
.linear()
|
||||
.range(['#acd5f2', '#254e77'])
|
||||
.domain([0, 3])
|
||||
|
||||
clickDay: (stamp) ->
|
||||
if @currentSelectedDate isnt stamp.date
|
||||
@currentSelectedDate = stamp.date
|
||||
formatted_date = @currentSelectedDate.getFullYear() + "-" + (@currentSelectedDate.getMonth()+1) + "-" + @currentSelectedDate.getDate()
|
||||
|
||||
$.ajax
|
||||
url: @calendar_activities_path
|
||||
data:
|
||||
date: formatted_date
|
||||
cache: false
|
||||
dataType: 'html'
|
||||
beforeSend: ->
|
||||
$('.user-calendar-activities').html '<div class="text-center"><i class="fa fa-spinner fa-spin user-calendar-activities-loading"></i></div>'
|
||||
success: (data) ->
|
||||
$('.user-calendar-activities').html data
|
||||
else
|
||||
$('.user-calendar-activities').html ''
|
||||
|
||||
initTooltips: ->
|
||||
$('.js-contrib-calendar .js-tooltip').tooltip
|
||||
html: true
|
||||
|
|
14
app/assets/javascripts/layout_nav.js.coffee
Normal file
14
app/assets/javascripts/layout_nav.js.coffee
Normal file
|
@ -0,0 +1,14 @@
|
|||
class @LayoutNav
|
||||
$ ->
|
||||
$('.fade-left').addClass('end-scroll')
|
||||
$('.scrolling-tabs').on 'scroll', (event) ->
|
||||
$this = $(this)
|
||||
$el = $(event.target)
|
||||
currentPosition = $this.scrollLeft()
|
||||
size = bp.getBreakpointSize()
|
||||
controlBtnWidth = $('.controls').width()
|
||||
maxPosition = $this.get(0).scrollWidth - $this.parent().width()
|
||||
maxPosition += controlBtnWidth if size isnt 'xs' and $('.nav-control').length
|
||||
|
||||
$el.find('.fade-left').toggleClass('end-scroll', currentPosition is 0)
|
||||
$el.find('.fade-right').toggleClass('end-scroll', currentPosition is maxPosition)
|
|
@ -8,7 +8,6 @@
|
|||
*= require select2
|
||||
*= require_self
|
||||
*= require dropzone/basic
|
||||
*= require cal-heatmap
|
||||
*= require cropper.css
|
||||
*/
|
||||
|
||||
|
|
|
@ -1,70 +1,44 @@
|
|||
.calender-block {
|
||||
padding-left: 0;
|
||||
padding-right: 0;
|
||||
|
||||
@media (min-width: $screen-sm-min) and (max-width: $screen-lg-min) {
|
||||
overflow-x: scroll;
|
||||
}
|
||||
}
|
||||
|
||||
.user-calendar-activities {
|
||||
.calendar_onclick_hr {
|
||||
padding: 0;
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.str-truncated {
|
||||
max-width: 70%;
|
||||
}
|
||||
|
||||
.text-expander {
|
||||
background: #eee;
|
||||
color: #555;
|
||||
padding: 0 5px;
|
||||
.user-calendar-activities-loading {
|
||||
font-size: 24px;
|
||||
}
|
||||
}
|
||||
|
||||
.user-calendar {
|
||||
text-align: center;
|
||||
|
||||
.calendar {
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
.user-contrib-cell {
|
||||
&:hover {
|
||||
cursor: pointer;
|
||||
margin-left: 4px;
|
||||
&:hover {
|
||||
background-color: #ddd;
|
||||
}
|
||||
stroke: #000;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This overwrites the default values of the cal-heatmap gem
|
||||
*/
|
||||
.calendar {
|
||||
.qi {
|
||||
fill: #fff;
|
||||
}
|
||||
|
||||
.q1 {
|
||||
fill: #ededed !important;
|
||||
}
|
||||
|
||||
.q2 {
|
||||
fill: #acd5f2 !important;
|
||||
}
|
||||
|
||||
.q3 {
|
||||
fill: #7fa8d1 !important;
|
||||
}
|
||||
|
||||
.q4 {
|
||||
fill: #49729b !important;
|
||||
}
|
||||
|
||||
.q5 {
|
||||
fill: #254e77 !important;
|
||||
}
|
||||
|
||||
.future {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.domain-background {
|
||||
fill: none;
|
||||
shape-rendering: crispedges;
|
||||
}
|
||||
|
||||
.ch-tooltip {
|
||||
padding: 3px;
|
||||
font-weight: 550;
|
||||
}
|
||||
.user-contrib-text {
|
||||
font-size: 12px;
|
||||
fill: #959494;
|
||||
}
|
||||
|
||||
.calendar-hint {
|
||||
margin-top: -23px;
|
||||
float: right;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
|
|
@ -1,3 +1,34 @@
|
|||
@mixin fade($gradient-direction, $rgba, $gradient-color) {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
position: absolute;
|
||||
bottom: 12px;
|
||||
width: 43px;
|
||||
height: 30px;
|
||||
transition-duration: .3s;
|
||||
-webkit-transform: translateZ(0);
|
||||
background: -webkit-linear-gradient($gradient-direction, $rgba, $gradient-color 45%);
|
||||
background: -o-linear-gradient($gradient-direction, $rgba, $gradient-color 45%);
|
||||
background: -moz-linear-gradient($gradient-direction, $rgba, $gradient-color 45%);
|
||||
background: linear-gradient($gradient-direction, $rgba, $gradient-color 45%);
|
||||
|
||||
&.end-scroll {
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition-duration: .3s;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin scrolling-links() {
|
||||
white-space: nowrap;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
@ -209,13 +240,8 @@
|
|||
float: right;
|
||||
padding: 7px 0 0;
|
||||
|
||||
@media (max-width: $screen-xs-min) {
|
||||
float: none;
|
||||
padding: 0 9px;
|
||||
|
||||
.dropdown-new {
|
||||
width: 100%;
|
||||
}
|
||||
@media (max-width: $screen-xs-max) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
i {
|
||||
|
@ -246,14 +272,18 @@
|
|||
}
|
||||
|
||||
.nav-links {
|
||||
@include scrolling-links();
|
||||
border-bottom: none;
|
||||
height: 51px;
|
||||
white-space: nowrap;
|
||||
overflow-x: auto;
|
||||
overflow-y: hidden;
|
||||
-webkit-overflow-scrolling: touch;
|
||||
&::-webkit-scrollbar {
|
||||
display: none;
|
||||
|
||||
.fade-right {
|
||||
@include fade(left, rgba(250, 250, 250, 0.4), $background-color);
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.fade-left {
|
||||
@include fade(right, rgba(250, 250, 250, 0.4), $background-color);
|
||||
left: 0;
|
||||
}
|
||||
|
||||
li {
|
||||
|
@ -278,16 +308,39 @@
|
|||
}
|
||||
}
|
||||
|
||||
.nav-control {
|
||||
.fade-right {
|
||||
|
||||
@media (min-width: $screen-xs-max) {
|
||||
right: 67px;
|
||||
}
|
||||
@media (max-width: $screen-xs-min) {
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav-block {
|
||||
position: relative;
|
||||
|
||||
.nav-links {
|
||||
@include scrolling-links();
|
||||
|
||||
.fade-right {
|
||||
@include fade(left, rgba(255, 255, 255, 0.4), $white-light);
|
||||
right: 0;
|
||||
}
|
||||
|
||||
.fade-left {
|
||||
@include fade(right, rgba(255, 255, 255, 0.4), $white-light);
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.page-with-layout-nav {
|
||||
margin-top: 50px;
|
||||
|
||||
&.controls-dropdown-visible {
|
||||
@media (max-width: $screen-xs-min) {
|
||||
margin-top: 96px;
|
||||
}
|
||||
}
|
||||
margin-top: $header-height + 2;
|
||||
|
||||
.right-sidebar {
|
||||
top: ($header-height * 2) + 2;
|
||||
|
|
|
@ -324,7 +324,7 @@
|
|||
|
||||
.layout-nav {
|
||||
@media (max-width: $screen-xs-min) {
|
||||
padding-right: 0;;
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
@media (min-width: $screen-xs-min) and (max-width: $screen-md-min) {
|
||||
|
|
134
app/assets/stylesheets/mailers/devise.scss
Normal file
134
app/assets/stylesheets/mailers/devise.scss
Normal file
|
@ -0,0 +1,134 @@
|
|||
// NOTE: This stylesheet is for the exclusive use of the `devise_mailer` layout
|
||||
// used for Devise email templates, and _should not_ be included in any
|
||||
// application stylesheets.
|
||||
//
|
||||
// Styles defined here are embedded directly into the resulting email HTML via
|
||||
// the `premailer` gem.
|
||||
|
||||
$body-background-color: #363636;
|
||||
$message-background-color: #fafafa;
|
||||
|
||||
$header-color: #6b4fbb;
|
||||
$body-color: #444;
|
||||
$cta-color: #e14329;
|
||||
$footer-link-color: #7e7e7e;
|
||||
|
||||
$font-family: Helvetica, Arial, sans-serif;
|
||||
|
||||
body {
|
||||
background-color: $body-background-color;
|
||||
font-family: $font-family;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
table {
|
||||
-premailer-cellpadding: 0;
|
||||
-premailer-cellspacing: 0;
|
||||
|
||||
border: 0;
|
||||
border-collapse: separate;
|
||||
|
||||
&#wrapper {
|
||||
background-color: $body-background-color;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&#header {
|
||||
margin: 0 auto;
|
||||
text-align: left;
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
&#body {
|
||||
background-color: $message-background-color;
|
||||
border: 1px solid #000;
|
||||
border-radius: 4px;
|
||||
margin: 0 auto;
|
||||
width: 600px;
|
||||
}
|
||||
|
||||
&#footer {
|
||||
color: $footer-link-color;
|
||||
font-size: 14px;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
td {
|
||||
&#body-container {
|
||||
padding: 20px 40px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#logo {
|
||||
border: none;
|
||||
outline: none;
|
||||
min-height: 88px;
|
||||
width: 134px;
|
||||
}
|
||||
|
||||
#content {
|
||||
h2 {
|
||||
color: $header-color;
|
||||
font-size: 30px;
|
||||
font-weight: 400;
|
||||
line-height: 34px;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
p {
|
||||
color: $body-color;
|
||||
font-size: 17px;
|
||||
line-height: 24px;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
#cta {
|
||||
border: 1px solid $cta-color;
|
||||
border-radius: 3px;
|
||||
display: inline-block;
|
||||
margin: 20px 0;
|
||||
padding: 12px 24px;
|
||||
|
||||
a {
|
||||
background-color: $message-background-color;
|
||||
color: $cta-color;
|
||||
display: inline-block;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
#tanuki {
|
||||
padding: 40px 0 0;
|
||||
|
||||
img {
|
||||
border: none;
|
||||
outline: none;
|
||||
width: 37px;
|
||||
min-height: 36px;
|
||||
}
|
||||
}
|
||||
|
||||
#tagline {
|
||||
font-size: 22px;
|
||||
font-weight: 100;
|
||||
padding: 4px 0 40px;
|
||||
}
|
||||
|
||||
#social {
|
||||
padding: 0 10px 20px;
|
||||
width: 600px;
|
||||
word-spacing: 20px;
|
||||
|
||||
a {
|
||||
color: $footer-link-color;
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
|
@ -280,11 +280,5 @@
|
|||
background-color: $white-light;
|
||||
color: $gl-placeholder-color;
|
||||
}
|
||||
|
||||
th,
|
||||
td {
|
||||
padding: 16px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,24 @@
|
|||
.pipeline-stage {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
.pipelines {
|
||||
.stage {
|
||||
max-width: 100px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.duration, .finished_at {
|
||||
margin: 4px 0;
|
||||
}
|
||||
|
||||
.commit-title {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.controls {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.btn {
|
||||
margin: 4px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -66,12 +66,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.calendar-hint {
|
||||
margin-top: -12px;
|
||||
float: right;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.profile-link-holder {
|
||||
display: inline;
|
||||
|
||||
|
|
|
@ -74,8 +74,6 @@ class UsersController < ApplicationController
|
|||
def calendar
|
||||
calendar = contributions_calendar
|
||||
@timestamps = calendar.timestamps
|
||||
@starting_year = calendar.starting_year
|
||||
@starting_month = calendar.starting_month
|
||||
|
||||
render 'calendar', layout: false
|
||||
end
|
||||
|
|
|
@ -18,7 +18,7 @@ class GroupProjectsFinder < UnionFinder
|
|||
projects = []
|
||||
|
||||
if current_user
|
||||
if @group.users.include?(current_user)
|
||||
if @group.users.include?(current_user) || current_user.admin?
|
||||
projects << @group.projects unless only_shared
|
||||
projects << @group.shared_projects unless only_owned
|
||||
else
|
||||
|
|
|
@ -159,28 +159,6 @@ module EventsHelper
|
|||
"--broken encoding"
|
||||
end
|
||||
|
||||
def event_to_atom(xml, event)
|
||||
if event.visible_to_user?(current_user)
|
||||
xml.entry do
|
||||
event_link = event_feed_url(event)
|
||||
event_title = event_feed_title(event)
|
||||
event_summary = event_feed_summary(event)
|
||||
|
||||
xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}"
|
||||
xml.link href: event_link
|
||||
xml.title truncate(event_title, length: 80)
|
||||
xml.updated event.created_at.xmlschema
|
||||
xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(event.author_email))
|
||||
xml.author do |author|
|
||||
xml.name event.author_name
|
||||
xml.email event.author_email
|
||||
end
|
||||
|
||||
xml.summary(type: "xhtml") { |x| x << event_summary unless event_summary.nil? }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def event_row_class(event)
|
||||
if event.body?
|
||||
"event-block"
|
||||
|
|
|
@ -105,23 +105,6 @@ module IssuesHelper
|
|||
return 'hidden' if issue.closed? == closed
|
||||
end
|
||||
|
||||
def issue_to_atom(xml, issue)
|
||||
xml.entry do
|
||||
xml.id namespace_project_issue_url(issue.project.namespace,
|
||||
issue.project, issue)
|
||||
xml.link href: namespace_project_issue_url(issue.project.namespace,
|
||||
issue.project, issue)
|
||||
xml.title truncate(issue.title, length: 80)
|
||||
xml.updated issue.created_at.xmlschema
|
||||
xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(issue.author_email))
|
||||
xml.author do |author|
|
||||
xml.name issue.author_name
|
||||
xml.email issue.author_email
|
||||
end
|
||||
xml.summary issue.title
|
||||
end
|
||||
end
|
||||
|
||||
def merge_requests_sentence(merge_requests)
|
||||
# Sorting based on the `!123` or `group/project!123` reference will sort
|
||||
# local merge requests first.
|
||||
|
|
|
@ -48,7 +48,7 @@ module NavHelper
|
|||
"page-with-layout-nav" if defined?(nav) && nav
|
||||
end
|
||||
|
||||
def layout_dropdown_class
|
||||
"controls-dropdown-visible" if current_user
|
||||
def nav_control_class
|
||||
"nav-control" if current_user
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
class DeviseMailer < Devise::Mailer
|
||||
default from: "#{Gitlab.config.gitlab.email_display_name} <#{Gitlab.config.gitlab.email_from}>"
|
||||
default reply_to: Gitlab.config.gitlab.email_reply_to
|
||||
|
||||
layout 'devise_mailer'
|
||||
end
|
||||
|
|
|
@ -3,7 +3,7 @@ module Projects
|
|||
def execute
|
||||
new_params = {
|
||||
forked_from_project_id: @project.id,
|
||||
visibility_level: @project.visibility_level,
|
||||
visibility_level: allowed_visibility_level,
|
||||
description: @project.description,
|
||||
name: @project.name,
|
||||
path: @project.path,
|
||||
|
@ -19,5 +19,17 @@ module Projects
|
|||
new_project = CreateService.new(current_user, new_params).execute
|
||||
new_project
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def allowed_visibility_level
|
||||
project_level = @project.visibility_level
|
||||
|
||||
if Gitlab::VisibilityLevel.non_restricted_level?(project_level)
|
||||
project_level
|
||||
else
|
||||
Gitlab::VisibilityLevel.highest_allowed_level
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -47,4 +47,3 @@
|
|||
= render "admin/builds/build", build: build
|
||||
|
||||
= paginate @builds, theme: 'gitlab'
|
||||
|
||||
|
|
|
@ -6,8 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
|
|||
xml.id issues_dashboard_url
|
||||
xml.updated @issues.first.created_at.xmlschema if @issues.any?
|
||||
|
||||
@issues.each do |issue|
|
||||
issue_to_atom(xml, issue)
|
||||
end
|
||||
xml << render(partial: 'issues/issue', collection: @issues) if @issues.any?
|
||||
end
|
||||
|
||||
|
|
|
@ -6,7 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
|
|||
xml.id dashboard_projects_url
|
||||
xml.updated @events[0].updated_at.xmlschema if @events[0]
|
||||
|
||||
@events.each do |event|
|
||||
event_to_atom(xml, event)
|
||||
end
|
||||
xml << render(partial: 'events/event', collection: @events) if @events.any?
|
||||
end
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
<p>Welcome <%= @resource.name %>!</p>
|
||||
|
||||
<% if @resource.unconfirmed_email.present? %>
|
||||
<p>You can confirm your email (<%= @resource.unconfirmed_email %>) through the link below:</p>
|
||||
<% else %>
|
||||
<p>You can confirm your account through the link below:</p>
|
||||
<% end %>
|
||||
|
||||
<p><%= link_to 'Confirm your account', confirmation_url(@resource, confirmation_token: @token) %></p>
|
16
app/views/devise/mailer/confirmation_instructions.html.haml
Normal file
16
app/views/devise/mailer/confirmation_instructions.html.haml
Normal file
|
@ -0,0 +1,16 @@
|
|||
.center
|
||||
- if @resource.unconfirmed_email.present?
|
||||
#content
|
||||
%h2= @resource.unconfirmed_email
|
||||
%p Click the link below to confirm your email address.
|
||||
#cta
|
||||
= link_to 'Confirm your email address', confirmation_url(@resource, confirmation_token: @token)
|
||||
- else
|
||||
#content
|
||||
- if Gitlab.com?
|
||||
%h2 Thanks for signing up to GitLab!
|
||||
- else
|
||||
%h2 Welcome, #{@resource.name}!
|
||||
%p To get started, click the link below to confirm your account.
|
||||
#cta
|
||||
= link_to 'Confirm your account', confirmation_url(@resource, confirmation_token: @token)
|
|
@ -0,0 +1,9 @@
|
|||
Welcome, <%= @resource.name %>!
|
||||
|
||||
<% if @resource.unconfirmed_email.present? %>
|
||||
You can confirm your email (<%= @resource.unconfirmed_email %>) through the link below:
|
||||
<% else %>
|
||||
You can confirm your account through the link below:
|
||||
<% end %>
|
||||
|
||||
<%= confirmation_url(@resource, confirmation_token: @token) %>
|
20
app/views/events/_event.atom.builder
Normal file
20
app/views/events/_event.atom.builder
Normal file
|
@ -0,0 +1,20 @@
|
|||
return unless event.visible_to_user?(current_user)
|
||||
|
||||
xml.entry do
|
||||
xml.id "tag:#{request.host},#{event.created_at.strftime("%Y-%m-%d")}:#{event.id}"
|
||||
xml.link href: event_feed_url(event)
|
||||
xml.title truncate(event_feed_title(event), length: 80)
|
||||
xml.updated event.created_at.xmlschema
|
||||
xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(event.author_email))
|
||||
|
||||
xml.author do
|
||||
xml.name event.author_name
|
||||
xml.email event.author_email
|
||||
end
|
||||
|
||||
xml.summary(type: "xhtml") do |summary|
|
||||
event_summary = event_feed_summary(event)
|
||||
|
||||
summary << event_summary unless event_summary.nil?
|
||||
end
|
||||
end
|
|
@ -6,8 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
|
|||
xml.id issues_group_url
|
||||
xml.updated @issues.first.created_at.xmlschema if @issues.any?
|
||||
|
||||
@issues.each do |issue|
|
||||
issue_to_atom(xml, issue)
|
||||
end
|
||||
xml << render(partial: 'issues/issue', collection: @issues) if @issues.any?
|
||||
end
|
||||
|
||||
|
|
|
@ -6,7 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
|
|||
xml.id group_url(@group)
|
||||
xml.updated @events[0].updated_at.xmlschema if @events[0]
|
||||
|
||||
@events.each do |event|
|
||||
event_to_atom(xml, event)
|
||||
end
|
||||
xml << render(@events) if @events.any?
|
||||
end
|
||||
|
|
14
app/views/issues/_issue.atom.builder
Normal file
14
app/views/issues/_issue.atom.builder
Normal file
|
@ -0,0 +1,14 @@
|
|||
xml.entry do
|
||||
xml.id namespace_project_issue_url(issue.project.namespace, issue.project, issue)
|
||||
xml.link href: namespace_project_issue_url(issue.project.namespace, issue.project, issue)
|
||||
xml.title truncate(issue.title, length: 80)
|
||||
xml.updated issue.created_at.xmlschema
|
||||
xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(issue.author_email))
|
||||
|
||||
xml.author do |author|
|
||||
xml.name issue.author_name
|
||||
xml.email issue.author_email
|
||||
end
|
||||
|
||||
xml.summary issue.title
|
||||
end
|
|
@ -25,7 +25,7 @@
|
|||
.layout-nav
|
||||
.container-fluid
|
||||
= render "layouts/nav/#{nav}"
|
||||
.content-wrapper{ class: "#{layout_nav_class} #{layout_dropdown_class}" }
|
||||
.content-wrapper{ class: "#{layout_nav_class}" }
|
||||
= render "layouts/broadcast"
|
||||
= render "layouts/flash"
|
||||
= yield :flash_message
|
||||
|
|
34
app/views/layouts/devise_mailer.html.haml
Normal file
34
app/views/layouts/devise_mailer.html.haml
Normal file
|
@ -0,0 +1,34 @@
|
|||
!!! 5
|
||||
%html
|
||||
%head
|
||||
%meta(content='text/html; charset=UTF-8' http-equiv='Content-Type')
|
||||
= stylesheet_link_tag 'mailers/devise'
|
||||
|
||||
%body
|
||||
%table#wrapper
|
||||
%tr
|
||||
%td
|
||||
%table#header
|
||||
%td{valign: "top"}
|
||||
= image_tag('mailers/gitlab_header_logo.png', id: 'logo', alt: 'GitLab Wordmark')
|
||||
|
||||
%table#body
|
||||
%tr
|
||||
%td#body-container
|
||||
= yield
|
||||
|
||||
- if Gitlab.com?
|
||||
%table#footer
|
||||
%tr
|
||||
%td#tanuki
|
||||
= image_tag('mailers/gitlab_tanuki_2x.png', alt: 'GitLab Logo')
|
||||
%tr
|
||||
%td#tagline
|
||||
Everyone can contribute
|
||||
%tr
|
||||
%td#social
|
||||
= link_to 'Blog', 'https://about.gitlab.com/blog/'
|
||||
= link_to 'Twitter', 'https://twitter.com/gitlab'
|
||||
= link_to 'Facebook', 'https://www.facebook.com/gitlab/'
|
||||
= link_to 'YouTube', 'https://www.youtube.com/channel/UCnMGQ8QHMAnVIsI3xJrihhg'
|
||||
= link_to 'LinkedIn', 'https://www.linkedin.com/company/gitlab-com'
|
|
@ -1,37 +1,40 @@
|
|||
= render 'layouts/nav/group_settings'
|
||||
%div{ class: nav_control_class }
|
||||
= render 'layouts/nav/group_settings'
|
||||
|
||||
%ul.nav-links
|
||||
= nav_link(path: 'groups#show', html_options: {class: 'home'}) do
|
||||
= link_to group_path(@group), title: 'Home' do
|
||||
= icon('group fw')
|
||||
%span
|
||||
Group
|
||||
= nav_link(path: 'groups#activity') do
|
||||
= link_to activity_group_path(@group), title: 'Activity' do
|
||||
= icon('dashboard fw')
|
||||
%span
|
||||
Activity
|
||||
= nav_link(controller: [:group, :milestones]) do
|
||||
= link_to group_milestones_path(@group), title: 'Milestones' do
|
||||
= icon('clock-o fw')
|
||||
%span
|
||||
Milestones
|
||||
= nav_link(path: 'groups#issues') do
|
||||
= link_to issues_group_path(@group), title: 'Issues' do
|
||||
= icon('exclamation-circle fw')
|
||||
%span
|
||||
Issues
|
||||
- issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute
|
||||
%span.badge.count= number_with_delimiter(issues.count)
|
||||
= nav_link(path: 'groups#merge_requests') do
|
||||
= link_to merge_requests_group_path(@group), title: 'Merge Requests' do
|
||||
= icon('tasks fw')
|
||||
%span
|
||||
Merge Requests
|
||||
- merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened').execute
|
||||
%span.badge.count= number_with_delimiter(merge_requests.count)
|
||||
= nav_link(controller: [:group_members]) do
|
||||
= link_to group_group_members_path(@group), title: 'Members' do
|
||||
= icon('users fw')
|
||||
%span
|
||||
Members
|
||||
%ul.nav-links.scrolling-tabs
|
||||
.fade-left
|
||||
= nav_link(path: 'groups#show', html_options: {class: 'home'}) do
|
||||
= link_to group_path(@group), title: 'Home' do
|
||||
= icon('group fw')
|
||||
%span
|
||||
Group
|
||||
= nav_link(path: 'groups#activity') do
|
||||
= link_to activity_group_path(@group), title: 'Activity' do
|
||||
= icon('dashboard fw')
|
||||
%span
|
||||
Activity
|
||||
= nav_link(controller: [:group, :milestones]) do
|
||||
= link_to group_milestones_path(@group), title: 'Milestones' do
|
||||
= icon('clock-o fw')
|
||||
%span
|
||||
Milestones
|
||||
= nav_link(path: 'groups#issues') do
|
||||
= link_to issues_group_path(@group), title: 'Issues' do
|
||||
= icon('exclamation-circle fw')
|
||||
%span
|
||||
Issues
|
||||
- issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute
|
||||
%span.badge.count= number_with_delimiter(issues.count)
|
||||
= nav_link(path: 'groups#merge_requests') do
|
||||
= link_to merge_requests_group_path(@group), title: 'Merge Requests' do
|
||||
= icon('tasks fw')
|
||||
%span
|
||||
Merge Requests
|
||||
- merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened').execute
|
||||
%span.badge.count= number_with_delimiter(merge_requests.count)
|
||||
= nav_link(controller: [:group_members]) do
|
||||
= link_to group_group_members_path(@group), title: 'Members' do
|
||||
= icon('users fw')
|
||||
%span
|
||||
Members
|
||||
.fade-right
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
%ul.nav-links
|
||||
%ul.nav-links.scrolling-tabs
|
||||
.fade-left
|
||||
= nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
|
||||
= link_to profile_path, title: 'Profile Settings' do
|
||||
= icon('user fw')
|
||||
|
@ -47,3 +48,4 @@
|
|||
= icon('history fw')
|
||||
%span
|
||||
Audit Log
|
||||
.fade-right
|
||||
|
|
|
@ -19,113 +19,117 @@
|
|||
data: { confirm: leave_project_message(@project) }, method: :delete, title: 'Leave project' do
|
||||
Leave Project
|
||||
|
||||
%ul.nav-links
|
||||
= nav_link(path: 'projects#show', html_options: {class: 'home'}) do
|
||||
= link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do
|
||||
= icon('bookmark fw')
|
||||
%span
|
||||
Project
|
||||
= nav_link(path: 'projects#activity') do
|
||||
= link_to activity_project_path(@project), title: 'Activity', class: 'shortcuts-project-activity' do
|
||||
= icon('dashboard fw')
|
||||
%span
|
||||
Activity
|
||||
- if project_nav_tab? :files
|
||||
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do
|
||||
= link_to project_files_path(@project), title: 'Files', class: 'shortcuts-tree' do
|
||||
= icon('files-o fw')
|
||||
%div{ class: nav_control_class }
|
||||
%ul.nav-links.scrolling-tabs
|
||||
.fade-left
|
||||
= nav_link(path: 'projects#show', html_options: {class: 'home'}) do
|
||||
= link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do
|
||||
= icon('bookmark fw')
|
||||
%span
|
||||
Files
|
||||
|
||||
- if project_nav_tab? :commits
|
||||
= nav_link(controller: %w(commit commits compare repositories tags branches releases network)) do
|
||||
= link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits' do
|
||||
= icon('history fw')
|
||||
Project
|
||||
= nav_link(path: 'projects#activity') do
|
||||
= link_to activity_project_path(@project), title: 'Activity', class: 'shortcuts-project-activity' do
|
||||
= icon('dashboard fw')
|
||||
%span
|
||||
Commits
|
||||
Activity
|
||||
- if project_nav_tab? :files
|
||||
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do
|
||||
= link_to project_files_path(@project), title: 'Files', class: 'shortcuts-tree' do
|
||||
= icon('files-o fw')
|
||||
%span
|
||||
Files
|
||||
|
||||
- if project_nav_tab? :pipelines
|
||||
= nav_link(controller: :pipelines) do
|
||||
= link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do
|
||||
= icon('ship fw')
|
||||
%span
|
||||
Pipelines
|
||||
%span.badge.count.ci_counter= number_with_delimiter(@project.ci_commits.running_or_pending.count)
|
||||
- if project_nav_tab? :commits
|
||||
= nav_link(controller: %w(commit commits compare repositories tags branches releases network)) do
|
||||
= link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits' do
|
||||
= icon('history fw')
|
||||
%span
|
||||
Commits
|
||||
|
||||
- if project_nav_tab? :builds
|
||||
= nav_link(controller: %w(builds)) do
|
||||
= link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds' do
|
||||
= icon('cubes fw')
|
||||
%span
|
||||
Builds
|
||||
%span.badge.count.builds_counter= number_with_delimiter(@project.builds.running_or_pending.count(:all))
|
||||
- if project_nav_tab? :pipelines
|
||||
= nav_link(controller: :pipelines) do
|
||||
= link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do
|
||||
= icon('ship fw')
|
||||
%span
|
||||
Pipelines
|
||||
%span.badge.count.ci_counter= number_with_delimiter(@project.ci_commits.running_or_pending.count)
|
||||
|
||||
- if project_nav_tab? :container_registry
|
||||
= nav_link(controller: %w(container_registry)) do
|
||||
= link_to project_container_registry_path(@project), title: 'Container Registry', class: 'shortcuts-container-registry' do
|
||||
= icon('hdd-o fw')
|
||||
%span
|
||||
Container Registry
|
||||
- if project_nav_tab? :builds
|
||||
= nav_link(controller: %w(builds)) do
|
||||
= link_to project_builds_path(@project), title: 'Builds', class: 'shortcuts-builds' do
|
||||
= icon('cubes fw')
|
||||
%span
|
||||
Builds
|
||||
%span.badge.count.builds_counter= number_with_delimiter(@project.builds.running_or_pending.count(:all))
|
||||
|
||||
- if project_nav_tab? :graphs
|
||||
= nav_link(controller: %w(graphs)) do
|
||||
= link_to namespace_project_graph_path(@project.namespace, @project, current_ref), title: 'Graphs', class: 'shortcuts-graphs' do
|
||||
= icon('area-chart fw')
|
||||
%span
|
||||
Graphs
|
||||
- if project_nav_tab? :container_registry
|
||||
= nav_link(controller: %w(container_registry)) do
|
||||
= link_to project_container_registry_path(@project), title: 'Container Registry', class: 'shortcuts-container-registry' do
|
||||
= icon('hdd-o fw')
|
||||
%span
|
||||
Container Registry
|
||||
|
||||
- if project_nav_tab? :milestones
|
||||
= nav_link(controller: :milestones) do
|
||||
= link_to namespace_project_milestones_path(@project.namespace, @project), title: 'Milestones' do
|
||||
= icon('clock-o fw')
|
||||
%span
|
||||
Milestones
|
||||
- if project_nav_tab? :graphs
|
||||
= nav_link(controller: %w(graphs)) do
|
||||
= link_to namespace_project_graph_path(@project.namespace, @project, current_ref), title: 'Graphs', class: 'shortcuts-graphs' do
|
||||
= icon('area-chart fw')
|
||||
%span
|
||||
Graphs
|
||||
|
||||
- if project_nav_tab? :issues
|
||||
= nav_link(controller: :issues) do
|
||||
= link_to url_for_project_issues(@project, only_path: true), title: 'Issues', class: 'shortcuts-issues' do
|
||||
= icon('exclamation-circle fw')
|
||||
%span
|
||||
Issues
|
||||
- if @project.default_issues_tracker?
|
||||
%span.badge.count.issue_counter= number_with_delimiter(@project.issues.visible_to_user(current_user).opened.count)
|
||||
- if project_nav_tab? :milestones
|
||||
= nav_link(controller: :milestones) do
|
||||
= link_to namespace_project_milestones_path(@project.namespace, @project), title: 'Milestones' do
|
||||
= icon('clock-o fw')
|
||||
%span
|
||||
Milestones
|
||||
|
||||
- if project_nav_tab? :merge_requests
|
||||
= nav_link(controller: :merge_requests) do
|
||||
= link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do
|
||||
= icon('tasks fw')
|
||||
%span
|
||||
Merge Requests
|
||||
%span.badge.count.merge_counter= number_with_delimiter(@project.merge_requests.opened.count)
|
||||
- if project_nav_tab? :issues
|
||||
= nav_link(controller: :issues) do
|
||||
= link_to url_for_project_issues(@project, only_path: true), title: 'Issues', class: 'shortcuts-issues' do
|
||||
= icon('exclamation-circle fw')
|
||||
%span
|
||||
Issues
|
||||
- if @project.default_issues_tracker?
|
||||
%span.badge.count.issue_counter= number_with_delimiter(@project.issues.visible_to_user(current_user).opened.count)
|
||||
|
||||
- if project_nav_tab? :labels
|
||||
= nav_link(controller: :labels) do
|
||||
= link_to namespace_project_labels_path(@project.namespace, @project), title: 'Labels' do
|
||||
= icon('tags fw')
|
||||
%span
|
||||
Labels
|
||||
- if project_nav_tab? :merge_requests
|
||||
= nav_link(controller: :merge_requests) do
|
||||
= link_to namespace_project_merge_requests_path(@project.namespace, @project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do
|
||||
= icon('tasks fw')
|
||||
%span
|
||||
Merge Requests
|
||||
%span.badge.count.merge_counter= number_with_delimiter(@project.merge_requests.opened.count)
|
||||
|
||||
- if project_nav_tab? :wiki
|
||||
= nav_link(controller: :wikis) do
|
||||
= link_to get_project_wiki_path(@project), title: 'Wiki', class: 'shortcuts-wiki' do
|
||||
= icon('book fw')
|
||||
%span
|
||||
Wiki
|
||||
- if project_nav_tab? :labels
|
||||
= nav_link(controller: :labels) do
|
||||
= link_to namespace_project_labels_path(@project.namespace, @project), title: 'Labels' do
|
||||
= icon('tags fw')
|
||||
%span
|
||||
Labels
|
||||
|
||||
- if project_nav_tab? :snippets
|
||||
= nav_link(controller: :snippets) do
|
||||
= link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets' do
|
||||
= icon('clipboard fw')
|
||||
%span
|
||||
Snippets
|
||||
- if project_nav_tab? :wiki
|
||||
= nav_link(controller: :wikis) do
|
||||
= link_to get_project_wiki_path(@project), title: 'Wiki', class: 'shortcuts-wiki' do
|
||||
= icon('book fw')
|
||||
%span
|
||||
Wiki
|
||||
|
||||
-# Global shortcut to network page for compatibility
|
||||
- if project_nav_tab? :network
|
||||
- if project_nav_tab? :snippets
|
||||
= nav_link(controller: :snippets) do
|
||||
= link_to namespace_project_snippets_path(@project.namespace, @project), title: 'Snippets', class: 'shortcuts-snippets' do
|
||||
= icon('clipboard fw')
|
||||
%span
|
||||
Snippets
|
||||
|
||||
-# Global shortcut to network page for compatibility
|
||||
- if project_nav_tab? :network
|
||||
%li.hidden
|
||||
= link_to namespace_project_network_path(@project.namespace, @project, current_ref), title: 'Network', class: 'shortcuts-network' do
|
||||
Network
|
||||
|
||||
-# Shortcut to create a new issue
|
||||
%li.hidden
|
||||
= link_to namespace_project_network_path(@project.namespace, @project, current_ref), title: 'Network', class: 'shortcuts-network' do
|
||||
Network
|
||||
= link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'shortcuts-new-issue' do
|
||||
Create a new issue
|
||||
|
||||
-# Shortcut to create a new issue
|
||||
%li.hidden
|
||||
= link_to new_namespace_project_issue_path(@project.namespace, @project), class: 'shortcuts-new-issue' do
|
||||
Create a new issue
|
||||
.fade-right
|
||||
|
|
|
@ -35,9 +35,6 @@
|
|||
= icon('wrench')
|
||||
%span CI Lint
|
||||
|
||||
.row-content-block
|
||||
#{(@scope || 'all').capitalize} builds from this project
|
||||
|
||||
%ul.content-list
|
||||
- if @builds.blank?
|
||||
%li
|
||||
|
|
|
@ -57,14 +57,10 @@
|
|||
|
||||
%td.duration
|
||||
- if build.duration
|
||||
= icon("clock-o")
|
||||
|
||||
#{duration_in_words(build.finished_at, build.started_at)}
|
||||
|
||||
%td.timestamp
|
||||
- if build.finished_at
|
||||
= icon("calendar")
|
||||
|
||||
%span #{time_ago_with_tooltip(build.finished_at)}
|
||||
|
||||
- if defined?(coverage) && coverage
|
||||
|
|
|
@ -12,10 +12,10 @@
|
|||
·
|
||||
= link_to commit.short_sha, namespace_project_commit_path(@project.namespace, @project, commit.sha), class: "commit-id monospace"
|
||||
|
||||
- if commit.latest?
|
||||
%span.label.label-success latest
|
||||
- if commit.tag?
|
||||
%span.label.label-primary tag
|
||||
- elsif commit.latest?
|
||||
%span.label.label-success.has-tooltip{ title: 'Latest build for this branch' } latest
|
||||
- if commit.triggered?
|
||||
%span.label.label-primary triggered
|
||||
- if commit.yaml_errors.present?
|
||||
|
@ -23,33 +23,29 @@
|
|||
- if commit.builds.any?(&:stuck?)
|
||||
%span.label.label-warning stuck
|
||||
|
||||
%p
|
||||
%span
|
||||
- if commit_data = commit.commit_data
|
||||
= link_to_gfm commit_data.title, namespace_project_commit_path(@project.namespace, @project, commit_data.id), class: "commit-row-message"
|
||||
- else
|
||||
Cant find HEAD commit for this branch
|
||||
%p.commit-title
|
||||
- if commit_data = commit.commit_data
|
||||
= link_to_gfm truncate(commit_data.title, length: 60), namespace_project_commit_path(@project.namespace, @project, commit_data.id), class: "commit-row-message"
|
||||
- else
|
||||
Cant find HEAD commit for this branch
|
||||
|
||||
|
||||
- stages_status = commit.statuses.stages_status
|
||||
- stages.each do |stage|
|
||||
%td
|
||||
- if status = stages_status[stage]
|
||||
- tooltip = "#{stage.titleize}: #{status}"
|
||||
%span.has-tooltip{ title: "#{tooltip}", class: "ci-status-icon-#{status}" }
|
||||
- status = stages_status[stage]
|
||||
- tooltip = "#{stage.titleize}: #{status || 'not found'}"
|
||||
- if status
|
||||
= link_to namespace_project_pipeline_path(@project.namespace, @project, commit.id, anchor: stage), class: "has-tooltip ci-status-icon-#{status}", title: tooltip do
|
||||
= ci_icon_for_status(status)
|
||||
- else
|
||||
.light.has-tooltip{ title: tooltip }
|
||||
\-
|
||||
|
||||
%td
|
||||
- if commit.started_at && commit.finished_at
|
||||
%p
|
||||
= icon("clock-o")
|
||||
|
||||
%p.duration
|
||||
#{duration_in_words(commit.finished_at, commit.started_at)}
|
||||
- if commit.finished_at
|
||||
%p
|
||||
= icon("calendar")
|
||||
|
||||
#{time_ago_with_tooltip(commit.finished_at)}
|
||||
|
||||
%td
|
||||
.controls.hidden-xs.pull-right
|
||||
|
@ -67,11 +63,9 @@
|
|||
%span #{build.name}
|
||||
|
||||
- if can?(current_user, :update_pipeline, @project)
|
||||
|
||||
- if commit.retryable? && commit.builds.failed.any?
|
||||
= link_to retry_namespace_project_pipeline_path(@project.namespace, @project, commit.id), class: 'btn has-tooltip', title: "Retry", method: :post do
|
||||
= icon("repeat")
|
||||
|
||||
- if commit.active?
|
||||
= link_to cancel_namespace_project_pipeline_path(@project.namespace, @project, commit.id), class: 'btn btn-remove has-tooltip', title: "Cancel", method: :post do
|
||||
= icon("remove")
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
%tr
|
||||
%th{colspan: 10}
|
||||
%strong
|
||||
%a{name: stage}
|
||||
- status = statuses.latest.status
|
||||
%span{class: "ci-status-link ci-status-icon-#{status}"}
|
||||
= ci_icon_for_status(status)
|
||||
|
|
14
app/views/projects/commits/_commit.atom.builder
Normal file
14
app/views/projects/commits/_commit.atom.builder
Normal file
|
@ -0,0 +1,14 @@
|
|||
xml.entry do
|
||||
xml.id namespace_project_commit_url(@project.namespace, @project, id: commit.id)
|
||||
xml.link href: namespace_project_commit_url(@project.namespace, @project, id: commit.id)
|
||||
xml.title truncate(commit.title, length: 80)
|
||||
xml.updated commit.committed_date.xmlschema
|
||||
xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(commit.author_email))
|
||||
|
||||
xml.author do |author|
|
||||
xml.name commit.author_name
|
||||
xml.email commit.author_email
|
||||
end
|
||||
|
||||
xml.summary markdown(commit.description, pipeline: :single_line)
|
||||
end
|
|
@ -6,18 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
|
|||
xml.id namespace_project_commits_url(@project.namespace, @project, @ref)
|
||||
xml.updated @commits.first.committed_date.xmlschema if @commits.any?
|
||||
|
||||
@commits.each do |commit|
|
||||
xml.entry do
|
||||
xml.id namespace_project_commit_url(@project.namespace, @project, id: commit.id)
|
||||
xml.link href: namespace_project_commit_url(@project.namespace, @project, id: commit.id)
|
||||
xml.title truncate(commit.title, length: 80)
|
||||
xml.updated commit.committed_date.xmlschema
|
||||
xml.media :thumbnail, width: "40", height: "40", url: image_url(avatar_icon(commit.author_email))
|
||||
xml.author do |author|
|
||||
xml.name commit.author_name
|
||||
xml.email commit.author_email
|
||||
end
|
||||
xml.summary markdown(commit.description, pipeline: :single_line)
|
||||
end
|
||||
end
|
||||
xml << render(@commits) if @commits.any?
|
||||
end
|
||||
|
|
|
@ -50,14 +50,10 @@
|
|||
|
||||
%td.duration
|
||||
- if generic_commit_status.duration
|
||||
= icon("clock-o")
|
||||
|
||||
#{duration_in_words(generic_commit_status.finished_at, generic_commit_status.started_at)}
|
||||
|
||||
%td.timestamp
|
||||
- if generic_commit_status.finished_at
|
||||
= icon("calendar")
|
||||
|
||||
%span #{time_ago_with_tooltip(generic_commit_status.finished_at)}
|
||||
|
||||
- if defined?(coverage) && coverage
|
||||
|
|
|
@ -6,7 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
|
|||
xml.id namespace_project_issues_url(@project.namespace, @project)
|
||||
xml.updated @issues.first.created_at.xmlschema if @issues.any?
|
||||
|
||||
@issues.each do |issue|
|
||||
issue_to_atom(xml, issue)
|
||||
end
|
||||
xml << render(partial: 'issues/issue', collection: @issues) if @issues.any?
|
||||
end
|
||||
|
|
|
@ -36,15 +36,7 @@
|
|||
= icon('wrench')
|
||||
%span CI Lint
|
||||
|
||||
.row-content-block
|
||||
- if @scope == 'running'
|
||||
Running pipelines for this project
|
||||
- elsif @scope.nil?
|
||||
Pipelines for this project
|
||||
- else
|
||||
#{@scope.titleize} for this project
|
||||
|
||||
%ul.content-list
|
||||
%ul.content-list.pipelines
|
||||
- stages = @pipelines.stages
|
||||
- if @pipelines.blank?
|
||||
%li
|
||||
|
@ -56,10 +48,10 @@
|
|||
%th ID
|
||||
%th Commit
|
||||
- stages.each do |stage|
|
||||
%th
|
||||
%span.pipeline-stage.has-tooltip{ title: "#{stage.titleize}" }
|
||||
%th.stage
|
||||
%span.has-tooltip{ title: "#{stage.titleize}" }
|
||||
= stage.titleize.pluralize
|
||||
%th
|
||||
%th Duration
|
||||
%th
|
||||
= render @pipelines, commit_sha: true, stage: true, allow_retry: true, stages: stages
|
||||
|
||||
|
|
|
@ -6,7 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
|
|||
xml.id namespace_project_url(@project.namespace, @project)
|
||||
xml.updated @events[0].updated_at.xmlschema if @events[0]
|
||||
|
||||
@events.each do |event|
|
||||
event_to_atom(xml, event)
|
||||
end
|
||||
xml << render(@events) if @events.any?
|
||||
end
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
%ul.nav-links.event-filter
|
||||
%ul.nav-links.event-filter.scrolling-tabs
|
||||
.fade-left
|
||||
= event_filter_link EventFilter.push, 'Push events'
|
||||
= event_filter_link EventFilter.merged, 'Merge events'
|
||||
= event_filter_link EventFilter.comments, 'Comments'
|
||||
= event_filter_link EventFilter.team, 'Team'
|
||||
.fade-right
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
#cal-heatmap.calendar
|
||||
:javascript
|
||||
new Calendar(
|
||||
#{@timestamps.to_json},
|
||||
#{@starting_year},
|
||||
#{@starting_month},
|
||||
'#{user_calendar_activities_path}'
|
||||
);
|
||||
|
||||
.calendar-hint Summary of issues, merge requests, and push events
|
||||
.clearfix.calendar
|
||||
.js-contrib-calendar
|
||||
.calendar-hint
|
||||
Summary of issues, merge requests, and push events
|
||||
:javascript
|
||||
new Calendar(
|
||||
#{@timestamps.to_json},
|
||||
'#{user_calendar_activities_path}'
|
||||
);
|
||||
|
|
|
@ -1,23 +1,27 @@
|
|||
%h4.prepend-top-20
|
||||
%span.light Contributions for
|
||||
Contributions for
|
||||
%strong #{@calendar_date.to_s(:short)}
|
||||
|
||||
%ul.bordered-list
|
||||
- @events.sort_by(&:created_at).each do |event|
|
||||
%li
|
||||
%span.light
|
||||
%i.fa.fa-clock-o
|
||||
= event.created_at.to_s(:time)
|
||||
- if event.push?
|
||||
#{event.action_name} #{event.ref_type} #{event.ref_name}
|
||||
- else
|
||||
= event_action_name(event)
|
||||
- if event.target
|
||||
%strong= link_to "##{event.target_iid}", [event.project.namespace.becomes(Namespace), event.project, event.target]
|
||||
|
||||
at
|
||||
%strong
|
||||
- if event.project
|
||||
= link_to_project event.project
|
||||
- if @events.any?
|
||||
%ul.bordered-list
|
||||
- @events.sort_by(&:created_at).each do |event|
|
||||
%li
|
||||
%span.light
|
||||
%i.fa.fa-clock-o
|
||||
= event.created_at.to_s(:time)
|
||||
- if event.push?
|
||||
#{event.action_name} #{event.ref_type} #{event.ref_name}
|
||||
- else
|
||||
= event.project_name
|
||||
= event_action_name(event)
|
||||
- if event.target
|
||||
%strong= link_to "##{event.target_iid}", [event.project.namespace.becomes(Namespace), event.project, event.target]
|
||||
|
||||
at
|
||||
%strong
|
||||
- if event.project
|
||||
= link_to_project event.project
|
||||
- else
|
||||
= event.project_name
|
||||
- else
|
||||
%p
|
||||
No contributions found for #{@calendar_date.to_s(:short)}
|
||||
|
|
|
@ -6,7 +6,5 @@ xml.feed "xmlns" => "http://www.w3.org/2005/Atom", "xmlns:media" => "http://sear
|
|||
xml.id user_url(@user)
|
||||
xml.updated @events[0].updated_at.xmlschema if @events[0]
|
||||
|
||||
@events.each do |event|
|
||||
event_to_atom(xml, event)
|
||||
end
|
||||
xml << render(@events) if @events.any?
|
||||
end
|
||||
|
|
|
@ -89,10 +89,9 @@
|
|||
.tab-content
|
||||
#activity.tab-pane
|
||||
.row-content-block.calender-block.white.second-block.hidden-xs
|
||||
%div{ class: container_class }
|
||||
.user-calendar{data: {href: user_calendar_path}}
|
||||
%h4.center.light
|
||||
%i.fa.fa-spinner.fa-spin
|
||||
.user-calendar{data: {href: user_calendar_path}}
|
||||
%h4.center.light
|
||||
%i.fa.fa-spinner.fa-spin
|
||||
.user-calendar-activities
|
||||
|
||||
.content_list{ data: {href: user_path} }
|
||||
|
|
|
@ -80,7 +80,7 @@ module Gitlab
|
|||
config.assets.precompile << "*.png"
|
||||
config.assets.precompile << "print.css"
|
||||
config.assets.precompile << "notify.css"
|
||||
config.assets.precompile << "mailers/repository_push_email.css"
|
||||
config.assets.precompile << "mailers/*.css"
|
||||
|
||||
# Version of your assets, change this if you want to expire all your assets
|
||||
config.assets.version = '1.0'
|
||||
|
|
|
@ -39,6 +39,7 @@ Rails.application.configure do
|
|||
config.action_mailer.delivery_method = :letter_opener_web
|
||||
# Don't make a mess when bootstrapping a development environment
|
||||
config.action_mailer.perform_deliveries = (ENV['BOOTSTRAP'] != '1')
|
||||
config.action_mailer.preview_path = 'spec/mailers/previews'
|
||||
|
||||
config.eager_load = false
|
||||
end
|
||||
|
|
|
@ -3,6 +3,6 @@ Premailer::Rails.config.merge!(
|
|||
generate_text_part: false,
|
||||
preserve_styles: true,
|
||||
remove_comments: true,
|
||||
remove_ids: true,
|
||||
remove_ids: false,
|
||||
remove_scripts: false
|
||||
)
|
||||
|
|
|
@ -19,6 +19,8 @@ Components/Servers Required:
|
|||
|
||||
- 2 servers/virtual machines (one active/one passive)
|
||||
|
||||
![Active/Passive HA Diagram](../img/high_availability/active-passive-diagram.png)
|
||||
|
||||
### Active/Active
|
||||
|
||||
This architecture scales easily because all application servers handle
|
||||
|
@ -26,6 +28,8 @@ user requests simultaneously. The database, Redis, and GitLab application are
|
|||
all deployed on separate servers. The configuration is **only** highly-available
|
||||
if the database, Redis and storage are also configured as such.
|
||||
|
||||
![Active/Active HA Diagram](../img/high_availability/active-active-diagram.png)
|
||||
|
||||
**Steps to configure active/active:**
|
||||
|
||||
1. [Configure the database](database.md)
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
Binary file not shown.
After Width: | Height: | Size: 24 KiB |
|
@ -34,7 +34,7 @@ class Spinach::Features::User < Spinach::FeatureSteps
|
|||
end
|
||||
|
||||
step 'I should see contributions calendar' do
|
||||
expect(page).to have_css('.cal-heatmap-container')
|
||||
expect(page).to have_css('.js-contrib-calendar')
|
||||
end
|
||||
|
||||
def contributed_project
|
||||
|
|
|
@ -95,8 +95,7 @@ module API
|
|||
# GET /groups/:id/projects
|
||||
get ":id/projects" do
|
||||
group = find_group(params[:id])
|
||||
projects = group.projects
|
||||
projects = filter_projects(projects)
|
||||
projects = GroupProjectsFinder.new(group).execute(current_user)
|
||||
projects = paginate projects
|
||||
present projects, with: Entities::Project
|
||||
end
|
||||
|
|
|
@ -19,7 +19,7 @@ module Gitlab
|
|||
select('date(created_at) as date, count(id) as total_amount').
|
||||
map(&:attributes)
|
||||
|
||||
dates = (1.year.ago.to_date..(Date.today + 1.day)).to_a
|
||||
dates = (1.year.ago.to_date..Date.today).to_a
|
||||
|
||||
dates.each do |date|
|
||||
date_id = date.to_time.to_i.to_s
|
||||
|
|
|
@ -7,7 +7,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def initialize(url, credentials: nil)
|
||||
@url = Addressable::URI.parse(URI.encode(url))
|
||||
@url = Addressable::URI.parse(url)
|
||||
@credentials = credentials
|
||||
end
|
||||
|
||||
|
|
|
@ -32,6 +32,13 @@ module Gitlab
|
|||
}
|
||||
end
|
||||
|
||||
def highest_allowed_level
|
||||
restricted_levels = current_application_settings.restricted_visibility_levels
|
||||
|
||||
allowed_levels = self.values - restricted_levels
|
||||
allowed_levels.max || PRIVATE
|
||||
end
|
||||
|
||||
def allowed_for?(user, level)
|
||||
user.is_admin? || allowed_level?(level.to_i)
|
||||
end
|
||||
|
|
|
@ -43,7 +43,6 @@ describe "Builds" do
|
|||
end
|
||||
|
||||
it { expect(page).to have_selector('.nav-links li.active', text: 'All') }
|
||||
it { expect(page).to have_selector('.row-content-block', text: 'All builds from this project') }
|
||||
it { expect(page).to have_content @build.short_sha }
|
||||
it { expect(page).to have_content @build.ref }
|
||||
it { expect(page).to have_content @build.name }
|
||||
|
|
|
@ -186,7 +186,7 @@ describe 'Filter issues', feature: true do
|
|||
fill_in 'issue_search', with: 'testing'
|
||||
|
||||
page.within '.issues-list' do
|
||||
expect(page).to_not have_selector('.issue')
|
||||
expect(page).not_to have_selector('.issue')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
11
spec/mailers/previews/devise_mailer_preview.rb
Normal file
11
spec/mailers/previews/devise_mailer_preview.rb
Normal file
|
@ -0,0 +1,11 @@
|
|||
class DeviseMailerPreview < ActionMailer::Preview
|
||||
def confirmation_instructions_for_signup
|
||||
user = User.new(name: 'Jane Doe', email: 'signup@example.com')
|
||||
DeviseMailer.confirmation_instructions(user, 'faketoken', {})
|
||||
end
|
||||
|
||||
def confirmation_instructions_for_new_email
|
||||
user = User.last
|
||||
DeviseMailer.confirmation_instructions(user, 'faketoken', {})
|
||||
end
|
||||
end
|
|
@ -12,6 +12,7 @@ describe API::API, api: true do
|
|||
let!(:group2) { create(:group, :private) }
|
||||
let!(:project1) { create(:project, namespace: group1) }
|
||||
let!(:project2) { create(:project, namespace: group2) }
|
||||
let!(:project3) { create(:project, namespace: group1, path: 'test', visibility_level: Gitlab::VisibilityLevel::PRIVATE) }
|
||||
|
||||
before do
|
||||
group1.add_owner(user1)
|
||||
|
@ -147,9 +148,11 @@ describe API::API, api: true do
|
|||
context "when authenticated as user" do
|
||||
it "should return the group's projects" do
|
||||
get api("/groups/#{group1.id}/projects", user1)
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(json_response.length).to eq(1)
|
||||
expect(json_response.first['name']).to eq(project1.name)
|
||||
expect(json_response.length).to eq(2)
|
||||
project_names = json_response.map { |proj| proj['name' ] }
|
||||
expect(project_names).to match_array([project1.name, project3.name])
|
||||
end
|
||||
|
||||
it "should not return a non existing group" do
|
||||
|
@ -162,6 +165,16 @@ describe API::API, api: true do
|
|||
|
||||
expect(response.status).to eq(404)
|
||||
end
|
||||
|
||||
it "should only return projects to which user has access" do
|
||||
project3.team << [user3, :developer]
|
||||
|
||||
get api("/groups/#{group1.id}/projects", user3)
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(json_response.length).to eq(1)
|
||||
expect(json_response.first['name']).to eq(project3.name)
|
||||
end
|
||||
end
|
||||
|
||||
context "when authenticated as admin" do
|
||||
|
@ -181,8 +194,10 @@ describe API::API, api: true do
|
|||
context 'when using group path in URL' do
|
||||
it 'should return any existing group' do
|
||||
get api("/groups/#{group1.path}/projects", admin)
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(json_response.first['name']).to eq(project1.name)
|
||||
project_names = json_response.map { |proj| proj['name' ] }
|
||||
expect(project_names).to match_array([project1.name, project3.name])
|
||||
end
|
||||
|
||||
it 'should not return a non existing group' do
|
||||
|
|
|
@ -42,6 +42,33 @@ describe Projects::ForkService, services: true do
|
|||
expect(@to_project.builds_enabled?).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
context "when project has restricted visibility level" do
|
||||
context "and only one visibility level is restricted" do
|
||||
before do
|
||||
@from_project.update_attributes(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
|
||||
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::INTERNAL])
|
||||
end
|
||||
|
||||
it "creates fork with highest allowed level" do
|
||||
forked_project = fork_project(@from_project, @to_user)
|
||||
|
||||
expect(forked_project.visibility_level).to eq(Gitlab::VisibilityLevel::PUBLIC)
|
||||
end
|
||||
end
|
||||
|
||||
context "and all visibility levels are restricted" do
|
||||
before do
|
||||
stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC, Gitlab::VisibilityLevel::INTERNAL, Gitlab::VisibilityLevel::PRIVATE])
|
||||
end
|
||||
|
||||
it "creates fork with private visibility levels" do
|
||||
forked_project = fork_project(@from_project, @to_user)
|
||||
|
||||
expect(forked_project.visibility_level).to eq(Gitlab::VisibilityLevel::PRIVATE)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe :fork_to_namespace do
|
||||
|
|
Loading…
Reference in a new issue