Merge branch 'master' into new-nav-fix-contextual-breadcrumbs

This commit is contained in:
Phil Hughes 2017-07-14 11:22:12 +01:00
commit b85d69d1f0
185 changed files with 3059 additions and 944 deletions

View File

@ -10,7 +10,7 @@ linters:
# Reports when you use improper spacing around ! (the "bang") in !default,
# !global, !important, and !optional flags.
BangFormat:
enabled: false
enabled: true
# Whether or not to prefer `border: 0` over `border: none`.
BorderZero:
@ -43,10 +43,11 @@ linters:
# Rule sets should be ordered as follows:
# - @extend declarations
# - @include declarations without inner @content
# - properties, @include declarations with inner @content
# - properties
# - @include declarations with inner @content
# - nested rule sets.
DeclarationOrder:
enabled: false
enabled: true
# `scss-lint:disable` control comments should be preceded by a comment
# explaining why these linters are being disabled for this file.
@ -178,6 +179,10 @@ linters:
SpaceAfterComma:
enabled: true
# Comment literals should be followed by a space.
SpaceAfterComment:
enabled: false
# Properties should be formatted with a single space separating the colon
# from the property's value.
SpaceAfterPropertyColon:
@ -240,7 +245,7 @@ linters:
# Do not use parent selector references (&) when they would otherwise
# be unnecessary.
UnnecessaryParentReference:
enabled: false
enabled: true
# URLs should be valid and not contain protocols or domain names.
UrlFormat:

View File

@ -1 +1 @@
0.16.0
0.17.0

View File

@ -1 +1 @@
5.3.0
5.3.1

View File

@ -1 +1 @@
2.3.0
3.0.0

View File

@ -334,7 +334,7 @@ group :development, :test do
gem 'rubocop', '~> 0.47.1', require: false
gem 'rubocop-rspec', '~> 1.15.0', require: false
gem 'scss_lint', '~> 0.47.0', require: false
gem 'scss_lint', '~> 0.54.0', require: false
gem 'haml_lint', '~> 0.21.0', require: false
gem 'simplecov', '~> 0.14.0', require: false
gem 'flay', '~> 2.8.0', require: false

View File

@ -762,9 +762,9 @@ GEM
sawyer (0.8.1)
addressable (>= 2.3.5, < 2.6)
faraday (~> 0.8, < 1.0)
scss_lint (0.47.1)
rake (>= 0.9, < 11)
sass (~> 3.4.15)
scss_lint (0.54.0)
rake (>= 0.9, < 13)
sass (~> 3.4.20)
securecompare (1.0.0)
seed-fu (2.3.6)
activerecord (>= 3.1)
@ -1081,7 +1081,7 @@ DEPENDENCIES
rugged (~> 0.25.1.1)
sanitize (~> 2.0)
sass-rails (~> 5.0.6)
scss_lint (~> 0.47.0)
scss_lint (~> 0.54.0)
seed-fu (~> 2.3.5)
select2-rails (~> 3.5.9)
sentry-raven (~> 2.5.3)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -51,8 +51,9 @@ export default () => {
methods: {
loadFile() {
this.$http.get(el.dataset.endpoint)
.then(response => response.json())
.then((res) => {
this.json = res.json();
this.json = res;
this.loading = false;
})
.catch((e) => {

View File

@ -81,8 +81,9 @@ $(() => {
mounted () {
Store.disabled = this.disabled;
gl.boardService.all()
.then(response => response.json())
.then((resp) => {
resp.json().forEach((board) => {
resp.forEach((board) => {
const list = Store.addList(board, this.defaultAvatar);
if (list.type === 'closed') {
@ -97,7 +98,8 @@ $(() => {
Store.addBlankState();
this.loading = false;
}).catch(() => new Flash('An error occurred. Please try again.'));
})
.catch(() => new Flash('An error occurred. Please try again.'));
},
methods: {
updateTokens() {

View File

@ -64,8 +64,9 @@ export default {
// Save the labels
gl.boardService.generateDefaultLists()
.then((resp) => {
resp.json().forEach((listObj) => {
.then(resp => resp.json())
.then((data) => {
data.forEach((listObj) => {
const list = Store.findList('title', listObj.title);
list.id = listObj.id;

View File

@ -88,9 +88,9 @@ gl.issueBoards.IssuesModal = Vue.extend({
return gl.boardService.getBacklog(queryData(this.filter.path, {
page: this.page,
per: this.perPage,
})).then((res) => {
const data = res.json();
}))
.then(resp => resp.json())
.then((data) => {
if (clearIssues) {
this.issues = [];
}

View File

@ -40,9 +40,8 @@ class List {
save () {
return gl.boardService.createList(this.label.id)
.then((resp) => {
const data = resp.json();
.then(resp => resp.json())
.then((data) => {
this.id = data.id;
this.type = data.list_type;
this.position = data.position;
@ -91,8 +90,8 @@ class List {
}
return gl.boardService.getIssuesForList(this.id, data)
.then((resp) => {
const data = resp.json();
.then(resp => resp.json())
.then((data) => {
this.loading = false;
this.issuesSize = data.size;
@ -109,8 +108,8 @@ class List {
this.issuesSize += 1;
return gl.boardService.newIssue(this.id, issue)
.then((resp) => {
const data = resp.json();
.then(resp => resp.json())
.then((data) => {
issue.id = data.iid;
if (this.issuesSize > 1) {

View File

@ -23,11 +23,6 @@ class BoardService {
url: bulkUpdatePath,
},
});
Vue.http.interceptors.push((request, next) => {
request.headers['X-CSRF-Token'] = $.rails.csrfToken();
next();
});
}
all () {

View File

@ -51,11 +51,11 @@
},
methods: {
successCallback(resp) {
const response = resp.json();
// depending of the endpoint the response can either bring a `pipelines` key or not.
const pipelines = response.pipelines || response;
this.setCommonData(pipelines);
return resp.json().then((response) => {
// depending of the endpoint the response can either bring a `pipelines` key or not.
const pipelines = response.pipelines || response;
this.setCommonData(pipelines);
});
},
},
};

View File

@ -1,4 +1,4 @@
/* 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, max-len */
/* global CommentsStore */
/* global ResolveService */
/* global Flash */
@ -64,8 +64,6 @@ const ResolveBtn = Vue.extend({
});
},
resolve: function () {
const errorFlashMsg = 'An error occurred when trying to resolve a comment. Please try again.';
if (!this.canResolve) return;
let promise;
@ -79,24 +77,20 @@ const ResolveBtn = Vue.extend({
.resolve(this.noteId);
}
promise.then((response) => {
this.loading = false;
promise
.then(resp => resp.json())
.then((data) => {
this.loading = false;
if (response.status === 200) {
const data = response.json();
const resolved_by = data ? data.resolved_by : null;
CommentsStore.update(this.discussionId, this.noteId, !this.isResolved, resolved_by);
this.discussion.updateHeadline(data);
gl.mrWidget.checkStatus();
} else {
new Flash(errorFlashMsg);
}
this.updateTooltip();
}).catch(() => {
new Flash(errorFlashMsg);
});
this.updateTooltip();
})
.catch(() => new Flash('An error occurred when trying to resolve a comment. Please try again.'));
}
},
mounted: function () {

View File

@ -1,4 +1,3 @@
/* eslint-disable class-methods-use-this, one-var, camelcase, no-new, comma-dangle, no-param-reassign, max-len */
/* global Flash */
/* global CommentsStore */
@ -32,27 +31,22 @@ class ResolveServiceClass {
promise = this.resolveAll(mergeRequestId, discussionId);
}
promise.then((response) => {
discussion.loading = false;
if (response.status === 200) {
const data = response.json();
const resolved_by = data ? data.resolved_by : null;
promise
.then(resp => resp.json())
.then((data) => {
discussion.loading = false;
const resolvedBy = data ? data.resolved_by : null;
if (isResolved) {
discussion.unResolveAllNotes();
} else {
discussion.resolveAllNotes(resolved_by);
discussion.resolveAllNotes(resolvedBy);
}
gl.mrWidget.checkStatus();
discussion.updateHeadline(data);
} else {
throw new Error('An error occurred when trying to resolve discussion.');
}
}).catch(() => {
new Flash('An error occurred when trying to resolve a discussion. Please try again.');
});
})
.catch(() => new Flash('An error occurred when trying to resolve a discussion. Please try again.'));
}
resolveAll(mergeRequestId, discussionId) {
@ -62,7 +56,7 @@ class ResolveServiceClass {
return this.discussionResource.save({
mergeRequestId,
discussionId
discussionId,
}, {});
}
@ -73,7 +67,7 @@ class ResolveServiceClass {
return this.discussionResource.delete({
mergeRequestId,
discussionId
discussionId,
}, {});
}
}

View File

@ -498,9 +498,9 @@ export default {
<div class="table-section section-15 hidden-xs hidden-sm" role="gridcell">
<a
v-if="shouldRenderBuildName"
class="build-link"
class="build-link flex-truncate-parent"
:href="buildPath">
{{buildName}}
<span class="flex-truncate-child">{{buildName}}</span>
</a>
</div>

View File

@ -1,17 +1,15 @@
export default {
methods: {
saveData(resp) {
const response = {
headers: resp.headers,
body: resp.json(),
};
const headers = resp.headers;
return resp.json().then((response) => {
this.isLoading = false;
this.isLoading = false;
this.store.storeAvailableCount(response.body.available_count);
this.store.storeStoppedCount(response.body.stopped_count);
this.store.storeEnvironments(response.body.environments);
this.store.setPagination(response.headers);
this.store.storeAvailableCount(response.available_count);
this.store.storeStoppedCount(response.stopped_count);
this.store.storeEnvironments(response.environments);
this.store.setPagination(headers);
});
},
},
};

View File

@ -7,5 +7,8 @@ export default () => {
Cookies.set(el.name, el.value, {
expires: 365 * 10,
});
document.body.scrollTop = 0;
window.location.reload();
});
};

View File

@ -99,8 +99,10 @@ document.addEventListener('DOMContentLoaded', () => {
page: currentPath,
}, document.title, currentPath);
this.updateGroups(response.json());
this.updatePagination(response.headers);
return response.json().then((data) => {
this.updateGroups(data);
this.updatePagination(response.headers);
});
})
.catch(this.handleErrorResponse);
},
@ -114,18 +116,19 @@ document.addEventListener('DOMContentLoaded', () => {
},
leaveGroup(group, collection) {
this.service.leaveGroup(group.leavePath)
.then(resp => resp.json())
.then((response) => {
$.scrollTo(0);
this.store.removeGroup(group, collection);
// eslint-disable-next-line no-new
new Flash(response.json().notice, 'notice');
new Flash(response.notice, 'notice');
})
.catch((response) => {
.catch((error) => {
let message = 'An error occurred. Please try again.';
if (response.status === 403) {
if (error.status === 403) {
message = 'Failed to leave the group. Please make sure you are not the only owner';
}

View File

@ -202,10 +202,7 @@ export default {
this.poll = new Poll({
resource: this.service,
method: 'getData',
successCallback: (res) => {
const data = res.json();
this.store.updateState(data);
},
successCallback: res => res.json().then(data => this.store.updateState(data)),
errorCallback(err) {
throw new Error(err);
},

View File

@ -54,9 +54,8 @@ export default class JobMediator {
}
successCallback(response) {
const data = response.json();
this.state.isLoading = false;
this.store.storeJob(data);
return response.json().then(data => this.store.storeJob(data));
}
errorCallback() {

View File

@ -1270,7 +1270,7 @@ export default class Notes {
<div class="timeline-entry-inner">
<div class="timeline-icon">
<a href="/${currentUsername}">
<img class="avatar s40" src="${currentUserAvatar}">
<img class="avatar s40" src="${currentUserAvatar}" />
</a>
</div>
<div class="timeline-content ${discussionClass}">

View File

@ -129,14 +129,11 @@
},
successCallback(resp) {
const response = {
headers: resp.headers,
body: resp.json(),
};
this.store.storeCount(response.body.count);
this.store.storePagination(response.headers);
this.setCommonData(response.body.pipelines);
return resp.json().then((response) => {
this.store.storeCount(response.count);
this.store.storePagination(resp.headers);
this.setCommonData(response.pipelines);
});
},
},
};

View File

@ -73,8 +73,9 @@ export default {
fetchJobs() {
this.$http.get(this.stage.dropdown_path)
.then((response) => {
this.dropdownContent = response.json().html;
.then(response => response.json())
.then((data) => {
this.dropdownContent = data.html;
this.isLoading = false;
})
.catch(() => {

View File

@ -40,10 +40,10 @@ export default class pipelinesMediator {
}
successCallback(response) {
const data = response.json();
this.state.isLoading = false;
this.store.storePipeline(data);
return response.json().then((data) => {
this.state.isLoading = false;
this.store.storePipeline(data);
});
}
errorCallback() {

View File

@ -1,6 +1,5 @@
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, quotes, prefer-arrow-callback, consistent-return, object-shorthand, no-unused-vars, one-var, one-var-declaration-per-line, no-else-return, comma-dangle, max-len */
/* global Mousetrap */
/* global findFileURL */
import Cookies from 'js-cookie';
import findAndFollowLink from './shortcuts_dashboard_navigation';
@ -20,6 +19,7 @@ import findAndFollowLink from './shortcuts_dashboard_navigation';
const $globalDropdownMenu = $('.global-dropdown-menu');
const $globalDropdownToggle = $('.global-dropdown-toggle');
const findFileURL = document.body.dataset.findFile;
$('.global-dropdown').on('hide.bs.dropdown', () => {
$globalDropdownMenu.removeClass('shortcuts');

View File

@ -28,8 +28,8 @@ export default class SidebarMediator {
fetch() {
this.service.get()
.then((response) => {
const data = response.json();
.then(response => response.json())
.then((data) => {
this.store.setAssigneeData(data);
this.store.setTimeTrackingData(data);
})

View File

@ -92,13 +92,13 @@ export default {
:class="{'label-truncated has-tooltip': isBranchTitleLong(mr.targetBranch)}"
:title="isBranchTitleLong(mr.targetBranch) ? mr.targetBranch : ''"
data-placement="bottom">
<a :href="mr.targetBranchPath">{{mr.targetBranch}}</a>
<a :href="mr.targetBranchTreePath">{{mr.targetBranch}}</a>
</span>
</strong>
<span
v-if="shouldShowCommitsBehindText"
class="diverged-commits-count">
({{mr.divergedCommitsCount}} {{commitsText}} behind)
(<a :href="mr.targetBranchPath">{{mr.divergedCommitsCount}} {{commitsText}} behind</a>)
</span>
</div>
</div>

View File

@ -48,6 +48,7 @@ export default class MergeRequestStore {
this.sourceBranchLink = data.source_branch_with_namespace_link;
this.mergeError = data.merge_error;
this.targetBranchPath = data.target_branch_commits_path;
this.targetBranchTreePath = data.target_branch_tree_path;
this.conflictResolutionPath = data.conflict_resolution_path;
this.cancelAutoMergePath = data.cancel_merge_when_pipeline_succeeds_path;
this.removeWIPPath = data.remove_wip_path;

View File

@ -44,9 +44,8 @@
text: this.$slots.textarea[0].elm.value,
},
)
.then((res) => {
const data = res.json();
.then(resp => resp.json())
.then((data) => {
this.markdownPreviewLoading = false;
this.markdownPreview = data.body;

View File

@ -14,11 +14,22 @@ Vue.http.interceptors.push((request, next) => {
});
});
// Inject CSRF token so we don't break any tests.
// Inject CSRF token and parse headers.
// New Vue Resource version uses Headers, we are expecting a plain object to render pagination
// and polling.
Vue.http.interceptors.push((request, next) => {
if ($.rails) {
// eslint-disable-next-line no-param-reassign
request.headers['X-CSRF-Token'] = $.rails.csrfToken();
request.headers.set('X-CSRF-Token', $.rails.csrfToken());
}
next();
next((response) => {
// Headers object has a `forEach` property that iterates through all values.
const headers = {};
response.headers.forEach((value, key) => {
headers[key] = value;
});
// eslint-disable-next-line no-param-reassign
response.headers = headers;
});
});

View File

@ -231,11 +231,11 @@
.award-control-icon-positive,
.award-control-icon-super-positive {
@include transition(opacity, transform);
position: absolute;
left: 10px;
bottom: 6px;
opacity: 0;
@include transition(opacity, transform);
}
.award-control-text {

View File

@ -35,8 +35,8 @@
.open {
.dropdown-menu,
.dropdown-menu-nav {
display: block;
@include set-visible;
display: block;
@media (max-width: $screen-xs-max) {
width: 100%;
@ -184,13 +184,15 @@
.dropdown-menu,
.dropdown-menu-nav {
@include set-invisible;
display: block;
position: absolute;
width: 100%;
width: auto;
top: 100%;
left: 0;
z-index: 9;
min-width: 240px;
max-width: 500px;
margin-top: 2px;
margin-bottom: 0;
font-size: 14px;
@ -200,7 +202,6 @@
border: 1px solid $dropdown-border-color;
border-radius: $border-radius-base;
box-shadow: 0 2px 4px $dropdown-shadow-color;
@include set-invisible;
@media (max-width: $screen-sm-min) {
width: 100%;
@ -675,8 +676,8 @@
}
.pika-single {
position: relative!important;
top: 0!important;
position: relative !important;
top: 0 !important;
border: 0;
box-shadow: none;
}

View File

@ -368,7 +368,7 @@
margin-right: 0.3em;
}
& > .value {
> .value {
font-weight: 600;
}
}
@ -467,7 +467,7 @@
-webkit-flex-direction: column;
flex-direction: column;
&> span {
> span {
white-space: normal;
word-break: break-all;
}

View File

@ -330,7 +330,7 @@ header {
padding-left: 5px;
.nav > li:not(.hidden-xs) {
display: table-cell!important;
display: table-cell !important;
width: 25%;
a {

View File

@ -61,7 +61,7 @@
&:focus {
outline: none;
& i {
i {
visibility: visible;
}
}

View File

@ -165,8 +165,8 @@
.cur {
.avatar {
border: 1px solid $white-light;
@include disableAllAnimation;
border: 1px solid $white-light;
}
}

View File

@ -100,9 +100,9 @@
}
.table-mobile-header {
@include flex-max-width(40);
color: $gl-text-color-secondary;
text-align: left;
@include flex-max-width(40);
@media (min-width: $screen-md-min) {
display: none;

View File

@ -11,7 +11,7 @@
.is-dragging {
// Important because plugin sets inline CSS
opacity: 1!important;
opacity: 1 !important;
* {
-webkit-user-select: none;
@ -19,8 +19,8 @@
-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;
cursor: -webkit-grabbing !important;
cursor: grabbing !important;
}
}

View File

@ -244,6 +244,10 @@
}
}
.block-last {
padding: 16px 0;
}
.trigger-build-variable {
color: $code-color;
}

View File

@ -250,8 +250,8 @@
}
.committed_ago {
float: right;
@extend .cgray;
float: right;
}
}
}

View File

@ -24,9 +24,9 @@
.col-headers {
ul {
@include clearfix;
margin: 0;
padding: 0;
@include clearfix;
}
li {
@ -189,8 +189,8 @@
}
li {
list-style-type: none;
@include clearfix;
list-style-type: none;
}
.stage-nav-item {
@ -281,11 +281,11 @@
}
.stage-event-item {
@include clearfix;
list-style-type: none;
padding: 0 0 $gl-padding;
margin: 0 $gl-padding $gl-padding;
border-bottom: 1px solid $gray-darker;
@include clearfix;
&:last-child {
border-bottom: none;
@ -307,9 +307,9 @@
&.issue-title,
&.commit-title,
&.merge-merquest-title {
@include text-overflow();
max-width: 100%;
display: block;
@include text-overflow();
a {
color: $gl-text-color;

View File

@ -91,6 +91,7 @@
.old_line,
.new_line {
@include user-select(none);
margin: 0;
border: none;
padding: 0 5px;
@ -99,7 +100,6 @@
min-width: 35px;
max-width: 50px;
width: 35px;
@include user-select(none);
a {
float: left;
@ -354,12 +354,12 @@
}
&.active {
cursor: default;
color: $gl-text-color;
&:hover {
text-decoration: none;
}
cursor: default;
color: $gl-text-color;
}
&.disabled {

View File

@ -96,7 +96,7 @@
overflow: visible;
}
& > span {
> span {
padding-right: 4px;
}

View File

@ -121,10 +121,11 @@ ul.notes {
overflow-y: hidden;
.note-text {
word-wrap: break-word;
@include md-typography;
// Reset ul style types since we're nested inside a ul already
@include bulleted-list;
word-wrap: break-word;
ul.task-list {
ul:not(.task-list) {
padding-left: 1.3em;
@ -250,7 +251,7 @@ ul.notes {
}
.note-text {
& p:first-child {
p:first-child {
display: none;
}

View File

@ -1,7 +1,7 @@
.js-pipeline-schedule-form {
.dropdown-select,
.dropdown-menu-toggle {
width: 100%!important;
width: 100% !important;
}
.gl-field-error {
@ -96,12 +96,12 @@
}
&:last-child {
& .pipeline-variable-row-remove-button {
.pipeline-variable-row-remove-button {
display: none;
}
@media (max-width: $screen-sm-max) {
& .pipeline-variable-value-input {
.pipeline-variable-value-input {
margin-right: $pipeline-variable-remove-button-width;
}
}
@ -137,6 +137,7 @@
}
.pipeline-variable-row-remove-button {
@include transition(color);
flex-shrink: 0;
display: flex;
justify-content: center;
@ -147,7 +148,6 @@
background: transparent;
border: 0;
color: $gl-text-color-secondary;
@include transition(color);
&:hover,
&:focus {

View File

@ -26,7 +26,7 @@
margin-bottom: 5px;
}
& > .form-group {
> .form-group {
padding-left: 0;
}
@ -83,7 +83,7 @@
border: 1px solid $border-color;
}
& + .select2 a {
+ .select2 a {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
@ -587,9 +587,9 @@ pre.light-well {
}
.project-row {
@include basic-list-stats;
display: flex;
align-items: center;
@include basic-list-stats;
}
h3 {

View File

@ -81,7 +81,7 @@
.todo-title {
display: flex;
& > .title-item {
> .title-item {
-webkit-flex: 0 0 auto;
flex: 0 0 auto;
margin: 0 2px;

View File

@ -5,13 +5,13 @@
}
.example {
padding: 15px;
border: 1px dashed $ui-dev-kit-example-border;
margin-bottom: 15px;
&::before {
content: "Example";
color: $ui-dev-kit-example-color;
}
padding: 15px;
border: 1px dashed $ui-dev-kit-example-border;
margin-bottom: 15px;
}
}

View File

@ -147,13 +147,13 @@
}
ul.wiki-pages-list.content-list {
& ul {
ul {
list-style: none;
margin-left: 0;
padding-left: 15px;
}
& ul li {
ul li {
padding: 5px 0;
}
}

View File

@ -37,7 +37,7 @@ ul.notes-form,
.issuable-details .content-block-small,
.edit-link,
.note-action-button {
display: none!important;
display: none !important;
}
pre {

View File

@ -113,6 +113,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:html_emails_enabled,
:koding_enabled,
:koding_url,
:password_authentication_enabled,
:plantuml_enabled,
:plantuml_url,
:max_artifacts_size,
@ -135,7 +136,6 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
:require_two_factor_authentication,
:session_expire_delay,
:sign_in_text,
:signin_enabled,
:signup_enabled,
:sentry_dsn,
:sentry_enabled,

View File

@ -170,7 +170,7 @@ class ApplicationController < ActionController::Base
end
def check_password_expiration
if current_user && current_user.password_expires_at && current_user.password_expires_at < Time.now && !current_user.ldap_user?
if current_user && current_user.password_expires_at && current_user.password_expires_at < Time.now && current_user.allow_password_authentication?
return redirect_to new_profile_password_path
end
end

View File

@ -1,6 +1,8 @@
class PasswordsController < Devise::PasswordsController
include Gitlab::CurrentSettings
before_action :resource_from_email, only: [:create]
before_action :prevent_ldap_reset, only: [:create]
before_action :check_password_authentication_available, only: [:create]
before_action :throttle_reset, only: [:create]
def edit
@ -25,7 +27,7 @@ class PasswordsController < Devise::PasswordsController
def update
super do |resource|
if resource.valid? && resource.require_password?
if resource.valid? && resource.require_password_creation?
resource.update_attribute(:password_automatically_set, false)
end
end
@ -38,11 +40,11 @@ class PasswordsController < Devise::PasswordsController
self.resource = resource_class.find_by_email(email)
end
def prevent_ldap_reset
return unless resource && resource.ldap_user?
def check_password_authentication_available
return if current_application_settings.password_authentication_enabled? && (resource.nil? || resource.allow_password_authentication?)
redirect_to after_sending_reset_password_instructions_path_for(resource_name),
alert: "Cannot reset password for LDAP user."
alert: "Password authentication is unavailable."
end
def throttle_reset

View File

@ -77,7 +77,7 @@ class Profiles::PasswordsController < Profiles::ApplicationController
end
def authorize_change_password!
return render_404 if @user.ldap_user?
render_404 unless @user.allow_password_authentication?
end
def user_params

View File

@ -107,7 +107,7 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
@target_project = @merge_request.target_project
@source_project = @merge_request.source_project
@commits = @merge_request.compare_commits.reverse
@commits = @merge_request.commits
@commit = @merge_request.diff_head_commit
@note_counts = Note.where(commit_id: @commits.map(&:id))

View File

@ -58,7 +58,7 @@ class SessionsController < Devise::SessionsController
user = User.admins.last
return unless user && user.require_password?
return unless user && user.require_password_creation?
Users::UpdateService.new(user).execute do |user|
@token = user.generate_reset_token

View File

@ -1,7 +1,7 @@
module ApplicationSettingsHelper
delegate :gravatar_enabled?,
:signup_enabled?,
:signin_enabled?,
:password_authentication_enabled?,
:akismet_enabled?,
:koding_enabled?,
to: :current_application_settings
@ -35,7 +35,7 @@ module ApplicationSettingsHelper
# Return a group of checkboxes that use Bootstrap's button plugin for a
# toggle button effect.
def restricted_level_checkboxes(help_block_id, checkbox_name)
Gitlab::VisibilityLevel.options.map do |name, level|
Gitlab::VisibilityLevel.values.map do |level|
checked = restricted_visibility_levels(true).include?(level)
css_class = checked ? 'active' : ''
tag_name = "application_setting_visibility_level_#{level}"
@ -44,7 +44,7 @@ module ApplicationSettingsHelper
check_box_tag(checkbox_name, level, checked,
autocomplete: 'off',
'aria-describedby' => help_block_id,
id: tag_name) + visibility_level_icon(level) + name
id: tag_name) + visibility_level_icon(level) + visibility_level_label(level)
end
end
end

View File

@ -50,12 +50,12 @@ module ButtonHelper
def http_clone_button(project, placement = 'right', append_link: true)
klass = 'http-selector'
klass << ' has-tooltip' if current_user.try(:require_password?) || current_user.try(:require_personal_access_token?)
klass << ' has-tooltip' if current_user.try(:require_password_creation?) || current_user.try(:require_personal_access_token_creation_for_git_auth?)
protocol = gitlab_config.protocol.upcase
tooltip_title =
if current_user.try(:require_password?)
if current_user.try(:require_password_creation?)
_("Set a password on your account to pull or push via %{protocol}.") % { protocol: protocol }
else
_("Create a personal access token on your account to pull or push via %{protocol}.") % { protocol: protocol }

View File

@ -214,11 +214,11 @@ module ProjectsHelper
def show_no_password_message?
cookies[:hide_no_password_message].blank? && !current_user.hide_no_password &&
( current_user.require_password? || current_user.require_personal_access_token? )
( current_user.require_password_creation? || current_user.require_personal_access_token_creation_for_git_auth? )
end
def link_to_set_password
if current_user.require_password?
if current_user.require_password_creation?
link_to s_('SetPasswordToCloneLink|set a password'), edit_profile_password_path
else
link_to s_('CreateTokenToCloneLink|create a personal access token'), profile_personal_access_tokens_path
@ -518,4 +518,12 @@ module ProjectsHelper
current_application_settings.restricted_visibility_levels || []
end
def find_file_path
return unless @project && !@project.empty_repo?
ref = @ref || @project.repository.root_ref
project_find_file_path(@project, ref)
end
end

View File

@ -237,6 +237,7 @@ class ApplicationSetting < ActiveRecord::Base
koding_url: nil,
max_artifacts_size: Settings.artifacts['max_size'],
max_attachment_size: Settings.gitlab['max_attachment_size'],
password_authentication_enabled: Settings.gitlab['password_authentication_enabled'],
performance_bar_allowed_group_id: nil,
plantuml_enabled: false,
plantuml_url: nil,
@ -251,7 +252,6 @@ class ApplicationSetting < ActiveRecord::Base
shared_runners_text: nil,
sidekiq_throttling_enabled: false,
sign_in_text: nil,
signin_enabled: Settings.gitlab['signin_enabled'],
signup_enabled: Settings.gitlab['signup_enabled'],
terminal_max_session_time: 0,
two_factor_grace_period: 48,

View File

@ -32,9 +32,6 @@ class MergeRequest < ActiveRecord::Base
after_create :ensure_merge_request_diff, unless: :importing?
after_update :reload_diff_if_branch_changed
delegate :commits, :real_size, :commit_shas, :commits_count,
to: :merge_request_diff, prefix: nil
# When this attribute is true some MR validation is ignored
# It allows us to close or modify broken merge requests
attr_accessor :allow_broken
@ -224,6 +221,36 @@ class MergeRequest < ActiveRecord::Base
"#{project.to_reference(from, full: full)}#{reference}"
end
def commits
if persisted?
merge_request_diff.commits
elsif compare_commits
compare_commits.reverse
else
[]
end
end
def commits_count
if persisted?
merge_request_diff.commits_count
elsif compare_commits
compare_commits.size
else
0
end
end
def commit_shas
if persisted?
merge_request_diff.commit_shas
elsif compare_commits
compare_commits.reverse.map(&:sha)
else
[]
end
end
def first_commit
merge_request_diff ? merge_request_diff.first_commit : compare_commits.first
end
@ -246,9 +273,7 @@ class MergeRequest < ActiveRecord::Base
def diff_size
# Calling `merge_request_diff.diffs.real_size` will also perform
# highlighting, which we don't need here.
return real_size if merge_request_diff
diffs.real_size
merge_request_diff&.real_size || diffs.real_size
end
def diff_base_commit

View File

@ -580,16 +580,20 @@ class User < ActiveRecord::Base
keys.count == 0 && Gitlab::ProtocolAccess.allowed?('ssh')
end
def require_password?
password_automatically_set? && !ldap_user? && current_application_settings.signin_enabled?
def require_password_creation?
password_automatically_set? && allow_password_authentication?
end
def require_personal_access_token?
return false if current_application_settings.signin_enabled? || ldap_user?
def require_personal_access_token_creation_for_git_auth?
return false if allow_password_authentication? || ldap_user?
PersonalAccessTokensFinder.new(user: self, impersonation: false, state: 'active').execute.none?
end
def allow_password_authentication?
!ldap_user? && current_application_settings.password_authentication_enabled?
end
def can_change_username?
gitlab_config.username_changing_enabled
end
@ -699,7 +703,7 @@ class User < ActiveRecord::Base
end
def sanitize_attrs
%w[name username skype linkedin twitter].each do |attr|
%w[username skype linkedin twitter].each do |attr|
value = public_send(attr)
public_send("#{attr}=", Sanitize.clean(value)) if value.present?
end

View File

@ -76,6 +76,12 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
end
end
def target_branch_tree_path
if target_branch_exists?
project_tree_path(project, target_branch)
end
end
def target_branch_commits_path
if target_branch_exists?
project_commits_path(project, target_branch)
@ -94,7 +100,7 @@ class MergeRequestPresenter < Gitlab::View::Presenter::Delegated
if source_branch_exists?
namespace = link_to(namespace, project_path(source_project))
branch = link_to(branch, project_commits_path(source_project, source_branch))
branch = link_to(branch, project_tree_path(source_project, source_branch))
end
if for_fork?

View File

@ -97,6 +97,10 @@ class MergeRequestEntity < IssuableEntity
presenter(merge_request).target_branch_commits_path
end
expose :target_branch_tree_path do |merge_request|
presenter(merge_request).target_branch_tree_path
end
expose :new_blob_path do |merge_request|
if can?(current_user, :push_code, merge_request.project)
project_new_blob_path(merge_request.project, merge_request.source_branch)

View File

@ -7,9 +7,8 @@ module MergeRequests
source_project = @project
@project = Project.find(params[:target_project_id]) if params[:target_project_id]
params[:target_project_id] ||= source_project.id
merge_request = MergeRequest.new
merge_request.target_project = @project
merge_request.source_project = source_project
merge_request.source_branch = params[:source_branch]
merge_request.merge_params['force_remove_source_branch'] = params.delete(:force_remove_source_branch)

View File

@ -145,9 +145,9 @@
.form-group
.col-sm-offset-2.col-sm-10
.checkbox
= f.label :signin_enabled do
= f.check_box :signin_enabled
Sign-in enabled
= f.label :password_authentication_enabled do
= f.check_box :password_authentication_enabled
Password authentication enabled
- if omniauth_enabled? && button_based_providers.any?
.form-group
= f.label :enabled_oauth_sign_in_sources, 'Enabled OAuth sign-in sources', class: 'control-label col-sm-2'

View File

@ -6,15 +6,15 @@
- else
= render 'devise/shared/tabs_normal'
.tab-content
- if signin_enabled? || ldap_enabled? || crowd_enabled?
- if password_authentication_enabled? || ldap_enabled? || crowd_enabled?
= render 'devise/shared/signin_box'
-# Signup only makes sense if you can also sign-in
- if signin_enabled? && signup_enabled?
- if password_authentication_enabled? && signup_enabled?
= render 'devise/shared/signup_box'
-# Show a message if none of the mechanisms above are enabled
- if !signin_enabled? && !ldap_enabled? && !(omniauth_enabled? && devise_mapping.omniauthable?)
- if !password_authentication_enabled? && !ldap_enabled? && !(omniauth_enabled? && devise_mapping.omniauthable?)
%div
No authentication methods configured.

View File

@ -7,12 +7,12 @@
.login-box.tab-pane{ id: "#{server['provider_name']}", role: 'tabpanel', class: active_when(i.zero? && !crowd_enabled?) }
.login-body
= render 'devise/sessions/new_ldap', server: server
- if signin_enabled?
- if password_authentication_enabled?
.login-box.tab-pane{ id: 'ldap-standard', role: 'tabpanel' }
.login-body
= render 'devise/sessions/new_base'
- elsif signin_enabled?
- elsif password_authentication_enabled?
.login-box.tab-pane.active{ id: 'login-pane', role: 'tabpanel' }
.login-body
= render 'devise/sessions/new_base'

View File

@ -5,9 +5,9 @@
- @ldap_servers.each_with_index do |server, i|
%li{ class: active_when(i.zero? && !crowd_enabled?) }
= link_to server['label'], "##{server['provider_name']}", 'data-toggle' => 'tab'
- if signin_enabled?
- if password_authentication_enabled?
%li
= link_to 'Standard', '#ldap-standard', 'data-toggle' => 'tab'
- if signin_enabled? && signup_enabled?
- if password_authentication_enabled? && signup_enabled?
%li
= link_to 'Register', '#register-pane', 'data-toggle' => 'tab'

View File

@ -1,6 +1,6 @@
%ul.nav-links.new-session-tabs.nav-tabs{ role: 'tablist' }
%li.active{ role: 'presentation' }
%a{ href: '#login-pane', data: { toggle: 'tab' }, role: 'tab' } Sign in
- if signin_enabled? && signup_enabled?
- if password_authentication_enabled? && signup_enabled?
%li{ role: 'presentation' }
%a{ href: '#register-pane', data: { toggle: 'tab' }, role: 'tab' } Register

View File

@ -1,2 +1,2 @@
- BroadcastMessage.current.each do |message|
- BroadcastMessage.current&.each do |message|
= broadcast_message(message)

View File

@ -1,7 +1,7 @@
!!! 5
%html{ lang: I18n.locale, class: "#{page_class}" }
= render "layouts/head"
%body{ class: @body_class, data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}" } }
%body{ class: @body_class, data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}", find_file: find_file_path } }
= render "layouts/init_auto_complete" if @gfm_form
- if show_new_nav?
= render "layouts/header/new"

View File

@ -75,7 +75,7 @@
%li
= link_to "Settings", profile_path
%li
= link_to "Turn on new nav", profile_preferences_path(anchor: "new-navigation")
= link_to "Turn on new navigation", profile_preferences_path(anchor: "new-navigation")
%li.divider
%li
= link_to "Sign out", destroy_user_session_path, method: :delete, class: "sign-out-link"
@ -91,8 +91,3 @@
= yield :header_content
= render 'shared/outdated_browser'
- if @project && !@project.empty_repo?
- if ref = @ref || @project.repository.root_ref
:javascript
var findFileURL = "#{project_find_file_path(@project, ref)}";

View File

@ -69,7 +69,7 @@
%li
= link_to "Settings", profile_path
%li
= link_to "Turn off new nav", profile_preferences_path(anchor: "new-navigation")
= link_to "Turn off new navigation", profile_preferences_path(anchor: "new-navigation")
%li.divider
%li
= link_to "Sign out", destroy_user_session_path, method: :delete, class: "sign-out-link"
@ -84,8 +84,3 @@
= icon('times', class: 'js-navbar-toggle-left', style: 'display: none;')
= render 'shared/outdated_browser'
- if @project && !@project.empty_repo?
- if ref = @ref || @project.repository.root_ref
:javascript
var findFileURL = "#{project_find_file_path(@project, ref)}";

View File

@ -29,7 +29,7 @@
= link_to profile_emails_path, title: 'Emails' do
%span
Emails
- unless current_user.ldap_user?
- if current_user.allow_password_authentication?
= nav_link(controller: :passwords) do
= link_to edit_profile_password_path, title: 'Password' do
%span

View File

@ -30,7 +30,7 @@
%ul.dropdown-menu.dropdown-menu-align-right
%li.visible-xs-block.visible-sm-block
= link_to project_tree_path(@project, @commit) do
_('Browse Files')
#{ _('Browse Files') }
- unless @commit.has_been_reverted?(current_user)
%li.clearfix
= revert_commit_link(@commit, project_commit_path(@project, @commit.id), has_tooltip: false)

View File

@ -11,7 +11,7 @@
#js-details-block-vue
- if can?(current_user, :read_build, @project) && (@build.artifacts? || @build.artifacts_expired?)
.block{ class: ("block-first" if !@build.coverage) }
.block
.title
Job artifacts
- if @build.artifacts_expired?
@ -37,7 +37,7 @@
Browse
- if @build.trigger_request
.build-widget
.build-widget.block
%h4.title
Trigger
@ -55,7 +55,7 @@
.js-build-variable.trigger-build-variable= key
.js-build-value.trigger-build-value= value
.block
%div{ class: (@build.pipeline.stages_count > 1 ? "block" : "block-last") }
%p
Commit
= link_to @build.pipeline.short_sha, project_commit_path(@project, @build.pipeline.sha), class: 'commit-sha link-commit'
@ -69,7 +69,7 @@
- if @build.pipeline.stages_count > 1
.dropdown.build-dropdown
.title
%div
%span{ class: "ci-status-icon-#{@build.pipeline.status}" }
= ci_icon_for_status(@build.pipeline.status)
Pipeline

View File

@ -8,7 +8,7 @@
%p
Metrics are automatically configured and monitored
based on a library of metrics from popular exporters.
= link_to 'More information', '#'
= link_to 'More information', help_page_path('user/project/integrations/prometheus')
.col-lg-9
.panel.panel-default.js-panel-monitored-metrics{ data: { "active-metrics" => "#{project_prometheus_active_metrics_path(@project, :json)}" } }
@ -41,5 +41,5 @@
%code
$CI_ENVIRONMENT_SLUG
to exporter&rsquo;s queries.
= link_to 'More information', '#'
= link_to 'More information', help_page_path('user/project/integrations/prometheus', anchor: 'metrics-and-labels')
%ul.list-unstyled.metrics-list.js-missing-var-metrics-list

View File

@ -0,0 +1,4 @@
---
title: "Insert user name directly without encoding"
merge_request: 10085
author: Nathan Neulinger <nneul@neulinger.org>

View File

@ -0,0 +1,4 @@
---
title: Supplement Portuguese Brazil translation of Project Page & Repository Page
merge_request: 12156
author: Huang Tao

View File

@ -0,0 +1,4 @@
---
title: Return `is_admin` attribute in the GET /user endpoint for admins
merge_request: 12811
author:

View File

@ -0,0 +1,4 @@
---
title: Updates vue resource and code according to breaking changes
merge_request:
author:

View File

@ -0,0 +1,4 @@
---
title: Bump scss-lint to 0.54.0
merge_request: 12733
author: Takuya Noguchi

View File

@ -0,0 +1,4 @@
---
title: Remove public/ci/favicon.ico
merge_request: 12803
author: Takuya Noguchi

View File

@ -0,0 +1,4 @@
---
title: Fix vertical space in job details sidebar
merge_request:
author:

View File

@ -0,0 +1,4 @@
---
title: Increase width of dropdown menus automatically
merge_request: 12809
author: Thomas Wucher

View File

@ -0,0 +1,4 @@
---
title: Enable BangFormat in scss-lint [ci skip]
merge_request: 12815
author: Takuya Noguchi

View File

@ -0,0 +1,4 @@
---
title: Enable DeclarationOrder in scss-lint
merge_request: 12805
author: Takuya Noguchi

View File

@ -0,0 +1,4 @@
---
title: Enable UnnecessaryParentReference in scss-lint
merge_request: 12738
author: Takuya Noguchi

View File

@ -0,0 +1,4 @@
---
title: Fixes needed when GitLab sign-in is not enabled
merge_request: 12491
author: Robin Bobbitt

View File

@ -0,0 +1,4 @@
---
title: MR branch link now links to tree instead of commits
merge_request:
author:

View File

@ -0,0 +1,4 @@
---
title: Replace 'browse_files.feature' spinach test with an rspec analog
merge_request: 12251
author: @blackst0ne

View File

@ -223,7 +223,7 @@ rescue ArgumentError # no user configured
end
Settings.gitlab['time_zone'] ||= nil
Settings.gitlab['signup_enabled'] ||= true if Settings.gitlab['signup_enabled'].nil?
Settings.gitlab['signin_enabled'] ||= true if Settings.gitlab['signin_enabled'].nil?
Settings.gitlab['password_authentication_enabled'] ||= true if Settings.gitlab['password_authentication_enabled'].nil?
Settings.gitlab['restricted_visibility_levels'] = Settings.__send__(:verify_constant_array, Gitlab::VisibilityLevel, Settings.gitlab['restricted_visibility_levels'], [])
Settings.gitlab['username_changing_enabled'] = true if Settings.gitlab['username_changing_enabled'].nil?
Settings.gitlab['issue_closing_pattern'] = '((?:[Cc]los(?:e[sd]?|ing)|[Ff]ix(?:e[sd]|ing)?|[Rr]esolv(?:e[sd]?|ing))(:?) +(?:(?:issues? +)?%{issue_ref}(?:(?:, *| +and +)?)|([A-Z][A-Z0-9_]+-\d+))+)' if Settings.gitlab['issue_closing_pattern'].nil?

View File

@ -0,0 +1,15 @@
class RenameApplicationSettingsSigninEnabledToPasswordAuthenticationEnabled < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
rename_column_concurrently :application_settings, :signin_enabled, :password_authentication_enabled
end
def down
cleanup_concurrent_column_rename :application_settings, :password_authentication_enabled, :signin_enabled
end
end

View File

@ -0,0 +1,15 @@
class CleanupApplicationSettingsSigninEnabledRename < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
cleanup_concurrent_column_rename :application_settings, :signin_enabled, :password_authentication_enabled
end
def down
rename_column_concurrently :application_settings, :password_authentication_enabled, :signin_enabled
end
end

View File

@ -41,7 +41,6 @@ ActiveRecord::Schema.define(version: 20170707184244) do
create_table "application_settings", force: :cascade do |t|
t.integer "default_projects_limit"
t.boolean "signup_enabled"
t.boolean "signin_enabled"
t.boolean "gravatar_enabled"
t.text "sign_in_text"
t.datetime "created_at"
@ -127,6 +126,7 @@ ActiveRecord::Schema.define(version: 20170707184244) do
t.boolean "help_page_hide_commercial_content", default: false
t.string "help_page_support_url"
t.integer "performance_bar_allowed_group_id"
t.boolean "password_authentication_enabled"
end
create_table "audit_events", force: :cascade do |t|

View File

@ -25,7 +25,7 @@ Example response:
"id" : 1,
"default_branch_protection" : 2,
"restricted_visibility_levels" : [],
"signin_enabled" : true,
"password_authentication_enabled" : true,
"after_sign_out_path" : null,
"max_attachment_size" : 10,
"user_oauth_applications" : true,
@ -63,7 +63,7 @@ PUT /application/settings
| --------- | ---- | :------: | ----------- |
| `default_projects_limit` | integer | no | Project limit per user. Default is `100000` |
| `signup_enabled` | boolean | no | Enable registration. Default is `true`. |
| `signin_enabled` | boolean | no | Enable login via a GitLab account. Default is `true`. |
| `password_authentication_enabled` | boolean | no | Enable authentication via a GitLab account password. Default is `true`. |
| `gravatar_enabled` | boolean | no | Enable Gravatar |
| `sign_in_text` | string | no | Text on login page |
| `home_page_url` | string | no | Redirect to this URL when not logged in |
@ -102,7 +102,7 @@ Example response:
"id": 1,
"default_projects_limit": 100000,
"signup_enabled": true,
"signin_enabled": true,
"password_authentication_enabled": true,
"gravatar_enabled": true,
"sign_in_text": "",
"created_at": "2015-06-12T15:51:55.432Z",

View File

@ -364,7 +364,7 @@ GET /user
Parameters:
- `sudo` (required) - the ID of a user
- `sudo` (optional) - the ID of a user to make the call in their place
```
GET /user

Some files were not shown because too many files have changed in this diff Show More