Commit bd01d79f authored by Filipa Lacerda's avatar Filipa Lacerda

Merge branch 'master' into fe-paginated-environments-api

* master: (97 commits)
  convert js-cookie dependency to an npm module
  convert timeago.js dependency to an npm module
  remove vue from vendor since it is now in node_modules
  Add CHANGELOG file
  Stylize blockquote in notification emails
  Add js prefix to right sidebar
  Replace accidentally deleted metaclick
  Remove right padding from navbar-collapse on large screens
  Add changelog
  common_utils merge conflicts
  Set sidebar height to 100% if at top of page
  Set height of fixed sidebars with js
  Add sticky sidebar on wiki page
  Fix comment button test for slash commands
  Fix time tracking spec
  Fix issue boards sidebar alignment and sidebar toggle spec
  Fix failing conflicts test
  Fix build sidebar scrolling
  Refactor JS
  Fix pinned sidebar alignment
  ...
parents d0d94e4f edb8ed36
...@@ -163,64 +163,7 @@ spinach 7 10: *spinach-knapsack ...@@ -163,64 +163,7 @@ spinach 7 10: *spinach-knapsack
spinach 8 10: *spinach-knapsack spinach 8 10: *spinach-knapsack
spinach 9 10: *spinach-knapsack spinach 9 10: *spinach-knapsack
# Execute all testing suites against Ruby 2.1
.ruby-21: &ruby-21
image: "dev.gitlab.org:5005/gitlab/gitlab-build-images:ruby-2.1-git-2.7-phantomjs-2.1"
<<: *use-db
only:
- master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee
- master@gitlab/gitlabhq
- master@gitlab/gitlab-ee
cache:
key: "ruby21"
paths:
- vendor/ruby
.rspec-knapsack-ruby21: &rspec-knapsack-ruby21
<<: *rspec-knapsack
<<: *dedicated-runner
<<: *ruby-21
.spinach-knapsack-ruby21: &spinach-knapsack-ruby21
<<: *spinach-knapsack
<<: *dedicated-runner
<<: *ruby-21
rspec 0 20 ruby21: *rspec-knapsack-ruby21
rspec 1 20 ruby21: *rspec-knapsack-ruby21
rspec 2 20 ruby21: *rspec-knapsack-ruby21
rspec 3 20 ruby21: *rspec-knapsack-ruby21
rspec 4 20 ruby21: *rspec-knapsack-ruby21
rspec 5 20 ruby21: *rspec-knapsack-ruby21
rspec 6 20 ruby21: *rspec-knapsack-ruby21
rspec 7 20 ruby21: *rspec-knapsack-ruby21
rspec 8 20 ruby21: *rspec-knapsack-ruby21
rspec 9 20 ruby21: *rspec-knapsack-ruby21
rspec 10 20 ruby21: *rspec-knapsack-ruby21
rspec 11 20 ruby21: *rspec-knapsack-ruby21
rspec 12 20 ruby21: *rspec-knapsack-ruby21
rspec 13 20 ruby21: *rspec-knapsack-ruby21
rspec 14 20 ruby21: *rspec-knapsack-ruby21
rspec 15 20 ruby21: *rspec-knapsack-ruby21
rspec 16 20 ruby21: *rspec-knapsack-ruby21
rspec 17 20 ruby21: *rspec-knapsack-ruby21
rspec 18 20 ruby21: *rspec-knapsack-ruby21
rspec 19 20 ruby21: *rspec-knapsack-ruby21
spinach 0 10 ruby21: *spinach-knapsack-ruby21
spinach 1 10 ruby21: *spinach-knapsack-ruby21
spinach 2 10 ruby21: *spinach-knapsack-ruby21
spinach 3 10 ruby21: *spinach-knapsack-ruby21
spinach 4 10 ruby21: *spinach-knapsack-ruby21
spinach 5 10 ruby21: *spinach-knapsack-ruby21
spinach 6 10 ruby21: *spinach-knapsack-ruby21
spinach 7 10 ruby21: *spinach-knapsack-ruby21
spinach 8 10 ruby21: *spinach-knapsack-ruby21
spinach 9 10 ruby21: *spinach-knapsack-ruby21
# Other generic tests # Other generic tests
.ruby-static-analysis: &ruby-static-analysis .ruby-static-analysis: &ruby-static-analysis
variables: variables:
SIMPLECOV: "false" SIMPLECOV: "false"
......
...@@ -6,13 +6,13 @@ ...@@ -6,13 +6,13 @@
(How one can reproduce the issue - this is very important) (How one can reproduce the issue - this is very important)
### Expected behavior ### What is the current *bug* behavior?
(What you should see instead) (What actually happens)
### Actual behavior ### What is the expected *correct* behavior?
(What actually happens) (What you should see instead)
### Relevant logs and/or screenshots ### Relevant logs and/or screenshots
...@@ -23,23 +23,23 @@ logs, and code as it's very hard to read otherwise.) ...@@ -23,23 +23,23 @@ logs, and code as it's very hard to read otherwise.)
(If you are reporting a bug on GitLab.com, write: This bug happens on GitLab.com) (If you are reporting a bug on GitLab.com, write: This bug happens on GitLab.com)
#### Results of GitLab application Check #### Results of GitLab environment info
(For installations with omnibus-gitlab package run and paste the output of: (For installations with omnibus-gitlab package run and paste the output of:
`sudo gitlab-rake gitlab:check SANITIZE=true`) `sudo gitlab-rake gitlab:env:info`)
(For installations from source run and paste the output of: (For installations from source run and paste the output of:
`sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true`) `sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`)
(we will only investigate if the tests are passing)
#### Results of GitLab environment info #### Results of GitLab application Check
(For installations with omnibus-gitlab package run and paste the output of: (For installations with omnibus-gitlab package run and paste the output of:
`sudo gitlab-rake gitlab:env:info`) `sudo gitlab-rake gitlab:check SANITIZE=true`)
(For installations from source run and paste the output of: (For installations from source run and paste the output of:
`sudo -u git -H bundle exec rake gitlab:env:info RAILS_ENV=production`) `sudo -u git -H bundle exec rake gitlab:check RAILS_ENV=production SANITIZE=true`)
(we will only investigate if the tests are passing)
### Possible fixes ### Possible fixes
......
...@@ -31,8 +31,7 @@ AllCops: ...@@ -31,8 +31,7 @@ AllCops:
- 'lib/gitlab/seeder.rb' - 'lib/gitlab/seeder.rb'
- 'generator_templates/**/*' - 'generator_templates/**/*'
# Style #######################################################################
##################### Style ##################################
# Check indentation of private/protected visibility modifiers. # Check indentation of private/protected visibility modifiers.
Style/AccessModifierIndentation: Style/AccessModifierIndentation:
...@@ -471,7 +470,7 @@ Style/WhileUntilModifier: ...@@ -471,7 +470,7 @@ Style/WhileUntilModifier:
Style/WordArray: Style/WordArray:
Enabled: false Enabled: false
#################### Metrics ################################ # Metrics #####################################################################
# A calculated magnitude based on number of assignments, # A calculated magnitude based on number of assignments,
# branches, and conditions. # branches, and conditions.
...@@ -516,8 +515,7 @@ Metrics/PerceivedComplexity: ...@@ -516,8 +515,7 @@ Metrics/PerceivedComplexity:
Enabled: true Enabled: true
Max: 18 Max: 18
# Lint ########################################################################
#################### Lint ################################
# Checks for useless access modifiers. # Checks for useless access modifiers.
Lint/UselessAccessModifier: Lint/UselessAccessModifier:
...@@ -679,8 +677,7 @@ Lint/UselessSetterCall: ...@@ -679,8 +677,7 @@ Lint/UselessSetterCall:
Lint/Void: Lint/Void:
Enabled: true Enabled: true
# Performance #################################################################
##################### Performance ############################
# Use `casecmp` rather than `downcase ==`. # Use `casecmp` rather than `downcase ==`.
Performance/Casecmp: Performance/Casecmp:
...@@ -718,8 +715,7 @@ Performance/StringReplacement: ...@@ -718,8 +715,7 @@ Performance/StringReplacement:
Performance/TimesMap: Performance/TimesMap:
Enabled: true Enabled: true
# Rails #######################################################################
##################### Rails ##################################
# Enables Rails cops. # Enables Rails cops.
Rails: Rails:
...@@ -767,7 +763,7 @@ Rails/ReadWriteAttribute: ...@@ -767,7 +763,7 @@ Rails/ReadWriteAttribute:
Rails/ScopeArgs: Rails/ScopeArgs:
Enabled: true Enabled: true
##################### RSpec ################################## # RSpec #######################################################################
# Check that instances are not being stubbed globally. # Check that instances are not being stubbed globally.
RSpec/AnyInstance: RSpec/AnyInstance:
...@@ -828,3 +824,9 @@ RSpec/NotToNot: ...@@ -828,3 +824,9 @@ RSpec/NotToNot:
# Prefer using verifying doubles over normal doubles. # Prefer using verifying doubles over normal doubles.
RSpec/VerifiedDoubles: RSpec/VerifiedDoubles:
Enabled: false Enabled: false
# Custom ######################################################################
# Disallow the `git` and `github` arguments in the Gemfile.
GemFetcher:
Enabled: true
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
- [Issue weight](#issue-weight) - [Issue weight](#issue-weight)
- [Regression issues](#regression-issues) - [Regression issues](#regression-issues)
- [Technical debt](#technical-debt) - [Technical debt](#technical-debt)
- [Stewardship][#stewardship] - [Stewardship](#stewardship)
- [Merge requests](#merge-requests) - [Merge requests](#merge-requests)
- [Merge request guidelines](#merge-request-guidelines) - [Merge request guidelines](#merge-request-guidelines)
- [Contribution acceptance criteria](#contribution-acceptance-criteria) - [Contribution acceptance criteria](#contribution-acceptance-criteria)
......
...@@ -284,7 +284,7 @@ group :development, :test do ...@@ -284,7 +284,7 @@ group :development, :test do
gem 'rspec-retry', '~> 0.4.5' gem 'rspec-retry', '~> 0.4.5'
gem 'spinach-rails', '~> 0.2.1' gem 'spinach-rails', '~> 0.2.1'
gem 'spinach-rerun-reporter', '~> 0.0.2' gem 'spinach-rerun-reporter', '~> 0.0.2'
gem 'rspec_profiling' gem 'rspec_profiling', '~> 0.0.5'
# Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826) # Prevent occasions where minitest is not bundled in packaged versions of ruby (see #3826)
gem 'minitest', '~> 5.7.0' gem 'minitest', '~> 5.7.0'
......
...@@ -638,7 +638,7 @@ GEM ...@@ -638,7 +638,7 @@ GEM
rspec-retry (0.4.5) rspec-retry (0.4.5)
rspec-core rspec-core
rspec-support (3.5.0) rspec-support (3.5.0)
rspec_profiling (0.0.4) rspec_profiling (0.0.5)
activerecord activerecord
pg pg
rails rails
...@@ -738,7 +738,7 @@ GEM ...@@ -738,7 +738,7 @@ GEM
actionpack (>= 4.0) actionpack (>= 4.0)
activesupport (>= 4.0) activesupport (>= 4.0)
sprockets (>= 3.0.0) sprockets (>= 3.0.0)
sqlite3 (1.3.11) sqlite3 (1.3.13)
stackprof (0.2.10) stackprof (0.2.10)
state_machines (0.4.0) state_machines (0.4.0)
state_machines-activemodel (0.4.0) state_machines-activemodel (0.4.0)
...@@ -962,7 +962,7 @@ DEPENDENCIES ...@@ -962,7 +962,7 @@ DEPENDENCIES
rqrcode-rails3 (~> 0.1.7) rqrcode-rails3 (~> 0.1.7)
rspec-rails (~> 3.5.0) rspec-rails (~> 3.5.0)
rspec-retry (~> 0.4.5) rspec-retry (~> 0.4.5)
rspec_profiling rspec_profiling (~> 0.0.5)
rubocop (~> 0.46.0) rubocop (~> 0.46.0)
rubocop-rspec (~> 1.9.1) rubocop-rspec (~> 1.9.1)
ruby-fogbugz (~> 0.2.1) ruby-fogbugz (~> 0.2.1)
...@@ -1011,4 +1011,4 @@ DEPENDENCIES ...@@ -1011,4 +1011,4 @@ DEPENDENCIES
wikicloth (= 0.8.1) wikicloth (= 0.8.1)
BUNDLED WITH BUNDLED WITH
1.14.2 1.14.3
Copyright (c) 2011-2016 GitLab B.V. Copyright (c) 2011-2017 GitLab B.V.
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
......
...@@ -59,7 +59,7 @@ star, smile, etc.). Some good tips about code reviews can be found in our ...@@ -59,7 +59,7 @@ star, smile, etc.). Some good tips about code reviews can be found in our
## Feature Freeze ## Feature Freeze
On the 7th of each month, RC1 of the upcoming release is created and deployed to GitLab.com and the stable branch for this release is frozen, which means master is no longer merged into it. After the 7th (Pacific Standard Time Zone) of each month, RC1 of the upcoming release is created and deployed to GitLab.com and the stable branch for this release is frozen, which means master is no longer merged into it.
Merge requests may still be merged into master during this period, Merge requests may still be merged into master during this period,
but they will go into the _next_ release, unless they are manually cherry-picked into the stable branch. but they will go into the _next_ release, unless they are manually cherry-picked into the stable branch.
By freezing the stable branches 2 weeks prior to a release, we reduce the risk of a last minute merge request potentially breaking things. By freezing the stable branches 2 weeks prior to a release, we reduce the risk of a last minute merge request potentially breaking things.
......
...@@ -20,7 +20,7 @@ require('vendor/jquery.waitforimages'); ...@@ -20,7 +20,7 @@ require('vendor/jquery.waitforimages');
require('vendor/jquery.caret'); require('vendor/jquery.caret');
require('vendor/jquery.atwho'); require('vendor/jquery.atwho');
require('vendor/jquery.scrollTo'); require('vendor/jquery.scrollTo');
window.Cookies = require('vendor/js.cookie'); window.Cookies = require('js-cookie');
require('./autosave'); require('./autosave');
require('bootstrap/js/affix'); require('bootstrap/js/affix');
require('bootstrap/js/alert'); require('bootstrap/js/alert');
......
...@@ -67,16 +67,8 @@ ...@@ -67,16 +67,8 @@
Build.prototype.initSidebar = function() { Build.prototype.initSidebar = function() {
this.$sidebar = $('.js-build-sidebar'); this.$sidebar = $('.js-build-sidebar');
this.sidebarTranslationLimits = {
min: $('.navbar-gitlab').outerHeight() + $('.layout-nav').outerHeight()
};
this.sidebarTranslationLimits.max = this.sidebarTranslationLimits.min + $('.scrolling-tabs-container').outerHeight();
this.$sidebar.css({
top: this.sidebarTranslationLimits.max
});
this.$sidebar.niceScroll(); this.$sidebar.niceScroll();
this.$document.off('click', '.js-sidebar-build-toggle').on('click', '.js-sidebar-build-toggle', this.toggleSidebar); this.$document.off('click', '.js-sidebar-build-toggle').on('click', '.js-sidebar-build-toggle', this.toggleSidebar);
this.$document.off('scroll.translateSidebar').on('scroll.translateSidebar', this.translateSidebar.bind(this));
}; };
Build.prototype.location = function() { Build.prototype.location = function() {
...@@ -231,14 +223,6 @@ ...@@ -231,14 +223,6 @@
return bootstrapBreakpoint === 'xs' || bootstrapBreakpoint === 'sm'; return bootstrapBreakpoint === 'xs' || bootstrapBreakpoint === 'sm';
}; };
Build.prototype.translateSidebar = function(e) {
var newPosition = this.sidebarTranslationLimits.max - (document.body.scrollTop || document.documentElement.scrollTop);
if (newPosition < this.sidebarTranslationLimits.min) newPosition = this.sidebarTranslationLimits.min;
this.$sidebar.css({
top: newPosition
});
};
Build.prototype.toggleSidebar = function(shouldHide) { Build.prototype.toggleSidebar = function(shouldHide) {
var shouldShow = typeof shouldHide === 'boolean' ? !shouldHide : undefined; var shouldShow = typeof shouldHide === 'boolean' ? !shouldHide : undefined;
this.$buildScroll.toggleClass('sidebar-expanded', shouldShow) this.$buildScroll.toggleClass('sidebar-expanded', shouldShow)
...@@ -285,7 +269,7 @@ ...@@ -285,7 +269,7 @@
e.preventDefault(); e.preventDefault();
$currentTarget = $(e.currentTarget); $currentTarget = $(e.currentTarget);
$.scrollTo($currentTarget.attr('href'), { $.scrollTo($currentTarget.attr('href'), {
offset: -($('.navbar-gitlab').outerHeight() + $('.layout-nav').outerHeight()) offset: 0
}); });
}; };
......
...@@ -91,6 +91,9 @@ require('./lib/utils/common_utils'); ...@@ -91,6 +91,9 @@ require('./lib/utils/common_utils');
}, },
}, },
SanitizationFilter: { SanitizationFilter: {
'a[name]:not([href]):empty'(el, text) {
return el.outerHTML;
},
'dl'(el, text) { 'dl'(el, text) {
let lines = text.trim().split('\n'); let lines = text.trim().split('\n');
// Add two spaces to the front of subsequent list items lines, // Add two spaces to the front of subsequent list items lines,
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
/* global Flash */ /* global Flash */
window.Vue = require('vue'); window.Vue = require('vue');
window.Cookies = require('vendor/js.cookie'); window.Cookies = require('js-cookie');
function requireAll(context) { return context.keys().map(context); } function requireAll(context) { return context.keys().map(context); }
requireAll(require.context('./svg', false, /^\.\/.*\.(js|es6)$/)); requireAll(require.context('./svg', false, /^\.\/.*\.(js|es6)$/));
......
...@@ -76,7 +76,7 @@ require('./lib/utils/url_utility'); ...@@ -76,7 +76,7 @@ require('./lib/utils/url_utility');
const diffFile = diffTitle.closest('.diff-file'); const diffFile = diffTitle.closest('.diff-file');
const nothingHereBlock = $('.nothing-here-block:visible', diffFile); const nothingHereBlock = $('.nothing-here-block:visible', diffFile);
if (nothingHereBlock.length) { if (nothingHereBlock.length) {
const clickTarget = $('.file-title, .click-to-expand', diffFile); const clickTarget = $('.js-file-title, .click-to-expand', diffFile);
diffFile.data('singleFileDiff').toggleDiff(clickTarget, () => { diffFile.data('singleFileDiff').toggleDiff(clickTarget, () => {
this.highlighSelectedLine(); this.highlighSelectedLine();
if (cb) cb(); if (cb) cb();
......
/* eslint-disable comma-dangle, object-shorthand, func-names, no-else-return, quotes, no-lonely-if, max-len */ /* eslint-disable comma-dangle, object-shorthand, func-names, no-else-return, quotes, no-lonely-if, max-len */
/* global Vue */
/* global CommentsStore */ /* global CommentsStore */
const Vue = require('vue');
(() => { (() => {
const CommentAndResolveBtn = Vue.extend({ const CommentAndResolveBtn = Vue.extend({
...@@ -9,13 +9,11 @@ ...@@ -9,13 +9,11 @@
}, },
data() { data() {
return { return {
textareaIsEmpty: true textareaIsEmpty: true,
discussion: {},
}; };
}, },
computed: { computed: {
discussion: function () {
return CommentsStore.state[this.discussionId];
},
showButton: function () { showButton: function () {
if (this.discussion) { if (this.discussion) {
return this.discussion.isResolvable(); return this.discussion.isResolvable();
...@@ -42,6 +40,9 @@ ...@@ -42,6 +40,9 @@
} }
} }
}, },
created() {
this.discussion = CommentsStore.state[this.discussionId];
},
mounted: function () { mounted: function () {
const $textarea = $(`#new-discussion-note-form-${this.discussionId} .note-textarea`); const $textarea = $(`#new-discussion-note-form-${this.discussionId} .note-textarea`);
this.textareaIsEmpty = $textarea.val() === ''; this.textareaIsEmpty = $textarea.val() === '';
......
/* eslint-disable comma-dangle, object-shorthand, func-names, no-else-return, guard-for-in, no-restricted-syntax, one-var, space-before-function-paren, no-lonely-if, no-continue, brace-style, max-len, quotes */ /* eslint-disable comma-dangle, object-shorthand, func-names, no-else-return, guard-for-in, no-restricted-syntax, one-var, space-before-function-paren, no-lonely-if, no-continue, brace-style, max-len, quotes */
/* global Vue */
/* global DiscussionMixins */ /* global DiscussionMixins */
/* global CommentsStore */ /* global CommentsStore */
const Vue = require('vue');
(() => { (() => {
const JumpToDiscussion = Vue.extend({ const JumpToDiscussion = Vue.extend({
...@@ -12,12 +12,10 @@ ...@@ -12,12 +12,10 @@
data: function () { data: function () {
return { return {
discussions: CommentsStore.state, discussions: CommentsStore.state,
discussion: {},
}; };
}, },
computed: { computed: {
discussion: function () {
return this.discussions[this.discussionId];
},
allResolved: function () { allResolved: function () {
return this.unresolvedDiscussionCount === 0; return this.unresolvedDiscussionCount === 0;
}, },
...@@ -183,10 +181,13 @@ ...@@ -183,10 +181,13 @@
} }
$.scrollTo($target, { $.scrollTo($target, {
offset: -($('.navbar-gitlab').outerHeight() + $('.layout-nav').outerHeight()) offset: 0
}); });
} }
} },
created() {
this.discussion = this.discussions[this.discussionId];
},
}); });
Vue.component('jump-to-discussion', JumpToDiscussion); Vue.component('jump-to-discussion', JumpToDiscussion);
......
/* eslint-disable comma-dangle, object-shorthand, func-names, quote-props, no-else-return, camelcase, no-new, max-len */ /* eslint-disable comma-dangle, object-shorthand, func-names, quote-props, no-else-return, camelcase, no-new, max-len */
/* global Vue */
/* global CommentsStore */ /* global CommentsStore */
/* global ResolveService */ /* global ResolveService */
/* global Flash */ /* global Flash */
const Vue = require('vue');
(() => { (() => {
const ResolveBtn = Vue.extend({ const ResolveBtn = Vue.extend({
...@@ -10,14 +10,14 @@ ...@@ -10,14 +10,14 @@
noteId: Number, noteId: Number,
discussionId: String, discussionId: String,
resolved: Boolean, resolved: Boolean,
projectPath: String,
canResolve: Boolean, canResolve: Boolean,
resolvedBy: String resolvedBy: String
}, },
data: function () { data: function () {
return { return {
discussions: CommentsStore.state, discussions: CommentsStore.state,
loading: false loading: false,
note: {},
}; };
}, },
watch: { watch: {
...@@ -30,13 +30,6 @@ ...@@ -30,13 +30,6 @@
discussion: function () { discussion: function () {
return this.discussions[this.discussionId]; return this.discussions[this.discussionId];
}, },
note: function () {
if (this.discussion) {
return this.discussion.getNote(this.noteId);
} else {
return undefined;
}
},
buttonText: function () { buttonText: function () {
if (this.isResolved) { if (this.isResolved) {
return `Resolved by ${this.resolvedByName}`; return `Resolved by ${this.resolvedByName}`;
...@@ -73,10 +66,10 @@ ...@@ -73,10 +66,10 @@
if (this.isResolved) { if (this.isResolved) {
promise = ResolveService promise = ResolveService
.unresolve(this.projectPath, this.noteId); .unresolve(this.noteId);
} else { } else {
promise = ResolveService promise = ResolveService
.resolve(this.projectPath, this.noteId); .resolve(this.noteId);
} }
promise.then((response) => { promise.then((response) => {
...@@ -106,6 +99,8 @@ ...@@ -106,6 +99,8 @@
}, },
created: function () { created: function () {
CommentsStore.create(this.discussionId, this.noteId, this.canResolve, this.resolved, this.resolvedBy); CommentsStore.create(this.discussionId, this.noteId, this.canResolve, this.resolved, this.resolvedBy);
this.note = this.discussion.getNote(this.noteId);
} }
}); });
......
/* eslint-disable comma-dangle, object-shorthand, func-names, no-param-reassign */ /* eslint-disable comma-dangle, object-shorthand, func-names, no-param-reassign */
/* global Vue */
/* global DiscussionMixins */ /* global DiscussionMixins */
/* global CommentsStore */ /* global CommentsStore */
const Vue = require('vue');
((w) => { ((w) => {
w.ResolveCount = Vue.extend({ w.ResolveCount = Vue.extend({
......
/* eslint-disable object-shorthand, func-names, space-before-function-paren, comma-dangle, no-else-return, quotes, max-len */ /* eslint-disable object-shorthand, func-names, space-before-function-paren, comma-dangle, no-else-return, quotes, max-len */
/* global Vue */
/* global CommentsStore */ /* global CommentsStore */
/* global ResolveService */ /* global ResolveService */
const Vue = require('vue');
(() => { (() => {
const ResolveDiscussionBtn = Vue.extend({ const ResolveDiscussionBtn = Vue.extend({
props: { props: {
discussionId: String, discussionId: String,
mergeRequestId: Number, mergeRequestId: Number,
projectPath: String,
canResolve: Boolean, canResolve: Boolean,
}, },
data: function() { data: function() {
return { return {
discussions: CommentsStore.state discussion: {},
}; };
}, },
computed: { computed: {
discussion: function () {
return this.discussions[this.discussionId];
},
showButton: function () { showButton: function () {
if (this.discussion) { if (this.discussion) {
return this.discussion.isResolvable(); return this.discussion.isResolvable();
...@@ -51,11 +48,13 @@ ...@@ -51,11 +48,13 @@
}, },
methods: { methods: {
resolve: function () { resolve: function () {
ResolveService.toggleResolveForDiscussion(this.projectPath, this.mergeRequestId, this.discussionId); ResolveService.toggleResolveForDiscussion(this.mergeRequestId, this.discussionId);
} }
}, },
created: function () { created: function () {
CommentsStore.createDiscussion(this.discussionId, this.canResolve); CommentsStore.createDiscussion(this.discussionId, this.canResolve);
this.discussion = CommentsStore.state[this.discussionId];
} }
}); });
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
/* global ResolveCount */ /* global ResolveCount */
function requireAll(context) { return context.keys().map(context); } function requireAll(context) { return context.keys().map(context); }
const Vue = require('vue');
requireAll(require.context('./models', false, /^\.\/.*\.(js|es6)$/)); requireAll(require.context('./models', false, /^\.\/.*\.(js|es6)$/));
requireAll(require.context('./stores', false, /^\.\/.*\.(js|es6)$/)); requireAll(require.context('./stores', false, /^\.\/.*\.(js|es6)$/));
requireAll(require.context('./services', false, /^\.\/.*\.(js|es6)$/)); requireAll(require.context('./services', false, /^\.\/.*\.(js|es6)$/));
...@@ -10,11 +11,14 @@ requireAll(require.context('./mixins', false, /^\.\/.*\.(js|es6)$/)); ...@@ -10,11 +11,14 @@ requireAll(require.context('./mixins', false, /^\.\/.*\.(js|es6)$/));
requireAll(require.context('./components', false, /^\.\/.*\.(js|es6)$/)); requireAll(require.context('./components', false, /^\.\/.*\.(js|es6)$/));
$(() => { $(() => {
const projectPath = document.querySelector('.merge-request').dataset.projectPath;
const COMPONENT_SELECTOR = 'resolve-btn, resolve-discussion-btn, jump-to-discussion, comment-and-resolve-btn'; const COMPONENT_SELECTOR = 'resolve-btn, resolve-discussion-btn, jump-to-discussion, comment-and-resolve-btn';
window.gl = window.gl || {}; window.gl = window.gl || {};
window.gl.diffNoteApps = {}; window.gl.diffNoteApps = {};
window.ResolveService = new gl.DiffNotesResolveServiceClass(projectPath);
gl.diffNotesCompileComponents = () => { gl.diffNotesCompileComponents = () => {
const $components = $(COMPONENT_SELECTOR).filter(function () { const $components = $(COMPONENT_SELECTOR).filter(function () {
return $(this).closest('resolve-count').length !== 1; return $(this).closest('resolve-count').length !== 1;
......
/* eslint-disable class-methods-use-this, one-var, camelcase, no-new, comma-dangle, no-param-reassign, max-len */ /* eslint-disable class-methods-use-this, one-var, camelcase, no-new, comma-dangle, no-param-reassign, max-len */
/* global Vue */
/* global Flash */ /* global Flash */
/* global CommentsStore */ /* global CommentsStore */
((w) => { const Vue = window.Vue = require('vue');
class ResolveServiceClass { window.Vue.use(require('vue-resource'));
constructor() { require('../../vue_shared/vue_resource_interceptor');
this.noteResource = Vue.resource('notes{/noteId}/resolve');
this.discussionResource = Vue.resource('merge_requests{/mergeRequestId}/discussions{/discussionId}/resolve');
}
setCSRF() { (() => {
Vue.http.headers.common['X-CSRF-Token'] = $.rails.csrfToken(); window.gl = window.gl || {};
}
prepareRequest(root) { class ResolveServiceClass {
this.setCSRF(); constructor(root) {
Vue.http.options.root = root; this.noteResource = Vue.resource(`${root}/notes{/noteId}/resolve`);
this.discussionResource = Vue.resource(`${root}/merge_requests{/mergeRequestId}/discussions{/discussionId}/resolve`);
} }
resolve(projectPath, noteId) { resolve(noteId) {
this.prepareRequest(projectPath);
return this.noteResource.save({ noteId }, {}); return this.noteResource.save({ noteId }, {});
} }
unresolve(projectPath, noteId) { unresolve(noteId) {
this.prepareRequest(projectPath);
return this.noteResource.delete({ noteId }, {}); return this.noteResource.delete({ noteId }, {});
} }
toggleResolveForDiscussion(projectPath, mergeRequestId, discussionId) { toggleResolveForDiscussion(mergeRequestId, discussionId) {
const discussion = CommentsStore.state[discussionId]; const discussion = CommentsStore.state[discussionId];
const isResolved = discussion.isResolved(); const isResolved = discussion.isResolved();
let promise; let promise;
if (isResolved) { if (isResolved) {
promise = this.unResolveAll(projectPath, mergeRequestId, discussionId); promise = this.unResolveAll(mergeRequestId, discussionId);
} else { } else {
promise = this.resolveAll(projectPath, mergeRequestId, discussionId); promise = this.resolveAll(mergeRequestId, discussionId);
} }
promise.then((response) => { promise.then((response) => {
...@@ -62,11 +54,9 @@ ...@@ -62,11 +54,9 @@
}); });
} }
resolveAll(projectPath, mergeRequestId, discussionId) { resolveAll(mergeRequestId, discussionId) {
const discussion = CommentsStore.state[discussionId]; const discussion = CommentsStore.state[discussionId];
this.prepareRequest(projectPath);
discussion.loading = true; discussion.loading = true;
return this.discussionResource.save({ return this.discussionResource.save({
...@@ -75,11 +65,9 @@ ...@@ -75,11 +65,9 @@
}, {}); }, {});
} }
unResolveAll(projectPath, mergeRequestId, discussionId) { unResolveAll(mergeRequestId, discussionId) {
const discussion = CommentsStore.state[discussionId]; const discussion = CommentsStore.state[discussionId];
this.prepareRequest(projectPath);
discussion.loading = true; discussion.loading = true;
return this.discussionResource.delete({ return this.discussionResource.delete({
...@@ -89,5 +77,5 @@ ...@@ -89,5 +77,5 @@
} }
} }
w.ResolveService = new ResolveServiceClass(); gl.DiffNotesResolveServiceClass = ResolveServiceClass;
})(window); })();
const Vue = require('vue'); const Vue = require('vue');
const Timeago = require('vendor/timeago'); const Timeago = require('timeago.j');
require('../../lib/utils/text_utility'); require('../../lib/utils/text_utility');
require('../../vue_shared/components/commit'); require('../../vue_shared/components/commit');
const ActionsComponent = require('./environment_actions'); const ActionsComponent = require('./environment_actions');
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
class FilteredSearchDropdown { class FilteredSearchDropdown {
constructor(droplab, dropdown, input, filter) { constructor(droplab, dropdown, input, filter) {
this.droplab = droplab; this.droplab = droplab;
this.hookId = input.getAttribute('data-id'); this.hookId = input && input.getAttribute('data-id');
this.input = input; this.input = input;
this.filter = filter; this.filter = filter;
this.dropdown = dropdown; this.dropdown = dropdown;
......
...@@ -72,27 +72,18 @@ ...@@ -72,27 +72,18 @@
// This is required to handle non-unicode characters in hash // This is required to handle non-unicode characters in hash
hash = decodeURIComponent(hash); hash = decodeURIComponent(hash);
var navbar = document.querySelector('.navbar-gitlab');
var subnav = document.querySelector('.layout-nav');
var fixedTabs = document.querySelector('.js-tabs-affix');
var adjustment = 0;
if (navbar) adjustment -= navbar.offsetHeight;
if (subnav) adjustment -= subnav.offsetHeight;
// scroll to user-generated markdown anchor if we cannot find a match // scroll to user-generated markdown anchor if we cannot find a match
if (document.getElementById(hash) === null) { if (document.getElementById(hash) === null) {
var target = document.getElementById('user-content-' + hash); var target = document.getElementById('user-content-' + hash);
if (target && target.scrollIntoView) { if (target && target.scrollIntoView) {
target.scrollIntoView(true); target.scrollIntoView(true);
window.scrollBy(0, adjustment);
} }
} else { } else {
// only adjust for fixedTabs when not targeting user-generated content // only adjust for fixedTabs when not targeting user-generated content
var fixedTabs = document.querySelector('.js-tabs-affix');
if (fixedTabs) { if (fixedTabs) {
adjustment -= fixedTabs.offsetHeight; window.scrollBy(0, -fixedTabs.offsetHeight);
} }
window.scrollBy(0, adjustment);
} }
}; };
...@@ -147,12 +138,10 @@ ...@@ -147,12 +138,10 @@
gl.utils.scrollToElement = function($el) { gl.utils.scrollToElement = function($el) {
var top = $el.offset().top; var top = $el.offset().top;
gl.navBarHeight = gl.navBarHeight || $('.navbar-gitlab').height();
gl.navLinksHeight = gl.navLinksHeight || $('.nav-links').height();
gl.mrTabsHeight = gl.mrTabsHeight || $('.merge-request-tabs').height(); gl.mrTabsHeight = gl.mrTabsHeight || $('.merge-request-tabs').height();
return $('body, html').animate({ return $('body, html').animate({
scrollTop: top - (gl.navBarHeight + gl.navLinksHeight + gl.mrTabsHeight) scrollTop: top - (gl.mrTabsHeight)
}, 200); }, 200);
}; };
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
/* global timeago */ /* global timeago */
/* global dateFormat */ /* global dateFormat */
window.timeago = require('vendor/timeago'); window.timeago = require('timeago.js');
window.dateFormat = require('vendor/date.format'); window.dateFormat = require('vendor/date.format');
(function() { (function() {
......
...@@ -115,8 +115,8 @@ require('./merge_request_tabs'); ...@@ -115,8 +115,8 @@ require('./merge_request_tabs');
e.preventDefault(); e.preventDefault();
textarea.val(textarea.data('messageWithDescription')); textarea.val(textarea.data('messageWithDescription'));
$('p.js-with-description-hint').hide(); $('.js-with-description-hint').hide();
$('p.js-without-description-hint').show(); $('.js-without-description-hint').show();
}); });
$(document).on('click', 'a.js-without-description-link', function(e) { $(document).on('click', 'a.js-without-description-link', function(e) {
...@@ -124,8 +124,8 @@ require('./merge_request_tabs'); ...@@ -124,8 +124,8 @@ require('./merge_request_tabs');
e.preventDefault(); e.preventDefault();
textarea.val(textarea.data('messageWithoutDescription')); textarea.val(textarea.data('messageWithoutDescription'));
$('p.js-with-description-hint').show(); $('.js-with-description-hint').show();
$('p.js-without-description-hint').hide(); $('.js-without-description-hint').hide();
}); });
}; };
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
/* global Flash */ /* global Flash */
require('./breakpoints'); require('./breakpoints');
window.Cookies = require('vendor/js.cookie'); window.Cookies = require('js-cookie');
require('./flash'); require('./flash');
/* eslint-disable max-len */ /* eslint-disable max-len */
...@@ -125,9 +125,8 @@ require('./flash'); ...@@ -125,9 +125,8 @@ require('./flash');
if (this.diffViewType() === 'parallel') { if (this.diffViewType() === 'parallel') {
this.expandViewContainer(); this.expandViewContainer();
} }
const navBarHeight = $('.navbar-gitlab').outerHeight();
$.scrollTo('.merge-request-details .merge-request-tabs', { $.scrollTo('.merge-request-details .merge-request-tabs', {
offset: -navBarHeight, offset: 0,
}); });
} else { } else {
this.expandView(); this.expandView();
...@@ -140,11 +139,7 @@ require('./flash'); ...@@ -140,11 +139,7 @@ require('./flash');
scrollToElement(container) { scrollToElement(container) {
if (location.hash) { if (location.hash) {
const offset = 0 - ( const offset = -$('.js-tabs-affix').outerHeight();
$('.navbar-gitlab').outerHeight() +
$('.layout-nav').outerHeight() +
$('.js-tabs-affix').outerHeight()
);
const $el = $(`${container} ${location.hash}:not(.match)`); const $el = $(`${container} ${location.hash}:not(.match)`);
if ($el.length) { if ($el.length) {
$.scrollTo($el[0], { offset }); $.scrollTo($el[0], { offset });
...@@ -330,14 +325,12 @@ require('./flash'); ...@@ -330,14 +325,12 @@ require('./flash');
if (Breakpoints.get().getBreakpointSize() === 'xs' || !$tabs.length) return; if (Breakpoints.get().getBreakpointSize() === 'xs' || !$tabs.length) return;
const $diffTabs = $('#diff-notes-app'); const $diffTabs = $('#diff-notes-app');
const $fixedNav = $('.navbar-fixed-top');
const $layoutNav = $('.layout-nav');
$tabs.off('affix.bs.affix affix-top.bs.affix') $tabs.off('affix.bs.affix affix-top.bs.affix')
.affix({ .affix({
offset: { offset: {
top: () => ( top: () => (
$diffTabs.offset().top - $tabs.height() - $fixedNav.height() - $layoutNav.height() $diffTabs.offset().top - $tabs.height()
), ),
}, },
}) })
......
...@@ -154,7 +154,7 @@ require('./smart_interval'); ...@@ -154,7 +154,7 @@ require('./smart_interval');
return $.getJSON(this.opts.ci_status_url, (function(_this) { return $.getJSON(this.opts.ci_status_url, (function(_this) {
return function(data) { return function(data) {
var message, status, title; var message, status, title;
if (data.status === '') { if (!data.status) {
return; return;
} }
if (data.environments && data.environments.length) _this.renderEnvironments(data.environments); if (data.environments && data.environments.length) _this.renderEnvironments(data.environments);
......
...@@ -455,7 +455,7 @@ require('vendor/task_list'); ...@@ -455,7 +455,7 @@ require('vendor/task_list');
var mergeRequestId = $form.data('noteable-iid'); var mergeRequestId = $form.data('noteable-iid');
if (ResolveService != null) { if (ResolveService != null) {
ResolveService.toggleResolveForDiscussion(projectPath, mergeRequestId, discussionId); ResolveService.toggleResolveForDiscussion(mergeRequestId, discussionId);
} }
} }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
const sidebarBreakpoint = 1024; const sidebarBreakpoint = 1024;
const pageSelector = '.page-with-sidebar'; const pageSelector = '.page-with-sidebar';
const navbarSelector = '.navbar-fixed-top'; const navbarSelector = '.navbar-gitlab';
const sidebarWrapperSelector = '.sidebar-wrapper'; const sidebarWrapperSelector = '.sidebar-wrapper';
const sidebarContentSelector = '.nav-sidebar'; const sidebarContentSelector = '.nav-sidebar';
...@@ -35,13 +35,16 @@ ...@@ -35,13 +35,16 @@
window.innerWidth >= sidebarBreakpoint && window.innerWidth >= sidebarBreakpoint &&
$(pageSelector).hasClass(expandedPageClass) $(pageSelector).hasClass(expandedPageClass)
); );
$(window).on('resize', () => this.setSidebarHeight());
$(document) $(document)
.on('click', sidebarToggleSelector, () => this.toggleSidebar()) .on('click', sidebarToggleSelector, () => this.toggleSidebar())
.on('click', pinnedToggleSelector, () => this.togglePinnedState()) .on('click', pinnedToggleSelector, () => this.togglePinnedState())
.on('click', 'html, body, a, button', (e) => this.handleClickEvent(e)) .on('click', 'html, body, a, button', (e) => this.handleClickEvent(e))
.on('DOMContentLoaded', () => this.renderState()) .on('DOMContentLoaded', () => this.renderState())
.on('scroll', () => this.setSidebarHeight())
.on('todo:toggle', (e, count) => this.updateTodoCount(count)); .on('todo:toggle', (e, count) => this.updateTodoCount(count));
this.renderState(); this.renderState();
this.setSidebarHeight();
} }
handleClickEvent(e) { handleClickEvent(e) {
...@@ -64,6 +67,16 @@ ...@@ -64,6 +67,16 @@
this.renderState(); this.renderState();
} }
setSidebarHeight() {
const $navHeight = $('.navbar-gitlab').outerHeight() + $('.layout-nav').outerHeight();
const diff = $navHeight - $('body').scrollTop();
if (diff > 0) {
$('.js-right-sidebar').outerHeight($(window).height() - diff);
} else {
$('.js-right-sidebar').outerHeight('100%');
}
}
togglePinnedState() { togglePinnedState() {
this.isPinned = !this.isPinned; this.isPinned = !this.isPinned;
if (!this.isPinned) { if (!this.isPinned) {
......
...@@ -33,13 +33,13 @@ ...@@ -33,13 +33,13 @@
this.$toggleIcon.addClass('fa-caret-down'); this.$toggleIcon.addClass('fa-caret-down');
} }
$('.file-title, .click-to-expand', this.file).on('click', (function (e) { $('.js-file-title, .click-to-expand', this.file).on('click', (function (e) {
this.toggleDiff($(e.target)); this.toggleDiff($(e.target));
}).bind(this)); }).bind(this));
} }
SingleFileDiff.prototype.toggleDiff = function($target, cb) { SingleFileDiff.prototype.toggleDiff = function($target, cb) {
if (!$target.hasClass('file-title') && !$target.hasClass('click-to-expand') && !$target.hasClass('diff-toggle-caret')) return; if (!$target.hasClass('js-file-title') && !$target.hasClass('click-to-expand') && !$target.hasClass('diff-toggle-caret')) return;
this.isOpen = !this.isOpen; this.isOpen = !this.isOpen;
if (!this.isOpen && !this.hasError) { if (!this.isOpen && !this.hasError) {
this.content.hide(); this.content.hide();
......
...@@ -9,6 +9,8 @@ ...@@ -9,6 +9,8 @@
} }
.user-calendar-activities { .user-calendar-activities {
direction: ltr;
.str-truncated { .str-truncated {
max-width: 70%; max-width: 70%;
} }
......
...@@ -125,7 +125,6 @@ ...@@ -125,7 +125,6 @@
top: 100%; top: 100%;
left: 0; left: 0;
z-index: 9; z-index: 9;
max-width: 280px;
min-width: 240px; min-width: 240px;
margin-top: 2px; margin-top: 2px;
margin-bottom: 0; margin-bottom: 0;
...@@ -137,6 +136,10 @@ ...@@ -137,6 +136,10 @@
border-radius: $border-radius-base; border-radius: $border-radius-base;
box-shadow: 0 2px 4px $dropdown-shadow-color; box-shadow: 0 2px 4px $dropdown-shadow-color;
.filtered-search-input-container & {
max-width: 280px;
}
&.is-loading { &.is-loading {
.dropdown-content { .dropdown-content {
display: none; display: none;
......
...@@ -231,3 +231,46 @@ span.idiff { ...@@ -231,3 +231,46 @@ span.idiff {
} }
} }
} }
.file-title-flex-parent {
display: flex;
align-items: center;
justify-content: space-between;
background-color: $gray-light;
border-bottom: 1px solid $border-color;
padding: 5px $gl-padding;
margin: 0;
border-radius: 3px 3px 0 0;
.file-header-content {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding-right: 30px;
position: relative;
}
.btn-clipboard {
position: absolute;
right: 0;
}
a {
color: $gl-text-color;
}
small {
margin: 0 10px 0 0;
}
.file-actions {
white-space: nowrap;
.btn {
padding: 0 10px;
font-size: 13px;
line-height: 28px;
display: inline-block;
}
}
}
...@@ -222,6 +222,10 @@ header { ...@@ -222,6 +222,10 @@ header {
float: right; float: right;
border-top: none; border-top: none;
@media (min-width: $screen-md-min) {
padding: 0;
}
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
float: none; float: none;
} }
...@@ -272,7 +276,7 @@ header { ...@@ -272,7 +276,7 @@ header {
.header-user { .header-user {
.dropdown-menu-nav { .dropdown-menu-nav {
width: 140px; min-width: 140px;
margin-top: -5px; margin-top: -5px;
} }
} }
......
...@@ -283,10 +283,7 @@ ...@@ -283,10 +283,7 @@
} }
.layout-nav { .layout-nav {
position: fixed;
top: $header-height;
width: 100%; width: 100%;
z-index: 11;
background: $gray-light; background: $gray-light;
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
transition: padding $sidebar-transition-duration; transition: padding $sidebar-transition-duration;
...@@ -419,15 +416,20 @@ ...@@ -419,15 +416,20 @@
} }
.page-with-layout-nav { .page-with-layout-nav {
margin-top: $header-height + 2;
.right-sidebar { .right-sidebar {
top: ($header-height * 2) + 2; top: ($header-height * 2) + 2;
} }
.build-sidebar {
top: ($header-height * 3) + 3;
&.affix {
top: 0;
}
}
} }
.activities { .activities {
.nav-block { .nav-block {
border-bottom: 1px solid $border-color; border-bottom: 1px solid $border-color;
......
.page-with-sidebar { .page-with-sidebar {
padding: $header-height 0 25px; padding-bottom: 25px;
transition: padding $sidebar-transition-duration; transition: padding $sidebar-transition-duration;
&.page-sidebar-pinned { &.page-sidebar-pinned {
...@@ -208,7 +208,9 @@ header.header-sidebar-pinned { ...@@ -208,7 +208,9 @@ header.header-sidebar-pinned {
padding-right: 0; padding-right: 0;
@media (min-width: $screen-sm-min) { @media (min-width: $screen-sm-min) {
.content-wrapper {
padding-right: $sidebar_collapsed_width; padding-right: $sidebar_collapsed_width;
}
.merge-request-tabs-holder.affix { .merge-request-tabs-holder.affix {
right: $sidebar_collapsed_width; right: $sidebar_collapsed_width;
...@@ -234,7 +236,9 @@ header.header-sidebar-pinned { ...@@ -234,7 +236,9 @@ header.header-sidebar-pinned {
} }
@media (min-width: $screen-md-min) { @media (min-width: $screen-md-min) {
.content-wrapper {
padding-right: $gutter_width; padding-right: $gutter_width;
}
&:not(.with-overlay) .merge-request-tabs-holder.affix { &:not(.with-overlay) .merge-request-tabs-holder.affix {
right: $gutter_width; right: $gutter_width;
...@@ -252,4 +256,9 @@ header.header-sidebar-pinned { ...@@ -252,4 +256,9 @@ header.header-sidebar-pinned {
.right-sidebar { .right-sidebar {
border-left: 1px solid $border-color; border-left: 1px solid $border-color;
&.affix {
position: fixed;
top: 0;
}
} }
...@@ -138,6 +138,13 @@ pre { ...@@ -138,6 +138,13 @@ pre {
margin: 0; margin: 0;
} }
blockquote {
color: $gl-grayish-blue;
padding: 0 0 0 15px;
margin: 0;
border-left: 3px solid $white-dark;
}
span.highlight_word { span.highlight_word {
background-color: $highlighted-highlight-word !important; background-color: $highlighted-highlight-word !important;
} }
......
...@@ -298,12 +298,8 @@ ...@@ -298,12 +298,8 @@
.issue-boards-sidebar { .issue-boards-sidebar {
&.right-sidebar { &.right-sidebar {
top: 153px; top: 0;
bottom: 0; bottom: 0;
@media (min-width: $screen-sm-min) {
top: 220px;
}
} }
.issuable-sidebar-header { .issuable-sidebar-header {
......
...@@ -34,9 +34,14 @@ ...@@ -34,9 +34,14 @@
} }
} }
.file-title { .file-title,
.file-title-flex-parent {
cursor: pointer; cursor: pointer;
a:hover {
text-decoration: none;
}
&:hover { &:hover {
background-color: $gray-normal; background-color: $gray-normal;
} }
......
...@@ -189,7 +189,7 @@ ...@@ -189,7 +189,7 @@
} }
.right-sidebar { .right-sidebar {
position: fixed; position: absolute;
top: $header-height; top: $header-height;
bottom: 0; bottom: 0;
right: 0; right: 0;
...@@ -461,8 +461,19 @@ ...@@ -461,8 +461,19 @@
.issuable-list { .issuable-list {
li { li {
.issue-box {
display: -webkit-flex;
display: flex;
}
.issue-info-container {
-webkit-flex: 1;
flex: 1;
padding-right: $gl-padding;
}
.issue-check { .issue-check {
float: left;
padding-right: $gl-padding; padding-right: $gl-padding;
margin-bottom: 10px; margin-bottom: 10px;
min-width: 15px; min-width: 15px;
......
.issues-list { .issues-list {
.issue { .issue {
padding: 10px $gl-padding; padding: 10px 0 10px $gl-padding;
position: relative; position: relative;
.title { .title {
......
...@@ -96,13 +96,6 @@ ...@@ -96,13 +96,6 @@
padding-right: 4px; padding-right: 4px;
} }
&.ci-success_with_warnings {
i {
color: $gl-warning;
}
}
@media (max-width: $screen-xs-max) { @media (max-width: $screen-xs-max) {
flex-wrap: wrap; flex-wrap: wrap;
} }
...@@ -272,8 +265,15 @@ ...@@ -272,8 +265,15 @@
.mr-list { .mr-list {
.merge-request { .merge-request {
padding: 10px 15px; padding: 10px 0 10px 15px;
position: relative; position: relative;
display: -webkit-flex;
display: flex;
.issue-info-container {
-webkit-flex: 1;
flex: 1;
}
.merge-request-title { .merge-request-title {
margin-bottom: 2px; margin-bottom: 2px;
...@@ -479,7 +479,7 @@ ...@@ -479,7 +479,7 @@
background-color: $white-light; background-color: $white-light;
&.affix { &.affix {
top: 100px; top: 0;
left: 0; left: 0;
z-index: 10; z-index: 10;
transition: right .15s; transition: right .15s;
......
...@@ -94,6 +94,10 @@ ...@@ -94,6 +94,10 @@
padding: 10px 8px; padding: 10px 8px;
} }
td.stage-cell {
padding: 10px 0;
}
.commit-link { .commit-link {
padding: 9px 8px 10px; padding: 9px 8px 10px;
} }
...@@ -291,12 +295,14 @@ ...@@ -291,12 +295,14 @@
height: 22px; height: 22px;
margin: 3px 6px 3px 0; margin: 3px 6px 3px 0;
.tooltip { // Hack to show a button tooltip inline
white-space: nowrap; button.has-tooltip + .tooltip {
min-width: 105px;
} }
.tooltip-inner { // Bootstrap way of showing the content inline for anchors.
padding: 3px 4px; a.has-tooltip {
white-space: nowrap;
} }
&:not(:last-child) { &:not(:last-child) {
......
...@@ -171,8 +171,6 @@ ...@@ -171,8 +171,6 @@
.tree-controls { .tree-controls {
float: right; float: right;
margin-top: 11px; margin-top: 11px;
position: relative;
z-index: 2;
.project-action-button { .project-action-button {
margin-left: $btn-side-margin; margin-left: $btn-side-margin;
......
...@@ -12,7 +12,6 @@ class ApplicationController < ActionController::Base ...@@ -12,7 +12,6 @@ class ApplicationController < ActionController::Base
before_action :authenticate_user_from_private_token! before_action :authenticate_user_from_private_token!
before_action :authenticate_user! before_action :authenticate_user!
before_action :validate_user_service_ticket! before_action :validate_user_service_ticket!
before_action :reject_blocked!
before_action :check_password_expiration before_action :check_password_expiration
before_action :check_2fa_requirement before_action :check_2fa_requirement
before_action :ldap_security_check before_action :ldap_security_check
...@@ -87,23 +86,9 @@ class ApplicationController < ActionController::Base ...@@ -87,23 +86,9 @@ class ApplicationController < ActionController::Base
logger.error "\n#{exception.class.name} (#{exception.message}):\n#{application_trace.join}" logger.error "\n#{exception.class.name} (#{exception.message}):\n#{application_trace.join}"
end end
def reject_blocked!
if current_user && current_user.blocked?
sign_out current_user
flash[:alert] = "Your account is blocked. Retry when an admin has unblocked it."
redirect_to new_user_session_path
end
end
def after_sign_in_path_for(resource) def after_sign_in_path_for(resource)
if resource.is_a?(User) && resource.respond_to?(:blocked?) && resource.blocked?
sign_out resource
flash[:alert] = "Your account is blocked. Retry when an admin has unblocked it."
new_user_session_path
else
stored_location_for(:redirect) || stored_location_for(resource) || root_path stored_location_for(:redirect) || stored_location_for(resource) || root_path
end end
end
def after_sign_out_path_for(resource) def after_sign_out_path_for(resource)
current_application_settings.after_sign_out_path.presence || new_user_session_path current_application_settings.after_sign_out_path.presence || new_user_session_path
......
class Explore::ApplicationController < ApplicationController class Explore::ApplicationController < ApplicationController
skip_before_action :authenticate_user!, :reject_blocked! skip_before_action :authenticate_user!
layout 'explore' layout 'explore'
end end
...@@ -9,7 +9,7 @@ class Groups::GroupMembersController < Groups::ApplicationController ...@@ -9,7 +9,7 @@ class Groups::GroupMembersController < Groups::ApplicationController
@sort = params[:sort].presence || sort_value_name @sort = params[:sort].presence || sort_value_name
@project = @group.projects.find(params[:project_id]) if params[:project_id] @project = @group.projects.find(params[:project_id]) if params[:project_id]
@members = @group.group_members @members = GroupMembersFinder.new(@group).execute
@members = @members.non_invite unless can?(current_user, :admin_group, @group) @members = @members.non_invite unless can?(current_user, :admin_group, @group)
@members = @members.search(params[:search]) if params[:search].present? @members = @members.search(params[:search]) if params[:search].present?
@members = @members.sort(@sort) @members = @members.sort(@sort)
......
class HelpController < ApplicationController class HelpController < ApplicationController
skip_before_action :authenticate_user!, :reject_blocked! skip_before_action :authenticate_user!
layout 'help' layout 'help'
......
class KodingController < ApplicationController class KodingController < ApplicationController
before_action :check_integration!, :authenticate_user!, :reject_blocked! before_action :check_integration!
layout 'koding' layout 'koding'
def index def index
......
...@@ -68,8 +68,12 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController ...@@ -68,8 +68,12 @@ class Projects::ProtectedBranchesController < Projects::ApplicationController
def access_levels_options def access_levels_options
{ {
push_access_levels: ProtectedBranch::PushAccessLevel.human_access_levels.map { |id, text| { id: id, text: text, before_divider: true } }, push_access_levels: {
merge_access_levels: ProtectedBranch::MergeAccessLevel.human_access_levels.map { |id, text| { id: id, text: text, before_divider: true } } "Roles" => ProtectedBranch::PushAccessLevel.human_access_levels.map { |id, text| { id: id, text: text, before_divider: true } },
},
merge_access_levels: {
"Roles" => ProtectedBranch::MergeAccessLevel.human_access_levels.map { |id, text| { id: id, text: text, before_divider: true } }
}
} }
end end
......
class Projects::UploadsController < Projects::ApplicationController class Projects::UploadsController < Projects::ApplicationController
skip_before_action :reject_blocked!, :project, skip_before_action :project, :repository,
:repository, if: -> { action_name == 'show' && image_or_video? } if: -> { action_name == 'show' && image_or_video? }
before_action :authorize_upload_file!, only: [:create] before_action :authorize_upload_file!, only: [:create]
......
class SearchController < ApplicationController class SearchController < ApplicationController
skip_before_action :authenticate_user!, :reject_blocked! skip_before_action :authenticate_user!
include SearchHelper include SearchHelper
......
class GroupMembersFinder < Projects::ApplicationController
def initialize(group)
@group = group
end
def execute
group_members = @group.members
return group_members unless @group.parent
parents_members = GroupMember.non_request.
where(source_id: @group.ancestors.select(:id)).
where.not(user_id: @group.users.select(:id))
wheres = ["members.id IN (#{group_members.select(:id).to_sql})"]
wheres << "members.id IN (#{parents_members.select(:id).to_sql})"
GroupMember.where(wheres.join(' OR '))
end
end
...@@ -206,7 +206,7 @@ class Group < Namespace ...@@ -206,7 +206,7 @@ class Group < Namespace
end end
def members_with_parents def members_with_parents
GroupMember.where(requested_at: nil, source_id: ancestors.map(&:id).push(id)) GroupMember.non_request.where(source_id: ancestors.map(&:id).push(id))
end end
def users_with_parents def users_with_parents
......
...@@ -47,6 +47,7 @@ class Member < ActiveRecord::Base ...@@ -47,6 +47,7 @@ class Member < ActiveRecord::Base
scope :invite, -> { where.not(invite_token: nil) } scope :invite, -> { where.not(invite_token: nil) }
scope :non_invite, -> { where(invite_token: nil) } scope :non_invite, -> { where(invite_token: nil) }
scope :request, -> { where.not(requested_at: nil) } scope :request, -> { where.not(requested_at: nil) }
scope :non_request, -> { where(requested_at: nil) }
scope :has_access, -> { active.where('access_level > 0') } scope :has_access, -> { active.where('access_level > 0') }
......
...@@ -250,21 +250,11 @@ class JiraService < IssueTrackerService ...@@ -250,21 +250,11 @@ class JiraService < IssueTrackerService
end end
end end
# Build remote link on JIRA properties
# Icons here must be available on WEB so JIRA can read the URL
# We are using a open word graphics icon which have LGPL license
def build_remote_link_props(url:, title:, resolved: false) def build_remote_link_props(url:, title:, resolved: false)
status = { status = {
resolved: resolved resolved: resolved
} }
if resolved
status[:icon] = {
title: 'Closed',
url16x16: 'http://www.openwebgraphics.com/resources/data/1768/16x16_apply.png'
}
end
{ {
GlobalID: 'GitLab', GlobalID: 'GitLab',
object: { object: {
......
...@@ -167,6 +167,15 @@ class User < ActiveRecord::Base ...@@ -167,6 +167,15 @@ class User < ActiveRecord::Base
def blocked? def blocked?
true true
end end
def active_for_authentication?
false
end
def inactive_message
"Your account has been blocked. Please contact your GitLab " \
"administrator if you think this is an error."
end
end end
end end
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
.tab-pane{ class: (klass == Gitlab::GitLogger ? 'active' : ''), .tab-pane{ class: (klass == Gitlab::GitLogger ? 'active' : ''),
id: klass::file_name_noext } id: klass::file_name_noext }
.file-holder#README .file-holder#README
.file-title .js-file-title.file-title
%i.fa.fa-file %i.fa.fa-file
= klass::file_name = klass::file_name
.pull-right .pull-right
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
.form-group .form-group
.col-sm-12 .col-sm-12
.file-holder .file-holder
.file-title.clearfix .js-file-title.file-title.clearfix
Content of .gitlab-ci.yml Content of .gitlab-ci.yml
#ci-editor.ci-editor= @content #ci-editor.ci-editor= @content
= text_area_tag(:content, @content, class: 'hidden form-control span1', rows: 7, require: true) = text_area_tag(:content, @content, class: 'hidden form-control span1', rows: 7, require: true)
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
- blob = discussion.blob - blob = discussion.blob
.diff-file.file-holder .diff-file.file-holder
.file-title .js-file-title.file-title
= render "projects/diffs/file_header", diff_file: diff_file, blob: blob, diff_commit: diff_file.content_commit, project: discussion.project, url: discussion_diff_path(discussion) = render "projects/diffs/file_header", diff_file: diff_file, blob: blob, diff_commit: diff_file.content_commit, project: discussion.project, url: discussion_diff_path(discussion)
.diff-content.code.js-syntax-highlight .diff-content.code.js-syntax-highlight
......
- if discussion.for_merge_request? - if discussion.for_merge_request?
%resolve-discussion-btn{ ":project-path" => "'#{project_path(discussion.project)}'", %resolve-discussion-btn{ ":discussion-id" => "'#{discussion.id}'",
":discussion-id" => "'#{discussion.id}'",
":merge-request-id" => discussion.noteable.iid, ":merge-request-id" => discussion.noteable.iid,
":can-resolve" => discussion.can_resolve?(current_user), ":can-resolve" => discussion.can_resolve?(current_user),
"inline-template" => true } "inline-template" => true }
......
...@@ -528,7 +528,7 @@ ...@@ -528,7 +528,7 @@
- blob = Snippet.new(content: "Wow\nSuch\nFile") - blob = Snippet.new(content: "Wow\nSuch\nFile")
.example .example
.file-holder .file-holder
.file-title .js-file-title.file-title
Awesome file Awesome file
.file-actions .file-actions
.btn-group .btn-group
......
%header.navbar.navbar-fixed-top.navbar-gitlab{ class: nav_header_class } %header.navbar.navbar-gitlab{ class: nav_header_class }
%a.sr-only.gl-accessibility{ href: "#content-body", tabindex: "1" } Skip to content %a.sr-only.gl-accessibility{ href: "#content-body", tabindex: "1" } Skip to content
.container-fluid .container-fluid
.header-content .header-content
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
- if @project && event.project != @project - if @project && event.project != @project
%span at %span at
%strong= link_to_project event.project %strong= link_to_project event.project
= clipboard_button(clipboard_text: event.ref_name, class: 'btn-clipboard btn-transparent', title: 'Copy branch to clipboard')
#{time_ago_with_tooltip(event.created_at)} #{time_ago_with_tooltip(event.created_at)}
.pull-right .pull-right
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
#blob-content-holder.tree-holder #blob-content-holder.tree-holder
.file-holder .file-holder
.file-title .js-file-title.file-title
= blob_icon @blob.mode, @blob.name = blob_icon @blob.mode, @blob.name
%strong %strong
= @path = @path
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#blob-content-holder.blob-content-holder #blob-content-holder.blob-content-holder
%article.file-holder %article.file-holder
.file-title .js-file-title.file-title
= blob_icon blob.mode, blob.name = blob_icon blob.mode, blob.name
%strong %strong
= blob.name = blob.name
......
.file-holder.file.append-bottom-default .file-holder.file.append-bottom-default
.file-title.clearfix .js-file-title.file-title.clearfix
.editor-ref .editor-ref
= icon('code-fork') = icon('code-fork')
= ref = ref
......
- builds = @build.pipeline.builds.to_a - builds = @build.pipeline.builds.to_a
%aside.right-sidebar.right-sidebar-expanded.build-sidebar.js-build-sidebar %aside.right-sidebar.right-sidebar-expanded.build-sidebar.js-build-sidebar.js-right-sidebar{ data: { "offset-top" => "151", "spy" => "affix" } }
.block.build-sidebar-header.visible-xs-block.visible-sm-block.append-bottom-default .block.build-sidebar-header.visible-xs-block.visible-sm-block.append-bottom-default
Job Job
%strong ##{@build.id} %strong ##{@build.id}
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
- else - else
%span.api.monospace API %span.api.monospace API
- if pipeline.latest? - if pipeline.latest?
%span.label.label-success.has-tooltip{ title: 'Latest job for this branch' } latest %span.label.label-success.has-tooltip{ title: 'Latest pipeline for this branch' } latest
- if pipeline.triggered? - if pipeline.triggered?
%span.label.label-primary triggered %span.label.label-primary triggered
- if pipeline.yaml_errors.present? - if pipeline.yaml_errors.present?
...@@ -61,7 +61,7 @@ ...@@ -61,7 +61,7 @@
.btn-group.inline .btn-group.inline
- if actions.any? - if actions.any?
.btn-group .btn-group
%button.dropdown-toggle.btn.btn-default.has-tooltip.js-pipeline-dropdown-manual-actions{ type: 'button', title: 'Manual job', data: { toggle: 'dropdown', placement: 'top' }, 'aria-label' => 'Manual job' } %button.dropdown-toggle.btn.btn-default.has-tooltip.js-pipeline-dropdown-manual-actions{ type: 'button', title: 'Manual pipeline', data: { toggle: 'dropdown', placement: 'top' }, 'aria-label' => 'Manual pipeline' }
= custom_icon('icon_play') = custom_icon('icon_play')
= icon('caret-down', 'aria-hidden' => 'true') = icon('caret-down', 'aria-hidden' => 'true')
%ul.dropdown-menu.dropdown-menu-align-right %ul.dropdown-menu.dropdown-menu-align-right
......
- environment = local_assigns.fetch(:environment, nil) - environment = local_assigns.fetch(:environment, nil)
.diff-file.file-holder{ id: file_hash, data: diff_file_html_data(project, diff_file.file_path, diff_commit.id) } .diff-file.file-holder{ id: file_hash, data: diff_file_html_data(project, diff_file.file_path, diff_commit.id) }
.file-title .js-file-title.file-title-flex-parent
.file-header-content
= render "projects/diffs/file_header", diff_file: diff_file, blob: blob, diff_commit: diff_commit, project: project, url: "##{file_hash}" = render "projects/diffs/file_header", diff_file: diff_file, blob: blob, diff_commit: diff_commit, project: project, url: "##{file_hash}"
- unless diff_file.submodule? - unless diff_file.submodule?
......
...@@ -10,13 +10,13 @@ ...@@ -10,13 +10,13 @@
- if diff_file.renamed_file - if diff_file.renamed_file
- old_path, new_path = mark_inline_diffs(diff_file.old_path, diff_file.new_path) - old_path, new_path = mark_inline_diffs(diff_file.old_path, diff_file.new_path)
%strong %strong.file-title-name.has-tooltip{ data: { title: old_path } }
= old_path = old_path
&rarr; &rarr;
%strong %strong.file-title-name.has-tooltip{ data: { title: new_path } }
= new_path = new_path
- else - else
%strong %strong.file-title-name.has-tooltip{ data: { title: diff_file.new_path } }
= diff_file.new_path = diff_file.new_path
- if diff_file.deleted_file - if diff_file.deleted_file
deleted deleted
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
.col-sm-6 .col-sm-6
.nav-controls .nav-controls
= link_to @environment.external_url, class: 'btn btn-default' do
= icon('external-link')
= render 'projects/deployments/actions', deployment: @environment.last_deployment = render 'projects/deployments/actions', deployment: @environment.last_deployment
.terminal-container{ class: container_class } .terminal-container{ class: container_class }
......
%li{ id: dom_id(issue), class: issue_css_classes(issue), url: issue_path(issue), data: { labels: issue.label_ids, id: issue.id } } %li{ id: dom_id(issue), class: issue_css_classes(issue), url: issue_path(issue), data: { labels: issue.label_ids, id: issue.id } }
.issue-box
- if @bulk_edit - if @bulk_edit
.issue-check .issue-check
= check_box_tag dom_id(issue, "selected"), nil, false, 'data-id' => issue.id, class: "selected_issue" = check_box_tag dom_id(issue, "selected"), nil, false, 'data-id' => issue.id, class: "selected_issue"
.issue-info-container
.issue-title.title .issue-title.title
%span.issue-title-text %span.issue-title-text
= confidential_icon(issue) = confidential_icon(issue)
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
.issue-check .issue-check
= check_box_tag dom_id(merge_request, "selected"), nil, false, 'data-id' => merge_request.id, class: "selected_issue" = check_box_tag dom_id(merge_request, "selected"), nil, false, 'data-id' => merge_request.id, class: "selected_issue"
.issue-info-container
.merge-request-title.title .merge-request-title.title
%span.merge-request-title-text %span.merge-request-title-text
= link_to merge_request.title, merge_request_path(merge_request) = link_to merge_request.title, merge_request_path(merge_request)
......
...@@ -3,10 +3,9 @@ ...@@ -3,10 +3,9 @@
- page_description @merge_request.description - page_description @merge_request.description
- page_card_attributes @merge_request.card_attributes - page_card_attributes @merge_request.card_attributes
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('lib_vue')
= page_specific_javascript_bundle_tag('diff_notes') = page_specific_javascript_bundle_tag('diff_notes')
.merge-request{ 'data-url' => merge_request_path(@merge_request) } .merge-request{ 'data-url' => merge_request_path(@merge_request), 'data-project-path' => project_path(@merge_request.project) }
= render "projects/merge_requests/show/mr_title" = render "projects/merge_requests/show/mr_title"
.merge-request-details.issuable-details{ data: { id: @merge_request.project.id } } .merge-request-details.issuable-details{ data: { id: @merge_request.project.id } }
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
.files-wrapper{ "v-if" => "!isLoading && !hasError" } .files-wrapper{ "v-if" => "!isLoading && !hasError" }
.files .files
.diff-file.file-holder.conflict{ "v-for" => "file in conflictsData.files" } .diff-file.file-holder.conflict{ "v-for" => "file in conflictsData.files" }
.file-title .js-file-title.file-title
%i.fa.fa-fw{ ":class" => "file.iconClass" } %i.fa.fa-fw{ ":class" => "file.iconClass" }
%strong {{file.filePath}} %strong {{file.filePath}}
= render partial: 'projects/merge_requests/conflicts/file_actions' = render partial: 'projects/merge_requests/conflicts/file_actions'
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
Pipeline Pipeline
= link_to "##{@pipeline.id}", namespace_project_pipeline_path(@pipeline.project.namespace, @pipeline.project, @pipeline.id), class: 'pipeline' = link_to "##{@pipeline.id}", namespace_project_pipeline_path(@pipeline.project.namespace, @pipeline.project, @pipeline.id), class: 'pipeline'
= ci_label_for_status(status) = ci_label_for_status(status)
- if @pipeline.stages.any?
.mr-widget-pipeline-graph .mr-widget-pipeline-graph
= render 'shared/mini_pipeline_graph', pipeline: @pipeline, klass: 'js-pipeline-inline-mr-widget-graph' = render 'shared/mini_pipeline_graph', pipeline: @pipeline, klass: 'js-pipeline-inline-mr-widget-graph'
%span %span
......
...@@ -16,13 +16,13 @@ ...@@ -16,13 +16,13 @@
gitlab_icon: "#{asset_path 'gitlab_logo.png'}", gitlab_icon: "#{asset_path 'gitlab_logo.png'}",
ci_status: "#{@merge_request.head_pipeline ? @merge_request.head_pipeline.status : ''}", ci_status: "#{@merge_request.head_pipeline ? @merge_request.head_pipeline.status : ''}",
ci_message: { ci_message: {
normal: "Job {{status}} for \"{{title}}\"", normal: "Pipeline {{status}} for \"{{title}}\"",
preparing: "{{status}} job for \"{{title}}\"" preparing: "{{status}} pipeline for \"{{title}}\""
}, },
ci_enable: #{@project.ci_service ? "true" : "false"}, ci_enable: #{@project.ci_service ? "true" : "false"},
ci_title: { ci_title: {
preparing: "{{status}} job", preparing: "{{status}} pipeline",
normal: "Job {{status}}" normal: "Pipeline {{status}}"
}, },
ci_sha: "#{@merge_request.head_pipeline ? @merge_request.head_pipeline.short_sha : ''}", ci_sha: "#{@merge_request.head_pipeline ? @merge_request.head_pipeline.short_sha : ''}",
ci_pipeline: #{@merge_request.head_pipeline.try(:id).to_json}, ci_pipeline: #{@merge_request.head_pipeline.try(:id).to_json},
......
%h4 %h4
= icon('exclamation-triangle') = icon('exclamation-triangle')
The job for this merge request failed The pipeline for this merge request failed
%p %p
Please retry the job or push a new commit to fix the failure. Please retry the job or push a new commit to fix the failure.
...@@ -94,9 +94,8 @@ ...@@ -94,9 +94,8 @@
.form-group.project-visibility-level-holder .form-group.project-visibility-level-holder
= f.label :visibility_level, class: 'label-light' do = f.label :visibility_level, class: 'label-light' do
Visibility Level Visibility Level
= link_to "(?)", help_page_path("public_access/public_access") = link_to icon('question-circle'), help_page_path("public_access/public_access")
= render 'shared/visibility_level', f: f, visibility_level: default_project_visibility, can_change_visibility_level: true, form_model: @project = render 'shared/visibility_level', f: f, visibility_level: default_project_visibility, can_change_visibility_level: true, form_model: @project, with_label: false
= f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 4 = f.submit 'Create project', class: "btn btn-create project-submit", tabindex: 4
= link_to 'Cancel', dashboard_projects_path, class: 'btn btn-cancel' = link_to 'Cancel', dashboard_projects_path, class: 'btn btn-cancel'
......
...@@ -30,8 +30,7 @@ ...@@ -30,8 +30,7 @@
- if note.resolvable? - if note.resolvable?
- can_resolve = can?(current_user, :resolve_note, note) - can_resolve = can?(current_user, :resolve_note, note)
%resolve-btn{ "project-path" => "#{project_path(note.project)}", %resolve-btn{ "discussion-id" => "#{note.discussion_id}",
"discussion-id" => "#{note.discussion_id}",
":note-id" => note.id, ":note-id" => note.id,
":resolved" => note.resolved?, ":resolved" => note.resolved?,
":can-resolve" => can_resolve, ":can-resolve" => can_resolve,
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
.project-snippets .project-snippets
%article.file-holder.snippet-file-content %article.file-holder.snippet-file-content
.file-title .js-file-title.file-title
= blob_icon 0, @snippet.file_name = blob_icon 0, @snippet.file_name
= @snippet.file_name = @snippet.file_name
.file-actions .file-actions
......
%article.file-holder.readme-holder %article.file-holder.readme-holder
.file-title .js-file-title.file-title
= blob_icon readme.mode, readme.name = blob_icon readme.mode, readme.name
= link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@ref, @path, readme.name)) do = link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@ref, @path, readme.name)) do
%strong %strong
......
...@@ -65,7 +65,7 @@ ...@@ -65,7 +65,7 @@
In the In the
%code .gitlab-ci.yml %code .gitlab-ci.yml
of another project, include the following snippet. of another project, include the following snippet.
The project will be rebuilt at the end of the job. The project will be rebuilt at the end of the pipeline.
%pre %pre
:plain :plain
...@@ -89,7 +89,7 @@ ...@@ -89,7 +89,7 @@
%p.light %p.light
Add Add
%code variables[VARIABLE]=VALUE %code variables[VARIABLE]=VALUE
to an API request. Variable values can be used to distinguish between triggered jobs and normal jobs. to an API request. Variable values can be used to distinguish between triggered pipelines and normal pipelines.
With cURL: With cURL:
......
%aside.right-sidebar.right-sidebar-expanded.wiki-sidebar.js-wiki-sidebar %aside.right-sidebar.right-sidebar-expanded.wiki-sidebar.js-wiki-sidebar.js-right-sidebar{ data: { "offset-top" => "101", "spy" => "affix" } }
.block.wiki-sidebar-header.append-bottom-default .block.wiki-sidebar-header.append-bottom-default
%a.gutter-toggle.pull-right.visible-xs-block.visible-sm-block.js-sidebar-wiki-toggle{ href: "#" } %a.gutter-toggle.pull-right.visible-xs-block.visible-sm-block.js-sidebar-wiki-toggle{ href: "#" }
= icon('angle-double-right') = icon('angle-double-right')
......
- file_name, blob = blob - file_name, blob = blob
.blob-result .blob-result
.file-holder .file-holder
.file-title .js-file-title.file-title
- ref = @search_results.repository_ref - ref = @search_results.repository_ref
- blob_link = namespace_project_blob_path(@project.namespace, @project, tree_join(ref, file_name)) - blob_link = namespace_project_blob_path(@project.namespace, @project, tree_join(ref, file_name))
= link_to blob_link do = link_to blob_link do
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
- snippet_path = reliable_snippet_path(snippet) - snippet_path = reliable_snippet_path(snippet)
= link_to snippet_path do = link_to snippet_path do
.file-holder .file-holder
.file-title .js-file-title.file-title
%i.fa.fa-file %i.fa.fa-file
%strong= snippet.file_name %strong= snippet.file_name
- if markup?(snippet.file_name) - if markup?(snippet.file_name)
......
- wiki_blob = parse_search_result(wiki_blob) - wiki_blob = parse_search_result(wiki_blob)
.blob-result .blob-result
.file-holder .file-holder
.file-title .js-file-title.file-title
= link_to namespace_project_wiki_path(@project.namespace, @project, wiki_blob.basename) do = link_to namespace_project_wiki_path(@project.namespace, @project, wiki_blob.basename) do
%i.fa.fa-file %i.fa.fa-file
%strong %strong
......
...@@ -17,9 +17,9 @@ ...@@ -17,9 +17,9 @@
Try to keep the first line under 52 characters Try to keep the first line under 52 characters
and the others under 72. and the others under 72.
- if descriptions.present? - if descriptions.present?
%p.hint.js-with-description-hint .hint.js-with-description-hint
= link_to "#", class: "js-with-description-link" do = link_to "#", class: "js-with-description-link" do
Include description in commit message Include description in commit message
%p.hint.js-without-description-hint.hide .hint.js-without-description-hint.hide
= link_to "#", class: "js-without-description-link" do = link_to "#", class: "js-without-description-link" do
Don't include description in commit message Don't include description in commit message
- with_label = local_assigns.fetch(:with_label, true)
.form-group.project-visibility-level-holder .form-group.project-visibility-level-holder
- if with_label
= f.label :visibility_level, class: 'control-label' do = f.label :visibility_level, class: 'control-label' do
Visibility Level Visibility Level
= link_to icon('question-circle'), help_page_path("public_access/public_access") = link_to icon('question-circle'), help_page_path("public_access/public_access")
.col-sm-10 %div{ :class => ("col-sm-10" if with_label) }
- if can_change_visibility_level - if can_change_visibility_level
= render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: visibility_level, form_model: form_model) = render('shared/visibility_radios', model_method: :visibility_level, form: f, selected_level: visibility_level, form_model: form_model)
- else - else
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('issuable') = page_specific_javascript_bundle_tag('issuable')
%aside.right-sidebar{ class: sidebar_gutter_collapsed_class, 'aria-live' => 'polite' } %aside.right-sidebar.js-right-sidebar{ data: { "offset-top" => "101", "spy" => "affix" }, class: sidebar_gutter_collapsed_class, 'aria-live' => 'polite' }
.issuable-sidebar .issuable-sidebar
- can_edit_issuable = can?(current_user, :"admin_#{issuable.to_ability_name}", @project) - can_edit_issuable = can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
.block.issuable-sidebar-header .block.issuable-sidebar-header
......
...@@ -19,9 +19,9 @@ ...@@ -19,9 +19,9 @@
%label.label.label-danger %label.label.label-danger
%strong Blocked %strong Blocked
- if source.instance_of?(Group) && !@group - if source.instance_of?(Group) && source != @group
&middot; &middot;
= link_to source.name, source, class: "member-group-link" = link_to source.full_name, source, class: "member-group-link"
.hidden-xs.cgray .hidden-xs.cgray
- if member.request? - if member.request?
...@@ -44,8 +44,9 @@ ...@@ -44,8 +44,9 @@
= link_to member.created_by.name, user_path(member.created_by) = link_to member.created_by.name, user_path(member.created_by)
= time_ago_with_tooltip(member.created_at) = time_ago_with_tooltip(member.created_at)
- if show_roles - if show_roles
- current_resource = @project || @group
.controls.member-controls .controls.member-controls
- if show_controls && (member.respond_to?(:group) && @group) || (member.respond_to?(:project) && @project) - if show_controls && member.source == current_resource
- if user != current_user - if user != current_user
= form_for member, remote: true, html: { class: 'form-horizontal js-edit-member-form' } do |f| = form_for member, remote: true, html: { class: 'form-horizontal js-edit-member-form' } do |f|
= f.hidden_field :access_level = f.hidden_field :access_level
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
= f.label :file_name, "File", class: 'control-label' = f.label :file_name, "File", class: 'control-label'
.col-sm-10 .col-sm-10
.file-holder.snippet .file-holder.snippet
.file-title .js-file-title.file-title
= f.text_field :file_name, placeholder: "Optionally name this file to add code highlighting, e.g. example.rb for Ruby.", class: 'form-control snippet-file-name' = f.text_field :file_name, placeholder: "Optionally name this file to add code highlighting, e.g. example.rb for Ruby.", class: 'form-control snippet-file-name'
.file-content.code .file-content.code
%pre#editor= @snippet.content %pre#editor= @snippet.content
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
= @file_sample.events = @file_sample.events
%article.file-holder %article.file-holder
.file-title .js-file-title.file-title
%i.fa.fa-file-text-o.fa-fw %i.fa.fa-file-text-o.fa-fw
%strong %strong
= @file_sample.file = @file_sample.file
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
= render 'shared/snippets/header' = render 'shared/snippets/header'
%article.file-holder.snippet-file-content %article.file-holder.snippet-file-content
.file-title .js-file-title.file-title
= blob_icon 0, @snippet.file_name = blob_icon 0, @snippet.file_name
= @snippet.file_name = @snippet.file_name
.file-actions .file-actions
......
---
title: Optionally make users created via the API set their password
merge_request: 8957
author: Joost Rijneveld
---
title: Responsive title in diffs inline, side by side, with and without sidebar
merge_request: 8475
author:
---
title: Added external environment link to web terminal view
merge_request: 8303
author:
---
title: fixes issue number alignment problem in MR and issue list
merge_request: 9020
author:
---
title: Fixes dropdown width in admin project page
merge_request: 9002
author:
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment