提交 ab7a2b1b 编写于 作者: R Regis

Merge branch 'master' into auto-pipelines-vue

/coverage-javascript/
/public/
/tmp/
/vendor/
......
{
"extends": "airbnb",
"plugins": [
"filenames"
],
"rules": {
"filenames/match-regex": [2, "^[a-z_]+$"]
},
"globals": {
"$": false,
"_": false,
......
此差异已折叠。
......@@ -19,7 +19,6 @@
- [Technical debt](#technical-debt)
- [Merge requests](#merge-requests)
- [Merge request guidelines](#merge-request-guidelines)
- [Merge request description format](#merge-request-description-format)
- [Contribution acceptance criteria](#contribution-acceptance-criteria)
- [Changes for Stable Releases](#changes-for-stable-releases)
- [Definition of done](#definition-of-done)
......@@ -247,13 +246,7 @@ request is as follows:
1. Fork the project into your personal space on GitLab.com
1. Create a feature branch, branch away from `master`
1. Write [tests](https://gitlab.com/gitlab-org/gitlab-development-kit#running-the-tests) and code
1. Add your changes to the [CHANGELOG.md](CHANGELOG.md):
1. If you are fixing a ~regression issue, you can add your entry to the next
patch release (e.g. `8.12.5` if current version is `8.12.4`)
1. Otherwise, add your entry to the next minor release (e.g. `8.13.0` if
current version is `8.12.4`
1. Please add your entry at a random place among the entries of the targeted
release
1. [Generate a changelog entry with `bin/changelog`][changelog]
1. If you are writing documentation, make sure to follow the
[documentation styleguide][doc-styleguide]
1. If you have multiple commits please combine them into one commit by
......@@ -262,8 +255,11 @@ request is as follows:
1. Submit a merge request (MR) to the `master` branch
1. The MR title should describe the change you want to make
1. The MR description should give a motive for your change and the method you
used to achieve it, see the [merge request description format]
(#merge-request-description-format)
used to achieve it.
1. If you are contributing code, fill in the template already provided in the
"Description" field.
1. If you are contributing documentation, choose `Documentation` from the
"Choose a template" menu and fill in the template.
1. If the MR changes the UI it should include *Before* and *After* screenshots
1. If the MR changes CSS classes please include the list of affected pages,
`grep css-class ./app -R`
......@@ -469,6 +465,7 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[contributor-covenant]: http://contributor-covenant.org
[rss-source]: https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#source-code-layout
[rss-naming]: https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#naming
[changelog]: doc/development/changelog.md "Generate a changelog entry"
[doc-styleguide]: doc/development/doc_styleguide.md "Documentation styleguide"
[scss-styleguide]: doc/development/scss_styleguide.md "SCSS styleguide"
[newlines-styleguide]: doc/development/newlines_styleguide.md "Newlines styleguide"
......
......@@ -51,7 +51,7 @@ gem 'browser', '~> 2.2'
# Extracting information from a git repository
# Provide access to Gitlab::Git library
gem 'gitlab_git', '~> 10.6.8'
gem 'gitlab_git', '~> 10.7.0'
# LDAP Auth
# GitLab fork with several improvements to original library. For full list of changes
......@@ -117,7 +117,7 @@ gem 'truncato', '~> 0.7.8'
gem 'nokogiri', '~> 1.6.7', '>= 1.6.7.2'
# Diffs
gem 'diffy', '~> 3.0.3'
gem 'diffy', '~> 3.1.0'
# Application server
group :unicorn do
......@@ -196,7 +196,7 @@ gem 'loofah', '~> 2.0.3'
gem 'licensee', '~> 8.0.0'
# Protect against bruteforcing
gem 'rack-attack', '~> 4.3.1'
gem 'rack-attack', '~> 4.4.1'
# Ace editor
gem 'ace-rails-ap', '~> 4.1.0'
......
......@@ -180,7 +180,7 @@ GEM
railties
rotp (~> 2.0)
diff-lcs (1.2.5)
diffy (3.0.7)
diffy (3.1.0)
docile (1.1.5)
doorkeeper (4.2.0)
railties (>= 4.2)
......@@ -283,7 +283,7 @@ GEM
mime-types (>= 1.16, < 3)
posix-spawn (~> 0.3)
gitlab-markup (1.5.0)
gitlab_git (10.6.8)
gitlab_git (10.7.0)
activesupport (~> 4.0)
charlock_holmes (~> 0.7.3)
github-linguist (~> 4.7.0)
......@@ -520,7 +520,7 @@ GEM
rack (1.6.4)
rack-accept (0.4.5)
rack (>= 0.4)
rack-attack (4.3.1)
rack-attack (4.4.1)
rack
rack-cors (0.4.0)
rack-mount (0.8.3)
......@@ -847,7 +847,7 @@ DEPENDENCIES
default_value_for (~> 3.0.0)
devise (~> 4.2)
devise-two-factor (~> 3.0.0)
diffy (~> 3.0.3)
diffy (~> 3.1.0)
doorkeeper (~> 4.2.0)
dropzonejs-rails (~> 0.7.1)
email_reply_parser (~> 0.5.8)
......@@ -870,7 +870,7 @@ DEPENDENCIES
github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-markup (~> 1.5.0)
gitlab_git (~> 10.6.8)
gitlab_git (~> 10.7.0)
gitlab_omniauth-ldap (~> 1.2.1)
gollum-lib (~> 4.2)
gollum-rugged_adapter (~> 0.4.2)
......@@ -929,7 +929,7 @@ DEPENDENCIES
poltergeist (~> 1.9.0)
premailer-rails (~> 1.9.0)
pry-rails (~> 0.3.4)
rack-attack (~> 4.3.1)
rack-attack (~> 4.4.1)
rack-cors (~> 0.4.0)
rack-oauth2 (~> 1.2.1)
rails (= 4.2.7.1)
......@@ -998,4 +998,4 @@ DEPENDENCIES
wikicloth (= 0.8.1)
BUNDLED WITH
1.13.3
1.13.5
/* eslint-disable */
// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
// Add new JavaScript code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
......@@ -188,6 +188,7 @@
// Close select2 on escape
});
// Initialize tooltips
$.fn.tooltip.Constructor.DEFAULTS.trigger = 'hover';
$body.tooltip({
selector: '.has-tooltip, [data-toggle="tooltip"]',
placement: function(_, el) {
......
......@@ -15,6 +15,11 @@
return $("body").on("click", ".js-details-expand", function(e) {
$(this).next('.js-details-content').removeClass("hide");
$(this).hide();
var truncatedItem = $(this).siblings('.js-details-short');
if (truncatedItem.length) {
truncatedItem.addClass("hide");
}
return e.preventDefault();
});
});
......
......@@ -22,7 +22,7 @@
fallbackClass: 'is-dragging',
fallbackOnBody: true,
ghostClass: 'is-ghost',
filter: '.has-tooltip, .btn',
filter: '.board-delete, .btn',
delay: gl.issueBoards.touchEnabled ? 100 : 50,
scrollSensitivity: gl.issueBoards.touchEnabled ? 60 : 100,
scrollSpeed: 20,
......
/* eslint-disable */
// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
// Add new JavaScript code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
......
......@@ -238,8 +238,11 @@
_this.expandViewContainer();
}
_this.diffsLoaded = true;
_this.scrollToElement("#diffs");
_this.highlighSelectedLine();
var anchoredDiff = gl.utils.getLocationHash();
if (anchoredDiff) _this.openAnchoredDiff(anchoredDiff, function() {
_this.scrollToElement("#diffs");
_this.highlighSelectedLine();
});
_this.filesCommentButton = $('.files .diff-file').filesCommentButton();
return $(document).off('click', '.diff-line-num a').on('click', '.diff-line-num a', function(e) {
e.preventDefault();
......@@ -252,6 +255,17 @@
});
};
MergeRequestTabs.prototype.openAnchoredDiff = function(anchoredDiff, cb) {
var diffTitle = $('#file-path-' + anchoredDiff);
var diffFile = diffTitle.closest('.diff-file');
var nothingHereBlock = $('.nothing-here-block:visible', diffFile);
if (nothingHereBlock.length) {
diffFile.singleFileDiff(true, cb);
} else {
cb();
}
};
MergeRequestTabs.prototype.highlighSelectedLine = function() {
var $diffLine, diffLineTop, hashClassString, locationHash, navBarHeight;
$('.hll').removeClass('hll');
......
/* eslint-disable */
// This is a manifest file that'll be compiled into including all the files listed below.
// Add new JavaScript/Coffee code in separate files in this directory and they'll automatically
// Add new JavaScript code in separate files in this directory and they'll automatically
// be included in the compiled file accessible from http://example.com/assets/application.js
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// the compiled file.
......
......@@ -13,7 +13,7 @@
COLLAPSED_HTML = '<div class="nothing-here-block diff-collapsed">This diff is collapsed. <a class="click-to-expand">Click to expand it.</a></div>';
function SingleFileDiff(file) {
function SingleFileDiff(file, forceLoad, cb) {
this.file = file;
this.toggleDiff = bind(this.toggleDiff, this);
this.content = $('.diff-content', this.file);
......@@ -32,9 +32,12 @@
this.$toggleIcon.addClass('fa-caret-down');
}
$('.file-title, .click-to-expand', this.file).on('click', this.toggleDiff);
if (forceLoad) {
this.toggleDiff(null, cb);
}
}
SingleFileDiff.prototype.toggleDiff = function(e) {
SingleFileDiff.prototype.toggleDiff = function(e, cb) {
var $target = $(e.target);
if (!$target.hasClass('file-title') && !$target.hasClass('click-to-expand') && !$target.hasClass('diff-toggle-caret')) return;
this.isOpen = !this.isOpen;
......@@ -54,11 +57,11 @@
}
} else {
this.$toggleIcon.addClass('fa-caret-down').removeClass('fa-caret-right');
return this.getContentHTML();
return this.getContentHTML(cb);
}
};
SingleFileDiff.prototype.getContentHTML = function() {
SingleFileDiff.prototype.getContentHTML = function(cb) {
this.collapsedContent.hide();
this.loadingContent.show();
$.get(this.diffForPath, (function(_this) {
......@@ -76,6 +79,8 @@
if (typeof DiffNotesApp !== 'undefined') {
DiffNotesApp.compileComponents();
}
if (cb) cb();
};
})(this));
};
......@@ -84,10 +89,10 @@
})();
$.fn.singleFileDiff = function() {
$.fn.singleFileDiff = function(forceLoad, cb) {
return this.each(function() {
if (!$.data(this, 'singleFileDiff')) {
return $.data(this, 'singleFileDiff', new SingleFileDiff(this));
if (!$.data(this, 'singleFileDiff') || forceLoad) {
return $.data(this, 'singleFileDiff', new SingleFileDiff(this, forceLoad, cb));
}
});
};
......
......@@ -11,11 +11,9 @@
$this.parent().find('.star-count').text(data.star_count);
if (isStarred) {
$starSpan.removeClass('starred').text('Star');
gl.utils.updateTooltipTitle($this, 'Star project');
$starIcon.removeClass('fa-star').addClass('fa-star-o');
} else {
$starSpan.addClass('starred').text('Unstar');
gl.utils.updateTooltipTitle($this, 'Unstar project');
$starIcon.removeClass('fa-star-o').addClass('fa-star');
}
};
......
.avatar {
@mixin avatar-size($size, $margin-right) {
width: $size;
height: $size;
margin-right: $margin-right;
}
.avatar-container {
float: left;
margin-right: 12px;
margin-right: 15px;
border-radius: $avatar_radius;
border: 1px solid rgba(0, 0, 0, .1);
&.s16 { @include avatar-size(16px, 6px); }
&.s20 { @include avatar-size(20px, 7px); }
&.s24 { @include avatar-size(24px, 8px); }
&.s26 { @include avatar-size(26px, 8px); }
&.s32 { @include avatar-size(32px, 10px); }
&.s36 { @include avatar-size(36px, 10px); }
&.s40 { @include avatar-size(40px, 10px); }
&.s46 { @include avatar-size(46px, 15px); }
&.s48 { @include avatar-size(48px, 10px); }
&.s60 { @include avatar-size(60px, 12px); }
&.s70 { @include avatar-size(70px, 14px); }
&.s90 { @include avatar-size(90px, 15px); }
&.s110 { @include avatar-size(110px, 15px); }
&.s140 { @include avatar-size(140px, 15px); }
&.s160 { @include avatar-size(160px, 20px); }
}
.avatar {
@extend .avatar-container;
width: 40px;
height: 40px;
padding: 0;
border-radius: $avatar_radius;
border: 1px solid rgba(0, 0, 0, .1);
&.avatar-inline {
float: none;
......@@ -20,22 +45,6 @@
border-radius: 0;
border: none;
}
&.s16 { width: 16px; height: 16px; margin-right: 6px; }
&.s20 { width: 20px; height: 20px; margin-right: 7px; }
&.s24 { width: 24px; height: 24px; margin-right: 8px; }
&.s26 { width: 26px; height: 26px; margin-right: 8px; }
&.s32 { width: 32px; height: 32px; margin-right: 10px; }
&.s36 { width: 36px; height: 36px; margin-right: 10px; }
&.s40 { width: 40px; height: 40px; margin-right: 10px; }
&.s46 { width: 46px; height: 46px; margin-right: 15px; }
&.s48 { width: 48px; height: 48px; margin-right: 10px; }
&.s60 { width: 60px; height: 60px; margin-right: 12px; }
&.s70 { width: 70px; height: 70px; margin-right: 14px; }
&.s90 { width: 90px; height: 90px; margin-right: 15px; }
&.s110 { width: 110px; height: 110px; margin-right: 15px; }
&.s140 { width: 140px; height: 140px; margin-right: 20px; }
&.s160 { width: 160px; height: 160px; margin-right: 20px; }
}
.identicon {
......@@ -54,3 +63,17 @@
&.s140 { font-size: 72px; line-height: 138px; }
&.s160 { font-size: 96px; line-height: 158px; }
}
.image-container {
@extend .avatar-container;
overflow: hidden;
display: flex;
.avatar {
border-radius: 0;
border: none;
height: auto;
margin: 0;
align-self: center;
}
}
\ No newline at end of file
......@@ -216,7 +216,7 @@
svg,
.fa {
&:not(:last-child) {
margin-right: 3px;
margin-right: 5px;
}
}
}
......
......@@ -21,57 +21,66 @@
background: $color-darker;
}
.nav-sidebar li {
a {
color: $color-light;
&:hover,
&:focus,
&:active {
background: $color-dark;
}
.sidebar-header,
.sidebar-action-buttons {
color: $color-light;
background-color: lighten($color-darker, 5%);
}
i {
.nav-sidebar {
li {
a {
color: $color-light;
}
path,
polygon {
fill: $color-light;
}
.count {
color: $color-light;
background: $color-dark;
&:hover,
&:focus,
&:active {
background: $color-dark;
}
i {
color: $color-light;
}
path,
polygon {
fill: $color-light;
}
.count {
color: $color-light;
background: $color-dark;
}
svg {
position: relative;
top: 3px;
}
}
svg {
position: relative;
top: 3px;
&.separate-item {
border-top: 1px solid $color;
}
}
&.separate-item {
border-top: 1px solid $color;
}
&.active a {
color: $white-light;
background: $color-dark;
&.active a {
color: $white-light;
background: $color-dark;
&.no-highlight {
border: none;
}
&.no-highlight {
border: none;
}
i {
color: $white-light;
}
i {
color: $white-light;
}
path,
polygon {
fill: $white-light;
path,
polygon {
fill: $white-light;
}
}
}
}
}
}
......
......@@ -49,12 +49,16 @@ header {
font-size: 18px;
padding: 0;
margin: ($header-height - 28) / 2 0;
margin-left: 10px;
margin-left: 8px;
height: 28px;
min-width: 28px;
line-height: 28px;
text-align: center;
&.header-user-dropdown-toggle {
margin-left: 14px;
}
&:hover,
&:focus,
&:active {
......
......@@ -142,10 +142,6 @@ ul.content-list {
}
}
.avatar {
margin-right: 15px;
}
.controls {
float: right;
......
......@@ -7,8 +7,70 @@
.pagination {
padding: 0;
}
.gap,
.gap:hover {
background-color: $gray-light;
padding: $gl-vert-padding;
cursor: default;
}
}
.panel > .gl-pagination {
margin: 0;
}
/**
* Extra-small screen pagination.
*/
@media (max-width: 320px) {
.gl-pagination {
.first,
.last {
display: none;
}
.page {
display: none;
&.active {
display: inline;
}
}
}
}
/**
* Small screen pagination
*/
@media (max-width: $screen-xs) {
.gl-pagination {
.pagination li a {
padding: 6px 10px;
}
.page {
display: none;
&.active {
display: inline;
}
}
}
}
/**
* Medium screen pagination
*/
@media (min-width: $screen-xs) and (max-width: $screen-md-max) {
.gl-pagination {
.page {
display: none;
&.active,
&.sibling {
display: inline;
}
}
}
}
......@@ -59,6 +59,11 @@
padding: 0 !important;
}
.sidebar-header {
padding: 11px 22px 12px;
font-size: 20px;
}
li {
&.separate-item {
padding-top: 10px;
......
......@@ -90,6 +90,8 @@ $table-border-color: #f0f0f0;
$background-color: $gray-light;
$dark-background-color: #f5f5f5;
$table-text-gray: #8f8f8f;
$widget-expand-item: #e8f2f7;
$widget-inner-border: #eef0f2;
/*
* Text
......
.awards {
.emoji-icon {
width: 20px;
height: 20px;
width: 19px;
height: 19px;
}
}
......@@ -94,7 +94,7 @@
.award-control {
margin: 3px 5px 3px 0;
padding: 6px 5px;
padding: 5px 6px;
outline: 0;
&:hover,
......@@ -127,7 +127,7 @@
.award-control-icon {
float: left;
margin-right: 5px;
font-size: 20px;
font-size: 19px;
}
.award-control-icon-loading {
......
......@@ -12,6 +12,10 @@
opacity: 1!important;
* {
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
// !important to make sure no style can override this when dragging
cursor: -webkit-grabbing!important;
cursor: grabbing!important;
......@@ -45,11 +49,6 @@
.page-with-sidebar {
padding-bottom: 0;
}
.issues-filters {
position: relative;
z-index: 999999;
}
}
.boards-app {
......
......@@ -52,10 +52,25 @@
.build-header {
position: relative;
padding-right: 40px;
padding: 0;
display: flex;
min-height: 58px;
align-items: center;
@media (min-width: $screen-sm-min) {
padding-right: 0;
.btn-inverted {
@include btn-outline($white-light, $blue-normal, $blue-normal, $blue-light, $white-light, $blue-light);
}
@media (max-width: $screen-sm-max) {
padding-right: 40px;
.btn-inverted {
display: none;
}
}
.header-content {
flex: 1;
}
a {
......@@ -137,10 +152,15 @@
.retry-link {
color: $gl-link-color;
display: none;
&:hover {
text-decoration: underline;
}
@media (max-width: $screen-sm-max) {
display: block;
}
}
.stage-item {
......
......@@ -33,10 +33,8 @@
&.commit-info-row-header {
line-height: 34px;
@media (min-width: $screen-sm-min) {
margin-bottom: 0;
}
padding: 10px 0;
margin-bottom: 0;
.commit-options-dropdown-caret {
@media (max-width: $screen-sm) {
......@@ -80,6 +78,58 @@
}
}
.js-details-expand {
&:hover {
text-decoration: none;
}
}
.commit-info-widget {
background: $background-color;
color: $gl-gray;
border: 1px solid $border-color;
border-radius: $border-radius-default;
.widget-row {
padding: $gl-padding;
&:not(:last-of-type) {
border-bottom: 1px solid $widget-inner-border;
}
&.branch-info {
.monospace,
.commit-info {
margin-left: 4px;
}
}
}
.icon-container {
display: inline-block;
margin-right: 8px;
svg {
position: relative;
top: 2px;
height: 16px;
width: 16px;
}
&.commit-icon {
svg {
path {
fill: $gl-text-color;
}
}
}
}
.label.label-gray {
background-color: $widget-expand-item;
}
}
.ci-status-link {
svg {
overflow: visible;
......@@ -88,6 +138,7 @@
.commit-box {
border-top: 1px solid $border-color;
padding: $gl-padding 0;
.commit-title {
margin: 0;
......@@ -138,6 +189,9 @@
}
.commit-action-buttons {
position: relative;
top: -1px;
i {
color: $gl-icon-color;
font-size: 13px;
......
......@@ -33,21 +33,22 @@
color: $gl-dark-link-color;
}
.text-expander {
display: inline-block;
background: $gray-light;
color: $gl-placeholder-color;
padding: 0 5px;
cursor: pointer;
border: 1px solid $border-gray-dark;
border-radius: $border-radius-default;
margin-left: 5px;
line-height: 1;
&:hover {
background-color: darken($gray-light, 10%);
text-decoration: none;
}
}
.text-expander {
display: inline-block;
background: $gray-light;
color: $gl-placeholder-color;
padding: 0 5px;
cursor: pointer;
border: 1px solid $border-gray-dark;
border-radius: $border-radius-default;
margin-left: 5px;
line-height: 1;
&:hover {
background-color: darken($gray-light, 10%);
text-decoration: none;
}
}
......
......@@ -36,10 +36,6 @@
}
}
.dash-project-avatar {
float: left;
}
.dash-project-access-icon {
float: left;
margin-right: 5px;
......
......@@ -3,12 +3,14 @@
}
.dashboard .side .panel .panel-heading .input-group {
.form-control {
height: 42px;
}
}
.group-row {
.stats {
float: right;
line-height: $list-text-height;
......@@ -21,12 +23,14 @@
}
.ldap-group-links {
.form-actions {
margin-bottom: $gl-padding;
}
}
.groups-cover-block {
.container-fluid {
position: relative;
}
......@@ -41,9 +45,14 @@
background-color: $background-color;
}
}
.group-avatar {
border: 0;
}
}
.groups-header {
@media (min-width: $screen-sm-min) {
.nav-links {
width: 35%;
......
......@@ -54,7 +54,6 @@
margin: 0 0 10px;
}
.login-footer {
margin-top: 10px;
......
......@@ -60,7 +60,7 @@
}
.ci_widget {
border-bottom: 1px solid #eef0f2;
border-bottom: 1px solid $widget-inner-border;
svg {
margin-right: 4px;
......
......@@ -105,11 +105,6 @@ ul.notes {
padding: 2px;
margin-top: 10px;
}
.award-control {
font-size: 13px;
padding: 2px 5px;
}
}
.note-header {
......
......@@ -96,8 +96,8 @@
.project-avatar {
float: none;
margin-left: auto;
margin-right: auto;
margin: 0 auto;
border: none;
&.identicon {
border-radius: 50%;
......
......@@ -161,3 +161,63 @@
}
}
}
.todos-empty {
display: -webkit-flex;
display: flex;
-webkit-flex-direction: column;
flex-direction: column;
max-width: 900px;
margin-left: auto;
margin-right: auto;
@media (min-width: $screen-sm-min) {
-webkit-flex-direction: row;
flex-direction: row;
padding-top: 80px;
}
}
.todos-empty-content {
-webkit-align-self: center;
align-self: center;
max-width: 480px;
margin-right: 20px;
}
.todos-empty-hero {
width: 200px;
margin-left: auto;
margin-right: auto;
@media (min-width: $screen-sm-min) {
width: 300px;
margin-right: 0;
-webkit-order: 2;
order: 2;
}
}
.todos-all-done {
padding-top: 20px;
@media (min-width: $screen-sm-min) {
padding-top: 50px;
}
> svg {
display: block;
max-width: 300px;
margin: 0 auto 20px;
}
p {
max-width: 470px;
margin-left: auto;
margin-right: auto;
}
a {
font-weight: 600;
}
}
......@@ -3,7 +3,7 @@ class Admin::UsersController < Admin::ApplicationController
def index
@users = User.order_name_asc.filter(params[:filter])
@users = @users.search(params[:name]) if params[:name].present?
@users = @users.search_with_secondary_emails(params[:search_query]) if params[:search_query].present?
@users = @users.sort(@sort = params[:sort])
@users = @users.page(params[:page])
end
......
......@@ -126,7 +126,7 @@ class Projects::LabelsController < Projects::ApplicationController
alias_method :subscribable_resource, :label
def find_labels
@available_labels ||= LabelsFinder.new(current_user, project_id: @project.id).execute.includes(:priorities)
@available_labels ||= LabelsFinder.new(current_user, project_id: @project.id).execute
end
def authorize_admin_labels!
......
......@@ -25,18 +25,15 @@ class Projects::ProjectMembersController < Projects::ApplicationController
end
def create
if params[:user_ids].blank?
return redirect_to(namespace_project_project_members_path(@project.namespace, @project), alert: 'No users or groups specified.')
end
status = Members::CreateService.new(@project, current_user, params).execute
@project.team.add_users(
params[:user_ids].split(','),
params[:access_level],
expires_at: params[:expires_at],
current_user: current_user
)
redirect_url = namespace_project_project_members_path(@project.namespace, @project)
redirect_to namespace_project_project_members_path(@project.namespace, @project), notice: 'Users were successfully added.'
if status
redirect_to redirect_url, notice: 'Users were successfully added.'
else
redirect_to redirect_url, alert: 'No users or groups specified.'
end
end
def update
......
......@@ -23,7 +23,7 @@ class Projects::TagsController < Projects::ApplicationController
return render_404 unless @tag
@release = @project.releases.find_or_initialize_by(tag: @tag.name)
@commit = @repository.commit(@tag.target)
@commit = @repository.commit(@tag.dereferenced_target)
end
def create
......
......@@ -289,7 +289,8 @@ class ProjectsController < Projects::ApplicationController
render 'projects/empty' if @project.empty_repo?
else
if @project.wiki_enabled?
@wiki_home = @project.wiki.find_page('home', params[:version_id])
@project_wiki = @project.wiki
@wiki_home = @project_wiki.find_page('home', params[:version_id])
elsif @project.feature_available?(:issues, current_user)
@issues = issues_collection
@issues = @issues.page(params[:page])
......
......@@ -126,7 +126,7 @@ class IssuableFinder
@labels =
if labels? && !filter_by_no_label?
LabelsFinder.new(current_user, project_ids: projects, title: label_names).execute
LabelsFinder.new(current_user, project_ids: projects, title: label_names).execute(skip_authorization: true)
else
Label.none
end
......@@ -273,7 +273,7 @@ class IssuableFinder
items = items.with_label(label_names, params[:sort])
if projects
label_ids = LabelsFinder.new(current_user, project_ids: projects).execute.select(:id)
label_ids = LabelsFinder.new(current_user, project_ids: projects).execute(skip_authorization: true).select(:id)
items = items.where(labels: { id: label_ids })
end
end
......
......@@ -16,13 +16,14 @@ module ButtonHelper
# See http://clipboardjs.com/#usage
def clipboard_button(data = {})
css_class = data[:class] || 'btn-clipboard btn-transparent'
title = data[:title] || 'Copy to Clipboard'
data = { toggle: 'tooltip', placement: 'bottom', container: 'body' }.merge(data)
content_tag :button,
icon('clipboard'),
class: "btn #{css_class}",
data: data,
type: :button,
title: 'Copy to Clipboard'
title: title
end
def http_clone_button(project, placement = 'right', append_link: true)
......
......@@ -39,6 +39,12 @@ module EventsHelper
end
end
def event_filter_visible(feature_key)
return true unless @project
@project.feature_available?(feature_key, current_user)
end
def event_preposition(event)
if event.push? || event.commented? || event.target
"at"
......
......@@ -174,10 +174,14 @@ module ProjectsHelper
nav_tabs << :merge_requests
end
if can?(current_user, :read_build, project)
if can?(current_user, :read_pipeline, project)
nav_tabs << :pipelines
end
if can?(current_user, :read_build, project)
nav_tabs << :builds
end
if Gitlab.config.registry.enabled && can?(current_user, :read_container_image, project)
nav_tabs << :container_registry
end
......
......@@ -31,7 +31,7 @@ module ProjectFeaturesCompatibility
def write_feature_attribute(field, value)
build_project_feature unless project_feature
access_level = value == "true" ? ProjectFeature::ENABLED : ProjectFeature::DISABLED
access_level = Gitlab::Utils.to_boolean(value) ? ProjectFeature::ENABLED : ProjectFeature::DISABLED
project_feature.update_attribute(field, access_level)
end
end
class Event < ActiveRecord::Base
include Sortable
default_scope { where.not(author_id: nil) }
default_scope { reorder(nil).where.not(author_id: nil) }
CREATED = 1
UPDATED = 2
......
......@@ -5,6 +5,10 @@ class GroupLabel < Label
alias_attribute :subject, :group
def subject_foreign_key
'group_id'
end
def to_reference(source_project = nil, target_project = nil, format: :id)
super(source_project, target_project, format: format)
end
......
......@@ -92,16 +92,23 @@ class Label < ActiveRecord::Base
nil
end
def open_issues_count(user = nil, project = nil)
issues_count(user, project_id: project.try(:id) || project_id, state: 'opened')
def open_issues_count(user = nil)
issues_count(user, state: 'opened')
end
def closed_issues_count(user = nil, project = nil)
issues_count(user, project_id: project.try(:id) || project_id, state: 'closed')
def closed_issues_count(user = nil)
issues_count(user, state: 'closed')
end
def open_merge_requests_count(user = nil, project = nil)
merge_requests_count(user, project_id: project.try(:id) || project_id, state: 'opened')
def open_merge_requests_count(user = nil)
params = {
subject_foreign_key => subject.id,
label_name: title,
scope: 'all',
state: 'opened'
}
MergeRequestsFinder.new(user, params.with_indifferent_access).execute.count
end
def prioritize!(project, value)
......@@ -167,15 +174,8 @@ class Label < ActiveRecord::Base
end
def issues_count(user, params = {})
IssuesFinder.new(user, params.reverse_merge(label_name: title, scope: 'all'))
.execute
.count
end
def merge_requests_count(user, params = {})
MergeRequestsFinder.new(user, params.reverse_merge(label_name: title, scope: 'all'))
.execute
.count
params.merge!(subject_foreign_key => subject.id, label_name: title, scope: 'all')
IssuesFinder.new(user, params.with_indifferent_access).execute.count
end
def label_format_reference(format = :id)
......
......@@ -17,4 +17,10 @@ class LfsObject < ActiveRecord::Base
def project_allowed_access?(project)
projects.exists?(storage_project(project).id)
end
def self.destroy_unreferenced
joins("LEFT JOIN lfs_objects_projects ON lfs_objects_projects.lfs_object_id = #{table_name}.id")
.where(lfs_objects_projects: { id: nil })
.destroy_all
end
end
......@@ -30,6 +30,11 @@ class Project < ActiveRecord::Base
default_value_for :container_registry_enabled, gitlab_config_features.container_registry
default_value_for(:repository_storage) { current_application_settings.repository_storage }
default_value_for(:shared_runners_enabled) { current_application_settings.shared_runners_enabled }
default_value_for :issues_enabled, gitlab_config_features.issues
default_value_for :merge_requests_enabled, gitlab_config_features.merge_requests
default_value_for :builds_enabled, gitlab_config_features.builds
default_value_for :wiki_enabled, gitlab_config_features.wiki
default_value_for :snippets_enabled, gitlab_config_features.snippets
after_create :ensure_dir_exist
after_create :create_project_feature, unless: :project_feature
......@@ -390,7 +395,7 @@ class Project < ActiveRecord::Base
end
def group_ids
joins(:namespace).where(namespaces: { type: 'Group' }).pluck(:namespace_id)
joins(:namespace).where(namespaces: { type: 'Group' }).select(:namespace_id)
end
end
......
......@@ -12,6 +12,10 @@ class ProjectLabel < Label
alias_attribute :subject, :project
def subject_foreign_key
'project_id'
end
def to_reference(target_project = nil, format: :id)
super(project, target_project, format: format)
end
......
......@@ -237,7 +237,7 @@ class JiraService < IssueTrackerService
end
def resource_url(resource)
"#{Settings.gitlab['url'].chomp("/")}#{resource}"
"#{Settings.gitlab.base_url.chomp("/")}#{resource}"
end
def build_entity_url(entity_name, entity_id)
......
......@@ -195,7 +195,7 @@ class Repository
before_remove_branch
branch = find_branch(branch_name)
oldrev = branch.try(:target).try(:id)
oldrev = branch.try(:dereferenced_target).try(:id)
newrev = Gitlab::Git::BLANK_SHA
ref = Gitlab::Git::BRANCH_REF_PREFIX + branch_name
......@@ -311,10 +311,10 @@ class Repository
# Rugged seems to throw a `ReferenceError` when given branch_names rather
# than SHA-1 hashes
number_commits_behind = raw_repository.
count_commits_between(branch.target.sha, root_ref_hash)
count_commits_between(branch.dereferenced_target.sha, root_ref_hash)
number_commits_ahead = raw_repository.
count_commits_between(root_ref_hash, branch.target.sha)
count_commits_between(root_ref_hash, branch.dereferenced_target.sha)
{ behind: number_commits_behind, ahead: number_commits_ahead }
end
......@@ -696,11 +696,11 @@ class Repository
branches.sort_by(&:name)
when 'updated_desc'
branches.sort do |a, b|
commit(b.target).committed_date <=> commit(a.target).committed_date
commit(b.dereferenced_target).committed_date <=> commit(a.dereferenced_target).committed_date
end
when 'updated_asc'
branches.sort do |a, b|
commit(a.target).committed_date <=> commit(b.target).committed_date
commit(a.dereferenced_target).committed_date <=> commit(b.dereferenced_target).committed_date
end
else
branches
......@@ -875,7 +875,7 @@ class Repository
branch = find_branch(ref)
if branch
last_commit = branch.target
last_commit = branch.dereferenced_target
index.read_tree(last_commit.raw_commit.tree)
parents = [last_commit.sha]
end
......@@ -962,7 +962,7 @@ class Repository
end
def revert(user, commit, base_branch, revert_tree_id = nil)
source_sha = find_branch(base_branch).target.sha
source_sha = find_branch(base_branch).dereferenced_target.sha
revert_tree_id ||= check_revert_content(commit, base_branch)
return false unless revert_tree_id
......@@ -979,7 +979,7 @@ class Repository
end
def cherry_pick(user, commit, base_branch, cherry_pick_tree_id = nil)
source_sha = find_branch(base_branch).target.sha
source_sha = find_branch(base_branch).dereferenced_target.sha
cherry_pick_tree_id ||= check_cherry_pick_content(commit, base_branch)
return false unless cherry_pick_tree_id
......@@ -1008,7 +1008,7 @@ class Repository
end
def check_revert_content(commit, base_branch)
source_sha = find_branch(base_branch).target.sha
source_sha = find_branch(base_branch).dereferenced_target.sha
args = [commit.id, source_sha]
args << { mainline: 1 } if commit.merge_commit?
......@@ -1022,7 +1022,7 @@ class Repository
end
def check_cherry_pick_content(commit, base_branch)
source_sha = find_branch(base_branch).target.sha
source_sha = find_branch(base_branch).dereferenced_target.sha
args = [commit.id, source_sha]
args << 1 if commit.merge_commit?
......@@ -1095,7 +1095,7 @@ class Repository
if rugged.lookup(newrev).parent_ids.empty? || target_branch.nil?
oldrev = Gitlab::Git::BLANK_SHA
else
oldrev = rugged.merge_base(newrev, target_branch.target.sha)
oldrev = rugged.merge_base(newrev, target_branch.dereferenced_target.sha)
end
GitHooksService.new.execute(current_user, path_to_repo, oldrev, newrev, ref) do
......@@ -1155,7 +1155,7 @@ class Repository
end
def tags_sorted_by_committed_date
tags.sort_by { |tag| tag.target.committed_date }
tags.sort_by { |tag| tag.dereferenced_target.committed_date }
end
def keep_around_ref_name(sha)
......
......@@ -258,6 +258,24 @@ class User < ActiveRecord::Base
)
end
# searches user by given pattern
# it compares name, email, username fields and user's secondary emails with given pattern
# This method uses ILIKE on PostgreSQL and LIKE on MySQL.
def search_with_secondary_emails(query)
table = arel_table
email_table = Email.arel_table
pattern = "%#{query}%"
matched_by_emails_user_ids = email_table.project(email_table[:user_id]).where(email_table[:email].matches(pattern))
where(
table[:name].matches(pattern).
or(table[:email].matches(pattern)).
or(table[:username].matches(pattern)).
or(table[:id].in(matched_by_emails_user_ids))
)
end
def by_login(login)
return nil unless login
......
......@@ -2,11 +2,11 @@ class ProjectPolicy < BasePolicy
def rules
team_access!(user)
owner = user.admin? ||
project.owner == user ||
owner = project.owner == user ||
(project.group && project.group.has_owner?(user))
owner_access! if owner
owner_access! if user.admin? || owner
team_member_owner_access! if owner
if project.public? || (project.internal? && !user.external?)
guest_access!
......@@ -16,7 +16,7 @@ class ProjectPolicy < BasePolicy
can! :read_build if project.public_builds?
if project.request_access_enabled &&
!(owner || project.team.member?(user) || project_group_member?(user))
!(owner || user.admin? || project.team.member?(user) || project_group_member?(user))
can! :request_access
end
end
......@@ -135,6 +135,10 @@ class ProjectPolicy < BasePolicy
can! :destroy_issue
end
def team_member_owner_access!
team_member_reporter_access!
end
# Push abilities on the users team role
def team_access!(user)
access = project.team.max_member_access(user.id)
......
......@@ -42,7 +42,7 @@ class DeleteBranchService < BaseService
Gitlab::DataBuilder::Push.build(
project,
current_user,
branch.target.sha,
branch.dereferenced_target.sha,
Gitlab::Git::BLANK_SHA,
"#{Gitlab::Git::BRANCH_REF_PREFIX}#{branch.name}",
[])
......
......@@ -36,7 +36,7 @@ class DeleteTagService < BaseService
Gitlab::DataBuilder::Push.build(
project,
current_user,
tag.target.sha,
tag.dereferenced_target.sha,
Gitlab::Git::BLANK_SHA,
"#{Gitlab::Git::TAG_REF_PREFIX}#{tag.name}",
[])
......
......@@ -27,8 +27,8 @@ class GitTagPushService < BaseService
tag_name = Gitlab::Git.ref_name(params[:ref])
tag = project.repository.find_tag(tag_name)
if tag && tag.object_sha == params[:newrev]
commit = project.commit(tag.target)
if tag && tag.target == params[:newrev]
commit = project.commit(tag.dereferenced_target)
commits = [commit].compact
message = tag.message
end
......
module Members
class CreateService < BaseService
def execute
return false if params[:user_ids].blank?
project.team.add_users(
params[:user_ids].split(','),
params[:access_level],
expires_at: params[:expires_at],
current_user: current_user
)
true
end
end
end
......@@ -13,20 +13,8 @@ module MergeRequests
merge_request.target_project ||= (project.forked_from_project || project)
merge_request.target_branch ||= merge_request.target_project.default_branch
if merge_request.target_branch.blank? || merge_request.source_branch.blank?
message =
if params[:source_branch] || params[:target_branch]
"You must select source and target branch"
end
return build_failed(merge_request, message)
end
if merge_request.source_project == merge_request.target_project &&
merge_request.target_branch == merge_request.source_branch
return build_failed(merge_request, 'You must select different branches')
end
messages = validate_branches(merge_request)
return build_failed(merge_request, messages) unless messages.empty?
compare = CompareService.new.execute(
merge_request.source_project,
......@@ -43,6 +31,34 @@ module MergeRequests
private
def validate_branches(merge_request)
messages = []
if merge_request.target_branch.blank? || merge_request.source_branch.blank?
messages <<
if params[:source_branch] || params[:target_branch]
"You must select source and target branch"
end
end
if merge_request.source_project == merge_request.target_project &&
merge_request.target_branch == merge_request.source_branch
messages << 'You must select different branches'
end
# See if source and target branches exist
unless merge_request.source_project.commit(merge_request.source_branch)
messages << "Source branch \"#{merge_request.source_branch}\" does not exist"
end
unless merge_request.target_project.commit(merge_request.target_branch)
messages << "Target branch \"#{merge_request.target_branch}\" does not exist"
end
messages
end
# When your branch name starts with an iid followed by a dash this pattern will be
# interpreted as the user wants to close that issue on this project.
#
......@@ -91,8 +107,10 @@ module MergeRequests
merge_request
end
def build_failed(merge_request, message)
merge_request.errors.add(:base, message) unless message.nil?
def build_failed(merge_request, messages)
messages.compact.each do |message|
merge_request.errors.add(:base, message)
end
merge_request.compare_commits = []
merge_request.can_be_created = false
merge_request
......
......@@ -16,7 +16,8 @@
%span.visibility-icon.has-tooltip{data: { container: 'body', placement: 'left' }, title: visibility_icon_description(group)}
= visibility_level_icon(group.visibility_level, fw: false)
= image_tag group_icon(group), class: "avatar s40 hidden-xs"
.image-container.s40
= image_tag group_icon(group), class: "avatar s40 hidden-xs"
.title
= link_to [:admin, group], class: 'group-name' do
= group.name
......
......@@ -13,7 +13,8 @@
Group info:
%ul.well-list
%li
= image_tag group_icon(@group), class: "avatar s60"
.image-container.s60
= image_tag group_icon(@group), class: "avatar s60"
%li
%span.light Name:
%strong= @group.name
......
......@@ -76,7 +76,8 @@
.title
= link_to [:admin, project.namespace.becomes(Namespace), project] do
.dash-project-avatar
= project_icon(project, alt: '', class: 'avatar project-avatar s40')
.image-container.s40
= project_icon(project, alt: '', class: 'avatar project-avatar s40')
%span.project-full-name
%span.namespace-name
- if project.namespace
......
......@@ -10,7 +10,7 @@
= hidden_field_tag "filter", h(params[:filter])
.search-holder
.search-field-holder
= search_field_tag :name, params[:name], placeholder: 'Search by name, email or username', class: 'form-control search-text-input js-search-input', spellcheck: false
= search_field_tag :search_query, params[:search_query], placeholder: 'Search by name, email or username', class: 'form-control search-text-input js-search-input', spellcheck: false
= icon("search", class: "search-icon")
.dropdown
- toggle_text = if @sort.present? then sort_options_hash[@sort] else sort_title_name end
......
- page_title "Todos"
- header_title "Todos", dashboard_todos_path
.top-area
%ul.nav-links
- todo_pending_active = ('active' if params[:state].blank? || params[:state] == 'pending')
%li{class: "todos-pending #{todo_pending_active}"}
= link_to todos_filter_path(state: 'pending') do
%span
To do
%span.badge
= number_with_delimiter(todos_pending_count)
- todo_done_active = ('active' if params[:state] == 'done')
%li{class: "todos-done #{todo_done_active}"}
= link_to todos_filter_path(state: 'done') do
%span
Done
%span.badge
= number_with_delimiter(todos_done_count)
- if current_user.todos.any?
.top-area
%ul.nav-links
- todo_pending_active = ('active' if params[:state].blank? || params[:state] == 'pending')
%li{class: "todos-pending #{todo_pending_active}"}
= link_to todos_filter_path(state: 'pending') do
%span
To do
%span.badge
= number_with_delimiter(todos_pending_count)
- todo_done_active = ('active' if params[:state] == 'done')
%li{class: "todos-done #{todo_done_active}"}
= link_to todos_filter_path(state: 'done') do
%span
Done
%span.badge
= number_with_delimiter(todos_done_count)
.nav-controls
- if @todos.any?(&:pending?)
= link_to destroy_all_dashboard_todos_path(todos_filter_params), class: 'btn btn-loading js-todos-mark-all', method: :delete do
Mark all as done
= icon('spinner spin')
.nav-controls
- if @todos.any?(&:pending?)
= link_to destroy_all_dashboard_todos_path(todos_filter_params), class: 'btn btn-loading js-todos-mark-all', method: :delete do
Mark all as done
= icon('spinner spin')
.todos-filters
.row-content-block.second-block
= form_tag todos_filter_path(without: [:project_id, :author_id, :type, :action_id]), method: :get, class: 'filter-form' do
.filter-item.inline
- if params[:project_id].present?
= hidden_field_tag(:project_id, params[:project_id])
= dropdown_tag(project_dropdown_label(params[:project_id], 'Project'), options: { toggle_class: 'js-project-search js-filter-submit', title: 'Filter by project', filter: true, filterInput: 'input#project-search', dropdown_class: 'dropdown-menu-selectable dropdown-menu-project js-filter-submit',
placeholder: 'Search projects', data: { data: todo_projects_options } })
.filter-item.inline
- if params[:author_id].present?
= hidden_field_tag(:author_id, params[:author_id])
= dropdown_tag(user_dropdown_label(params[:author_id], 'Author'), options: { toggle_class: 'js-user-search js-filter-submit js-author-search', title: 'Filter by author', filter: true, filterInput: 'input#author-search', dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author js-filter-submit',
placeholder: 'Search authors', data: { any_user: 'Any Author', first_user: (current_user.username if current_user), current_user: true, project_id: (@project.id if @project), selected: params[:author_id], field_name: 'author_id', default_label: 'Author' } })
.filter-item.inline
- if params[:type].present?
= hidden_field_tag(:type, params[:type])
= dropdown_tag(todo_types_dropdown_label(params[:type], 'Type'), options: { toggle_class: 'js-type-search js-filter-submit', dropdown_class: 'dropdown-menu-selectable dropdown-menu-type js-filter-submit',
data: { data: todo_types_options } })
.filter-item.inline.actions-filter
- if params[:action_id].present?
= hidden_field_tag(:action_id, params[:action_id])
= dropdown_tag(todo_actions_dropdown_label(params[:action_id], 'Action'), options: { toggle_class: 'js-action-search js-filter-submit', dropdown_class: 'dropdown-menu-selectable dropdown-menu-action js-filter-submit',
data: { data: todo_actions_options }})
.pull-right
.dropdown.inline.prepend-left-10
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
%span.light
- if @sort.present?
= sort_options_hash[@sort]
- else
= sort_title_recently_created
= icon('caret-down')
%ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-sort
%li
= link_to todos_filter_path(sort: sort_value_priority) do
= sort_title_priority
= link_to todos_filter_path(sort: sort_value_recently_created) do
.todos-filters
.row-content-block.second-block
= form_tag todos_filter_path(without: [:project_id, :author_id, :type, :action_id]), method: :get, class: 'filter-form' do
.filter-item.inline
- if params[:project_id].present?
= hidden_field_tag(:project_id, params[:project_id])
= dropdown_tag(project_dropdown_label(params[:project_id], 'Project'), options: { toggle_class: 'js-project-search js-filter-submit', title: 'Filter by project', filter: true, filterInput: 'input#project-search', dropdown_class: 'dropdown-menu-selectable dropdown-menu-project js-filter-submit',
placeholder: 'Search projects', data: { data: todo_projects_options } })
.filter-item.inline
- if params[:author_id].present?
= hidden_field_tag(:author_id, params[:author_id])
= dropdown_tag(user_dropdown_label(params[:author_id], 'Author'), options: { toggle_class: 'js-user-search js-filter-submit js-author-search', title: 'Filter by author', filter: true, filterInput: 'input#author-search', dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-author js-filter-submit',
placeholder: 'Search authors', data: { any_user: 'Any Author', first_user: (current_user.username if current_user), current_user: true, project_id: (@project.id if @project), selected: params[:author_id], field_name: 'author_id', default_label: 'Author' } })
.filter-item.inline
- if params[:type].present?
= hidden_field_tag(:type, params[:type])
= dropdown_tag(todo_types_dropdown_label(params[:type], 'Type'), options: { toggle_class: 'js-type-search js-filter-submit', dropdown_class: 'dropdown-menu-selectable dropdown-menu-type js-filter-submit',
data: { data: todo_types_options } })
.filter-item.inline.actions-filter
- if params[:action_id].present?
= hidden_field_tag(:action_id, params[:action_id])
= dropdown_tag(todo_actions_dropdown_label(params[:action_id], 'Action'), options: { toggle_class: 'js-action-search js-filter-submit', dropdown_class: 'dropdown-menu-selectable dropdown-menu-action js-filter-submit',
data: { data: todo_actions_options }})
.pull-right
.dropdown.inline.prepend-left-10
%button.dropdown-toggle.btn{type: 'button', 'data-toggle' => 'dropdown'}
%span.light
- if @sort.present?
= sort_options_hash[@sort]
- else
= sort_title_recently_created
= link_to todos_filter_path(sort: sort_value_oldest_created) do
= sort_title_oldest_created
= icon('caret-down')
%ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-sort
%li
= link_to todos_filter_path(sort: sort_value_priority) do
= sort_title_priority
= link_to todos_filter_path(sort: sort_value_recently_created) do
= sort_title_recently_created
= link_to todos_filter_path(sort: sort_value_oldest_created) do
= sort_title_oldest_created
.prepend-top-default
......@@ -78,5 +79,29 @@
%ul.content-list.todos-list
= render group[1]
= paginate @todos, theme: "gitlab"
- elsif current_user.todos.any?
.todos-all-done
= render "shared/empty_states/todos_all_done.svg"
%h4.text-center
Good job! Looks like you don't have any todos left.
%p.text-center
Are you looking for things to do? Take a look at
= succeed "," do
= link_to "the opened issues", issues_dashboard_path
contribute to
= link_to "merge requests", merge_requests_dashboard_path
or mention someone in a comment to assign a new todo automatically.
- else
.nothing-here-block You're all done!
.todos-empty
.todos-empty-hero
= render "shared/empty_states/todos_empty.svg"
.todos-empty-content
%h4
Todos let you see what you should do next.
%p
When an issue or merge request is assigned to you, or when you
%strong
@mention
in a comment, this will trigger a new item in your todo list, automatically.
%p
You will always know what to work on next.
......@@ -8,7 +8,8 @@
.form-group
.col-sm-offset-2.col-sm-10
= image_tag group_icon(@group), alt: '', class: 'avatar group-avatar s160'
.image-container.s160
= image_tag group_icon(@group), alt: '', class: 'avatar group-avatar s160'
%p.light
- if @group.avatar?
You can change your group avatar here
......
......@@ -13,7 +13,7 @@
.other-labels
- if @labels.present?
%ul.content-list.manage-labels-list.js-other-labels
= render partial: 'shared/label', collection: @labels, as: :label
= render partial: 'shared/label', subject: @group, collection: @labels, as: :label
= paginate @labels, theme: 'gitlab'
- else
.nothing-here-block
......
......@@ -6,7 +6,8 @@
.cover-block.groups-cover-block
%div{ class: container_class }
= image_tag group_icon(@group), class: "avatar group-avatar s70 avatar-tile"
.image-container.s70.group-avatar
= image_tag group_icon(@group), class: "avatar s70 avatar-tile"
.group-info
.cover-title
%h1
......
......@@ -4,6 +4,6 @@
-# total_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
%li{class: "page"}
%span.page.gap
%li
%span.gap
= raw(t 'views.pagination.truncate')
......@@ -6,5 +6,5 @@
-# total_pages: total number of pages
-# per_page: number of items to fetch per page
-# remote: data-remote
%li{class: "page#{' active' if page.current?}"}
%li{class: "page#{' active' if page.current?}#{' sibling' if page.next? || page.prev?}"}
= link_to page, url, {remote: remote, rel: page.next? ? 'next' : page.prev? ? 'prev' : nil}
......@@ -29,10 +29,6 @@
= icon('bell fw')
%span.badge.todos-pending-count{ class: ("hidden" if todos_pending_count == 0) }
= todos_pending_count
- if current_user.can_create_project?
%li
= link_to new_project_path, title: 'New project', aria: { label: "New project" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('plus fw')
- if Gitlab::Sherlock.enabled?
%li
= link_to sherlock_transactions_path, title: 'Sherlock Transactions',
......@@ -48,6 +44,8 @@
= link_to "Profile", current_user, class: 'profile-link', aria: { label: "Profile" }, data: { user: current_user.username }
%li
= link_to "Profile Settings", profile_path, aria: { label: "Profile Settings" }
%li
= link_to "Help", help_path, aria: { label: "Help" }
%li.divider
%li
= link_to "Sign out", destroy_user_session_path, method: :delete, class: "sign-out-link", aria: { label: "Sign out" }
......
%ul.nav.nav-sidebar
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: "#{project_tab_class} home"}) do
= link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
%span
Projects
= nav_link(controller: :todos) do
= link_to dashboard_todos_path, title: 'Todos' do
%span
Todos
%span.count.js-todos-count= number_with_delimiter(todos_pending_count)
= nav_link(path: 'dashboard#activity') do
= link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do
%span
Activity
- if koding_enabled?
= nav_link(controller: :koding) do
= link_to koding_path, title: 'Koding' do
.nav-sidebar
.sidebar-header Across GitLab
%ul.nav
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: "#{project_tab_class} home"}) do
= link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
%span
Koding
= nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do
= link_to dashboard_groups_path, title: 'Groups' do
%span
Groups
= nav_link(controller: 'dashboard/milestones') do
= link_to dashboard_milestones_path, title: 'Milestones' do
%span
Milestones
= nav_link(path: 'dashboard#issues') do
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues' do
%span
Issues
%span.count= number_with_delimiter(current_user.assigned_issues.opened.count)
= nav_link(path: 'dashboard#merge_requests') do
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do
%span
Merge Requests
%span.count= number_with_delimiter(current_user.assigned_merge_requests.opened.count)
= nav_link(controller: 'dashboard/snippets') do
= link_to dashboard_snippets_path, title: 'Snippets' do
%span
Snippets
= nav_link(controller: :help) do
= link_to help_path, title: 'Help' do
%span
Help
= nav_link(html_options: {class: profile_tab_class}) do
= link_to profile_path, title: 'Profile Settings', data: {placement: 'bottom'} do
%span
Profile Settings
Projects
= nav_link(path: 'dashboard#activity') do
= link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do
%span
Activity
- if koding_enabled?
= nav_link(controller: :koding) do
= link_to koding_path, title: 'Koding' do
%span
Koding
= nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do
= link_to dashboard_groups_path, title: 'Groups' do
%span
Groups
= nav_link(controller: 'dashboard/milestones') do
= link_to dashboard_milestones_path, title: 'Milestones' do
%span
Milestones
= nav_link(path: 'dashboard#issues') do
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues' do
%span
Issues
%span.count= number_with_delimiter(current_user.assigned_issues.opened.count)
= nav_link(path: 'dashboard#merge_requests') do
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do
%span
Merge Requests
%span.count= number_with_delimiter(current_user.assigned_merge_requests.opened.count)
= nav_link(controller: 'dashboard/snippets') do
= link_to dashboard_snippets_path, title: 'Snippets' do
%span
Snippets
- empty_repo = @project.empty_repo?
.project-home-panel.text-center{ class: ("empty-project" if empty_repo) }
%div{ class: container_class }
= project_icon(@project, alt: @project.name, class: 'project-avatar avatar s70 avatar-tile')
.image-container.s70.project-avatar
= project_icon(@project, alt: @project.name, class: 'avatar s70 avatar-tile')
%h1.project-title
= @project.name
%span.visibility-icon.has-tooltip{data: { container: 'body' }, title: visibility_icon_description(@project)}
......
......@@ -11,7 +11,9 @@
.board-inner
%header.board-header{ ":class" => "{ 'has-border': list.label }", ":style" => "{ borderTopColor: (list.label ? list.label.color : null) }" }
%h3.board-title.js-board-handle{ ":class" => "{ 'user-can-drag': (!disabled && !list.preset) }" }
{{ list.title }}
%span.has-tooltip{ ":title" => "(list.label ? list.label.description : '')",
data: { container: "body", placement: "bottom" } }
{{ list.title }}
.board-issue-count-holder.pull-right.clearfix{ "v-if" => "list.type !== 'blank'" }
%span.board-issue-count.pull-left{ ":class" => "{ 'has-btn': list.type !== 'done' }" }
{{ list.issuesSize }}
......
- commit = @repository.commit(branch.target)
- commit = @repository.commit(branch.dereferenced_target)
- bar_graph_width_factor = @max_commits > 0 ? 100.0/@max_commits : 0
- diverging_commit_counts = @repository.diverging_commit_counts(branch)
- number_commits_behind = diverging_commit_counts[:behind]
......
.content-block.build-header
= ci_status_with_icon(@build.status)
Build
%strong ##{@build.id}
for commit
= link_to ci_status_path(@build.pipeline) do
%strong= @build.pipeline.short_sha
from
= link_to namespace_project_commits_path(@project.namespace, @project, @build.ref) do
%code
= @build.ref
- if @build.user
= render "user"
= time_ago_with_tooltip(@build.created_at)
.header-content
= ci_status_with_icon(@build.status)
Build
%strong ##{@build.id}
for commit
= link_to ci_status_path(@build.pipeline) do
%strong= @build.pipeline.short_sha
from
= link_to namespace_project_commits_path(@project.namespace, @project, @build.ref) do
%code
= @build.ref
- if @build.user
= render "user"
= time_ago_with_tooltip(@build.created_at)
- if can?(current_user, :update_build, @build) && @build.retryable?
= link_to "Retry build", retry_namespace_project_build_path(@project.namespace, @project, @build), class: 'btn btn-inverted pull-right', method: :post
%button.btn.btn-default.pull-right.visible-xs-block.visible-sm-block.build-gutter-toggle.js-sidebar-build-toggle{ role: "button", type: "button" }
= icon('angle-double-left')
......@@ -44,7 +44,7 @@
.title
Build details
- if can?(current_user, :update_build, @build) && @build.retryable?
= link_to "Retry", retry_namespace_project_build_path(@project.namespace, @project, @build), class: 'pull-right retry-link', method: :post
= link_to "Retry build", retry_namespace_project_build_path(@project.namespace, @project, @build), class: 'pull-right retry-link', method: :post
- if @build.merge_request
%p.build-detail-row
%span.build-light-text Merge Request:
......
......@@ -5,10 +5,10 @@
= custom_icon('icon_fork')
%span Fork
- else
= link_to new_namespace_project_fork_path(@project.namespace, @project), title: 'Fork project', class: 'btn has-tooltip' do
= link_to new_namespace_project_fork_path(@project.namespace, @project), title: 'Fork project', class: 'btn' do
= custom_icon('icon_fork')
%span Fork
%div.count-with-arrow
%span.arrow
= link_to namespace_project_forks_path(@project.namespace, @project), title: 'Forks', class: 'count has-tooltip' do
= link_to namespace_project_forks_path(@project.namespace, @project), title: 'Forks', class: 'count' do
= @project.forks_count
- if current_user
= link_to toggle_star_namespace_project_path(@project.namespace, @project), { class: 'btn star-btn toggle-star has-tooltip', method: :post, remote: true, title: current_user.starred?(@project) ? 'Unstar project' : 'Star project' } do
= link_to toggle_star_namespace_project_path(@project.namespace, @project), { class: 'btn star-btn toggle-star', method: :post, remote: true } do
- if current_user.starred?(@project)
= icon('star')
%span.starred Unstar
......
.commit-info-row.commit-info-row-header
%span.hidden-xs Authored by
%span.hidden-xs.hidden-sm Commit
= link_to @commit.short_id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace js-details-short"
= link_to("#", class: "js-details-expand hidden-xs hidden-sm") do
%span.text-expander
\...
%span.js-details-content.hide
= link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace hidden-xs hidden-sm"
= clipboard_button(clipboard_text: @commit.id)
%span.hidden-xs authored
#{time_ago_with_tooltip(@commit.authored_date)}
%span by
= author_avatar(@commit, size: 24)
%strong
= commit_author_link(@commit, avatar: true, size: 24)
#{time_ago_with_tooltip(@commit.authored_date)}
- if @commit.different_committer?
%span.light Committed by
%strong
= commit_committer_link(@commit, avatar: true, size: 24)
#{time_ago_with_tooltip(@commit.committed_date)}
.pull-right.commit-action-buttons
- if defined?(@notes_count) && @notes_count > 0
......@@ -33,42 +48,35 @@
%li= link_to "Email Patches", namespace_project_commit_path(@project.namespace, @project, @commit, format: :patch)
%li= link_to "Plain Diff", namespace_project_commit_path(@project.namespace, @project, @commit, format: :diff)
- if @commit.different_committer?
.commit-info-row
%span.light Committed by
%strong
= commit_committer_link(@commit, avatar: true, size: 24)
#{time_ago_with_tooltip(@commit.committed_date)}
.commit-info-row
%span.hidden-xs.hidden-sm Commit
= link_to @commit.id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace hidden-xs hidden-sm"
= link_to @commit.short_id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace visible-xs-inline visible-sm-inline"
= clipboard_button(clipboard_text: @commit.id)
%span.cgray= pluralize(@commit.parents.count, "parent")
- @commit.parents.each do |parent|
= link_to parent.short_id, namespace_project_commit_path(@project.namespace, @project, parent), class: "monospace"
%span.commit-info.branches
%i.fa.fa-spinner.fa-spin
- if @commit.status
.commit-info-row
Builds for
= pluralize(@commit.pipelines.count, 'pipeline')
= link_to builds_namespace_project_commit_path(@project.namespace, @project, @commit.id), class: "ci-status-link ci-status-icon-#{@commit.status}" do
= ci_icon_for_status(@commit.status)
%span.ci-status-label
= ci_label_for_status(@commit.status)
in
= time_interval_in_words @commit.pipelines.total_duration
.commit-box.content-block
.commit-box
%h3.commit-title
= markdown(@commit.title, pipeline: :single_line, author: @commit.author)
- if @commit.description.present?
%pre.commit-description
= preserve(markdown(@commit.description, pipeline: :single_line, author: @commit.author))
.commit-info-widget
.widget-row.branch-info
.icon-container.commit-icon
= custom_icon("icon_commit")
%span.cgray= pluralize(@commit.parents.count, "parent")
- @commit.parents.each do |parent|
= link_to parent.short_id, namespace_project_commit_path(@project.namespace, @project, parent), class: "monospace"
%span.commit-info.branches
%i.fa.fa-spinner.fa-spin
- if @commit.status
.widget-row.pipeline-info
.icon-container
= ci_icon_for_status(@commit.status)
Pipeline
= link_to "##{@commit.pipelines.last.id}", pipelines_namespace_project_commit_path(@project.namespace, @project, @commit.id), class: "monospace"
for
= link_to @commit.short_id, namespace_project_commit_path(@project.namespace, @project, @commit), class: "monospace"
%span.ci-status-label
= ci_label_for_status(@commit.status)
in
= time_interval_in_words @commit.pipelines.total_duration
:javascript
$(".commit-info.branches").load("#{branches_namespace_project_commit_path(@project.namespace, @project, @commit.id)}");
......@@ -3,8 +3,7 @@
= render "projects/commits/head"
%div{ class: container_class }
.prepend-top-default
= render "commit_box"
= render "commit_box"
= render "ci_menu"
= render "builds"
- page_title "Pipelines", "#{@commit.title} (#{@commit.short_id})", "Commits"
.prepend-top-default
= render "commit_box"
= render "commit_box"
= render "ci_menu"
= render "pipelines_list", pipelines: @ci_pipelines
......@@ -4,8 +4,7 @@
= render "projects/commits/head"
%div{ class: container_class }
.prepend-top-default
= render "commit_box"
= render "commit_box"
- if @commit.status
= render "ci_menu"
- else
......
......@@ -8,7 +8,6 @@
= link_to '#', class: 'js-toggle-diff-comments btn active has-tooltip btn-file-option', title: "Toggle comments for this file", disabled: @diff_notes_disabled do
= icon('comment')
\
= clipboard_button(clipboard_text: diff_file.new_path, class: 'btn-file-option')
- if editable_diff?(diff_file)
- link_opts = @merge_request.id ? { from_merge_request_id: @merge_request.id } : {}
= edit_blob_link(@merge_request.source_project, @merge_request.source_branch, diff_file.new_path,
......
......@@ -21,6 +21,8 @@
- if diff_file.deleted_file
deleted
= clipboard_button(clipboard_text: diff_file.new_path, class: 'btn-clipboard btn-transparent prepend-left-5', title: 'Copy filename to clipboard')
- if diff_file.mode_changed?
%small
= "#{diff_file.a_mode}#{diff_file.b_mode}"
......@@ -118,7 +118,8 @@
Project avatar
.form-group
- if @project.avatar?
= project_icon("#{@project.namespace.to_param}/#{@project.to_param}", alt: '', class: 'avatar project-avatar s160')
.image-container.s160
= project_icon("#{@project.namespace.to_param}/#{@project.to_param}", alt: '', class: 'avatar project-avatar s160')
%p.light
- if @project.avatar_in_git
Project avatar in repository: #{ @project.avatar_in_git }
......@@ -180,6 +181,7 @@
%ul
%li Build traces and artifacts
%li LFS objects
%li Container registry images
%hr
- if can? current_user, :archive_project, @project
.row.prepend-top-default
......
......@@ -4,7 +4,7 @@
%ul.unstyled-list.related-merge-requests
- @related_branches.each do |branch|
%li
- target = @project.repository.find_branch(branch).target
- target = @project.repository.find_branch(branch).dereferenced_target
- pipeline = @project.pipeline_for(branch, target.sha) if target
- if pipeline
%span.related-branch-ci-status
......
......@@ -22,14 +22,14 @@
%ul.content-list.manage-labels-list.js-prioritized-labels{ "data-url" => set_priorities_namespace_project_labels_path(@project.namespace, @project) }
%p.empty-message{ class: ('hidden' unless @prioritized_labels.empty?) } No prioritized labels yet
- if @prioritized_labels.present?
= render partial: 'shared/label', collection: @prioritized_labels, as: :label
= render partial: 'shared/label', subject: @project, collection: @prioritized_labels, as: :label
.other-labels
- if can?(current_user, :admin_label, @project)
%h5{ class: ('hide' if hide) } Other Labels
%ul.content-list.manage-labels-list.js-other-labels
- if @labels.present?
= render partial: 'shared/label', collection: @labels, as: :label
= render partial: 'shared/label', subject: @project, collection: @labels, as: :label
= paginate @labels, theme: 'gitlab'
- if @labels.blank?
.nothing-here-block
......
- commit = @repository.commit(tag.target)
- commit = @repository.commit(tag.dereferenced_target)
- release = @releases.find { |release| release.tag == tag.name }
%li
%div
......
......@@ -33,7 +33,12 @@
.form-actions
- if @page && @page.persisted?
= f.submit 'Save changes', class: "btn-save btn"
= link_to "Cancel", namespace_project_wiki_path(@project.namespace, @project, @page), class: "btn btn-cancel"
.pull-right
- if can?(current_user, :admin_wiki, @project)
= link_to namespace_project_wiki_path(@project.namespace, @project, @page), data: { confirm: "Are you sure you want to delete this page?"}, method: :delete, class: "btn btn-danger btn-grouped" do
Delete
= link_to "Cancel", namespace_project_wiki_path(@project.namespace, @project, @page), class: "btn btn-cancel btn-grouped"
- else
= f.submit 'Create page', class: "btn-create btn"
= link_to "Cancel", namespace_project_wiki_path(@project.namespace, @project, :home), class: "btn btn-cancel"
.pull-right
= link_to "Cancel", namespace_project_wiki_path(@project.namespace, @project, :home), class: "btn btn-cancel"
......@@ -7,6 +7,3 @@
- if can?(current_user, :create_wiki, @project)
= link_to namespace_project_wiki_edit_path(@project.namespace, @project, @page), class: "btn" do
Edit
- if can?(current_user, :admin_wiki, @project)
= link_to namespace_project_wiki_path(@project.namespace, @project, @page), data: { confirm: "Are you sure you want to delete this page?"}, method: :delete, class: "btn btn-remove" do
Delete
......@@ -19,7 +19,5 @@
- if can?(current_user, :create_wiki, @project)
= link_to '#modal-new-wiki', class: "add-new-wiki btn btn-new", "data-toggle" => "modal" do
New Page
= render 'main_links'
= render 'form'
%ul.nav-links.event-filter.scrolling-tabs
= event_filter_link EventFilter.all, 'All'
= event_filter_link EventFilter.push, 'Push events'
= event_filter_link EventFilter.merged, 'Merge events'
= event_filter_link EventFilter.comments, 'Comments'
- if event_filter_visible(:repository)
= event_filter_link EventFilter.push, 'Push events'
- if event_filter_visible(:merge_requests)
= event_filter_link EventFilter.merged, 'Merge events'
- if event_filter_visible(:issues)
= event_filter_link EventFilter.comments, 'Comments'
= event_filter_link EventFilter.team, 'Team'
- label_css_id = dom_id(label)
- open_issues_count = label.open_issues_count(current_user, @project)
- open_merge_requests_count = label.open_merge_requests_count(current_user, @project)
- open_issues_count = label.open_issues_count(current_user)
- open_merge_requests_count = label.open_merge_requests_count(current_user)
- subject = local_assigns[:subject]
%li{id: label_css_id, data: { id: label.id } }
= render "shared/label_row", label: label
......@@ -12,10 +13,10 @@
.dropdown-menu.dropdown-menu-align-right
%ul
%li
= link_to_label(label, subject: @project, type: :merge_request) do
= link_to_label(label, subject: subject, type: :merge_request) do
= pluralize open_merge_requests_count, 'merge request'
%li
= link_to_label(label, subject: @project) do
= link_to_label(label, subject: subject) do
= pluralize open_issues_count, 'open issue'
- if current_user
%li.label-subscription{ data: toggle_subscription_data(label) }
......@@ -28,9 +29,9 @@
= link_to 'Delete', destroy_label_path(label), title: 'Delete', method: :delete, remote: true, data: {confirm: 'Remove this label? Are you sure?'}
.pull-right.hidden-xs.hidden-sm.hidden-md
= link_to_label(label, subject: @project, type: :merge_request, css_class: 'btn btn-transparent btn-action') do
= link_to_label(label, subject: subject, type: :merge_request, css_class: 'btn btn-transparent btn-action') do
= pluralize open_merge_requests_count, 'merge request'
= link_to_label(label, subject: @project, css_class: 'btn btn-transparent btn-action') do
= link_to_label(label, subject: subject, css_class: 'btn btn-transparent btn-action') do
= pluralize open_issues_count, 'open issue'
- if current_user
......
<svg viewBox="0 0 293 216"><g fill="none" fill-rule="evenodd"><g transform="rotate(-5 211.388 -693.89)"><rect width="163.6" height="200" x=".2" fill="#FFF" stroke="#EEE" stroke-width="3" stroke-linecap="round" stroke-dasharray="6 9" rx="6"/><g transform="translate(24 38)"><path fill="#FC6D26" d="M18.2 14l-4-3.8c-.4-.6-1.4-.6-2 0-.6.6-.6 1.5 0 2l5 5c.3.4.6.5 1 .5s.8 0 1-.4L28 8.8c.6-.6.6-1.5 0-2-.6-.7-1.6-.7-2 0L18 14z"/><path stroke="#6B4FBB" stroke-width="3" d="M27 23.3V27c0 2.3-1.7 4-4 4H4c-2.3 0-4-1.7-4-4V8c0-2.3 1.7-4 4-4h3.8" stroke-linecap="round"/><rect width="76" height="3" x="40" y="11" fill="#6B4FBB" opacity=".5" rx="1.5"/><rect width="43" height="3" x="40" y="21" fill="#6B4FBB" opacity=".5" rx="1.5"/></g><g transform="translate(24 83)"><path fill="#FC6D26" d="M18.2 14l-4-3.8c-.4-.6-1.4-.6-2 0-.6.6-.6 1.5 0 2l5 5c.3.4.6.5 1 .5s.8 0 1-.4L28 8.8c.6-.6.6-1.5 0-2-.6-.7-1.6-.7-2 0L18 14z"/><path stroke="#6B4FBB" stroke-width="3" d="M27 23.3V27c0 2.3-1.7 4-4 4H4c-2.3 0-4-1.7-4-4V8c0-2.3 1.7-4 4-4h3.8" stroke-linecap="round"/><rect width="76" height="3" x="40" y="11" fill="#B5A7DD" rx="1.5"/><rect width="43" height="3" x="40" y="21" fill="#B5A7DD" rx="1.5"/></g><g transform="translate(24 130)"><path fill="#FC6D26" d="M18.2 14l-4-3.8c-.4-.6-1.4-.6-2 0-.6.6-.6 1.5 0 2l5 5c.3.4.6.5 1 .5s.8 0 1-.4L28 8.8c.6-.6.6-1.5 0-2-.6-.7-1.6-.7-2 0L18 14z"/><path stroke="#6B4FBB" stroke-width="3" d="M27 23.3V27c0 2.3-1.7 4-4 4H4c-2.3 0-4-1.7-4-4V8c0-2.3 1.7-4 4-4h3.8" stroke-linecap="round"/><rect width="76" height="3" x="40" y="11" fill="#B5A7DD" rx="1.5"/><rect width="43" height="3" x="40" y="21" fill="#B5A7DD" rx="1.5"/></g></g><path fill="#FFCE29" d="M30 11l-1.8 4-2-4-4-1.8 4-2 2-4 2 4 4 2M286 60l-2.7 6.3-3-6-6-3 6-3 3-6 2.8 6.2 6.6 2.8M263 97l-2 4-2-4-4-2 4-2 2-4 2 4 4 2M12 85l-2.7 6.3-3-6-6-3 6-3 3-6 2.8 6.2 6.6 2.8"/></g></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 284 337" xmlns:xlink="http://www.w3.org/1999/xlink">
<defs>
<rect id="a" width="180" height="220" x="66.2" y="74.4" rx="6"/>
<mask id="l" width="180" height="220" x="0" y="0" fill="#fff">
<use xlink:href="#a"/>
</mask>
<rect id="b" width="180" height="220" rx="6"/>
<mask id="m" width="180" height="220" x="0" y="0" fill="#fff">
<use xlink:href="#b"/>
</mask>
<rect id="c" width="28" height="28" rx="4"/>
<mask id="n" width="28" height="28" x="0" y="0" fill="#fff">
<use xlink:href="#c"/>
</mask>
<rect id="d" width="28" height="28" rx="4"/>
<mask id="o" width="28" height="28" x="0" y="0" fill="#fff">
<use xlink:href="#d"/>
</mask>
<circle id="e" cx="21.5" cy="21.5" r="21.5"/>
<mask id="p" width="43" height="43" x="0" y="0" fill="#fff">
<use xlink:href="#e"/>
</mask>
<circle id="f" cx="26.5" cy="26.5" r="26.5"/>
<mask id="q" width="53" height="53" x="0" y="0" fill="#fff">
<use xlink:href="#f"/>
</mask>
<circle id="g" cx="9.5" cy="4.5" r="4.5"/>
<mask id="r" width="13" height="13" x="-2" y="-2">
<path fill="#fff" d="M3-2h13v13H3z"/>
<use xlink:href="#g"/>
</mask>
<circle id="h" cx="26.5" cy="26.5" r="26.5"/>
<mask id="s" width="53" height="53" x="0" y="0" fill="#fff">
<use xlink:href="#h"/>
</mask>
<circle id="i" cx="21.5" cy="21.5" r="21.5"/>
<mask id="t" width="43" height="43" x="0" y="0" fill="#fff">
<use xlink:href="#i"/>
</mask>
<path id="j" d="M18 38h15c10.5 0 19-8.5 19-19S43.5 0 33 0H19C8.5 0 0 8.5 0 19c0 6.3 3 12 7.8 15.3l5.2 9c.6 1 1.4 1 2 0l3-5.3z"/>
<mask id="u" width="52" height="44" x="0" y="0" fill="#fff">
<use xlink:href="#j"/>
</mask>
<circle id="k" cx="18.5" cy="18.5" r="18.5"/>
<mask id="v" width="37" height="37" x="0" y="0" fill="#fff">
<use xlink:href="#k"/>
</mask>
</defs>
<g fill="none" fill-rule="evenodd" transform="translate(-6 -4)">
<use stroke="#EEE" stroke-width="6" mask="url(#l)" transform="rotate(-5 156.245 184.425)" xlink:href="#a"/>
<g transform="rotate(5 -707.333 618.042)">
<use fill="#FFF" stroke="#EEE" stroke-width="6" mask="url(#m)" xlink:href="#b"/>
<g transform="translate(29 24)">
<path fill="#FC6D26" d="M18.2 14l-4-3.8c-.4-.6-1.4-.6-2 0-.6.6-.6 1.5 0 2l5 5c.3.4.6.5 1 .5s.8 0 1-.4L28 8.8c.6-.6.6-1.5 0-2-.6-.7-1.6-.7-2 0L18 14z"/>
<path stroke="#6B4FBB" stroke-width="3" d="M27 23.3V27c0 2.3-1.7 4-4 4H4c-2.3 0-4-1.7-4-4V8c0-2.3 1.7-4 4-4h3.8" stroke-linecap="round"/>
<rect width="86" height="3" x="40" y="11" fill="#6B4FBB" opacity=".5" rx="1.5"/>
<rect width="43" height="3" x="40" y="21" fill="#6B4FBB" opacity=".5" rx="1.5"/>
</g>
<g transform="translate(29 69)">
<path fill="#FC6D26" d="M18.2 14l-4-3.8c-.4-.6-1.4-.6-2 0-.6.6-.6 1.5 0 2l5 5c.3.4.6.5 1 .5s.8 0 1-.4L28 8.8c.6-.6.6-1.5 0-2-.6-.7-1.6-.7-2 0L18 14z"/>
<path stroke="#6B4FBB" stroke-width="3" d="M27 23.3V27c0 2.3-1.7 4-4 4H4c-2.3 0-4-1.7-4-4V8c0-2.3 1.7-4 4-4h3.8" stroke-linecap="round"/>
<rect width="86" height="3" x="40" y="11" fill="#B5A7DD" rx="1.5"/>
<rect width="43" height="3" x="40" y="21" fill="#B5A7DD" rx="1.5"/>
</g>
<g transform="translate(28 160)">
<use stroke="#E5E5E5" stroke-width="6" mask="url(#n)" opacity=".7" xlink:href="#c"/>
<rect width="26" height="3" x="41" y="7" fill="#ECECEC" rx="1.5"/>
<rect width="43" height="3" x="41" y="17" fill="#ECECEC" rx="1.5"/>
</g>
<g transform="translate(28 116)">
<use stroke="#E5E5E5" stroke-width="6" mask="url(#o)" xlink:href="#d"/>
<rect width="86" height="3" x="41" y="7" fill="#E5E5E5" rx="1.5"/>
<rect width="43" height="3" x="41" y="17" fill="#E5E5E5" rx="1.5"/>
</g>
</g>
<g transform="rotate(-15 601.917 -782.362)">
<use fill="#FFF" stroke="#B5A7DD" stroke-width="6" mask="url(#p)" xlink:href="#e"/>
<text fill="#6B4FBB" font-family="SourceSansPro-Black, Source Sans Pro" font-size="20" font-weight="700" letter-spacing="-.1">
<tspan x="12" y="27">@</tspan>
</text>
</g>
<g transform="rotate(15 -686.59 1035.907)">
<use fill="#FFF" stroke="#FDE5D8" stroke-width="6" mask="url(#q)" xlink:href="#f"/>
<path fill="#FC6D26" d="M26.5 38.2c3.3 0 9.5-2.5 9.5-9.6 0-7-2.4-6.6-9.5-6.6-7 0-9.5-.4-9.5 6.6s6.2 9.6 9.5 9.6z"/>
<g transform="translate(17 14)">
<use fill="#FC6D26" xlink:href="#g"/>
<use stroke="#FFF" stroke-width="4" mask="url(#r)" xlink:href="#g"/>
</g>
</g>
<g transform="rotate(15 -85.125 65.185)">
<use fill="#FFF" stroke="#B5A7DD" stroke-width="6" mask="url(#s)" xlink:href="#h"/>
<path fill="#6B4FBB" d="M24 18.5c0-1.4 1-2.5 2.5-2.5 1.4 0 2.5 1 2.5 2.5v9c0 1.4-1 2.5-2.5 2.5-1.4 0-2.5-1-2.5-2.5v-9zM26.5 37c1.4 0 2.5-1 2.5-2.5 0-1.4-1-2.5-2.5-2.5-1.4 0-2.5 1-2.5 2.5 0 1.4 1 2.5 2.5 2.5z"/>
</g>
<g transform="rotate(-15 716.492 78.873)">
<use fill="#FFF" stroke="#FDE5D8" stroke-width="6" mask="url(#t)" xlink:href="#i"/>
<path fill="#FC6D26" d="M20 23v-3h3v3h-3zm0 3v1.5c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5V26h-2.5c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5H17v-3h-1.5c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5H17v-2.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5V17h3v-1.5c0-.8.7-1.5 1.5-1.5s1.5.7 1.5 1.5V17h2.5c.8 0 1.5.7 1.5 1.5s-.7 1.5-1.5 1.5H26v3h1.5c.8 0 1.5.7 1.5 1.5s-.7 1.5-1.5 1.5H26v2.5c0 .8-.7 1.5-1.5 1.5s-1.5-.7-1.5-1.5V26h-3z"/>
</g>
<g transform="rotate(-15 129.114 -585.74)">
<use stroke="#FDE5D8" stroke-width="6" mask="url(#u)" xlink:href="#j"/>
<circle cx="16" cy="20" r="2" fill="#FC6D26"/>
<circle cx="27" cy="20" r="2" fill="#FC6D26"/>
<circle cx="38" cy="20" r="2" fill="#FC6D26"/>
</g>
<g transform="rotate(-15 1254.8 -458.986)">
<use stroke="#FDE5D8" stroke-width="6" mask="url(#v)" xlink:href="#k"/>
<path fill="#FC6D26" d="M10.6 19l2-2c.5-.5.5-1 0-1.5-.3-.4-1-.4-1.3 0l-2.8 2.8c-.2.2-.3.4-.3.7 0 .3 0 .5.3.7l2.8 2.8c.4.4 1 .4 1.4 0 .4-.4.4-1 0-1.4l-2-2zm14.8 0l-2-2c-.5-.5-.5-1 0-1.5.3-.4 1-.4 1.3 0l2.8 2.8c.2.2.3.4.3.7 0 .3 0 .5-.3.7l-2.8 2.8c-.4.4-1 .4-1.4 0-.4-.4-.4-1 0-1.4l2-2z"/>
<rect width="2" height="7" x="17" y="15.1" fill="#FC6D26" opacity=".5" transform="rotate(15 18.002 18.64)" rx="1"/>
</g>
</g>
</svg>
......@@ -24,7 +24,8 @@
%span.visibility-icon.has-tooltip{data: { container: 'body', placement: 'left' }, title: visibility_icon_description(group)}
= visibility_level_icon(group.visibility_level, fw: false)
= image_tag group_icon(group), class: "avatar s40 hidden-xs"
.image-container.s40
= image_tag group_icon(group), class: "avatar s40 hidden-xs"
.title
= link_to group, class: 'group-name' do
= group.name
......
- project = @target_project || @project
- extra_class = extra_class || ''
- show_menu_above = show_menu_above || false
- selected_text = selected.try(:title)
- selected_text = selected.try(:title) || params[:milestone_title]
- dropdown_title = local_assigns.fetch(:dropdown_title, "Filter by milestone")
- if selected.present?
= hidden_field_tag(name, name == :milestone_title ? selected.title : selected.id)
= hidden_field_tag(name, name == :milestone_title ? selected_text : selected.id)
= dropdown_tag(milestone_dropdown_label(selected_text), options: { title: dropdown_title, toggle_class: "js-milestone-select js-filter-submit #{extra_class}", filter: true, dropdown_class: "dropdown-menu-selectable dropdown-menu-milestone",
placeholder: "Search milestones", footer_content: project.present?, data: { show_no: true, show_menu_above: show_menu_above, show_any: show_any, show_upcoming: show_upcoming, field_name: name, selected: selected.try(:title), project_id: project.try(:id), milestones: milestones_filter_dropdown_path, default_label: "Milestone" } }) do
- if project
......
......@@ -32,10 +32,11 @@
= link_to project_path(project), class: dom_class(project) do
- if avatar
.dash-project-avatar
- if use_creator_avatar
= image_tag avatar_icon(project.creator.email, 40), class: "avatar s40", alt:''
- else
= project_icon(project, alt: '', class: 'avatar project-avatar s40')
.image-container.s40
- if use_creator_avatar
= image_tag avatar_icon(project.creator.email, 40), class: "avatar s40", alt:''
- else
= project_icon(project, alt: '', class: 'avatar project-avatar s40')
%span.project-full-name
%span.namespace-name
- if project.namespace && !skip_namespace
......
.clearfix
- groups.each do |group|
= link_to group, class: 'profile-groups-avatars inline', title: group.name do
= image_tag group_icon(group), class: 'avatar group-avatar s40'
.image-container.s40
= image_tag group_icon(group), class: 'avatar group-avatar s40'
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册