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

View File

@ -762,9 +762,9 @@ GEM
sawyer (0.8.1) sawyer (0.8.1)
addressable (>= 2.3.5, < 2.6) addressable (>= 2.3.5, < 2.6)
faraday (~> 0.8, < 1.0) faraday (~> 0.8, < 1.0)
scss_lint (0.47.1) scss_lint (0.54.0)
rake (>= 0.9, < 11) rake (>= 0.9, < 13)
sass (~> 3.4.15) sass (~> 3.4.20)
securecompare (1.0.0) securecompare (1.0.0)
seed-fu (2.3.6) seed-fu (2.3.6)
activerecord (>= 3.1) activerecord (>= 3.1)
@ -1081,7 +1081,7 @@ DEPENDENCIES
rugged (~> 0.25.1.1) rugged (~> 0.25.1.1)
sanitize (~> 2.0) sanitize (~> 2.0)
sass-rails (~> 5.0.6) sass-rails (~> 5.0.6)
scss_lint (~> 0.47.0) scss_lint (~> 0.54.0)
seed-fu (~> 2.3.5) seed-fu (~> 2.3.5)
select2-rails (~> 3.5.9) select2-rails (~> 3.5.9)
sentry-raven (~> 2.5.3) 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: { methods: {
loadFile() { loadFile() {
this.$http.get(el.dataset.endpoint) this.$http.get(el.dataset.endpoint)
.then(response => response.json())
.then((res) => { .then((res) => {
this.json = res.json(); this.json = res;
this.loading = false; this.loading = false;
}) })
.catch((e) => { .catch((e) => {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -51,11 +51,11 @@
}, },
methods: { methods: {
successCallback(resp) { successCallback(resp) {
const response = resp.json(); return resp.json().then((response) => {
// depending of the endpoint the response can either bring a `pipelines` key or not.
// depending of the endpoint the response can either bring a `pipelines` key or not. const pipelines = response.pipelines || response;
const pipelines = response.pipelines || response; this.setCommonData(pipelines);
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 CommentsStore */
/* global ResolveService */ /* global ResolveService */
/* global Flash */ /* global Flash */
@ -64,8 +64,6 @@ const ResolveBtn = Vue.extend({
}); });
}, },
resolve: function () { resolve: function () {
const errorFlashMsg = 'An error occurred when trying to resolve a comment. Please try again.';
if (!this.canResolve) return; if (!this.canResolve) return;
let promise; let promise;
@ -79,24 +77,20 @@ const ResolveBtn = Vue.extend({
.resolve(this.noteId); .resolve(this.noteId);
} }
promise.then((response) => { promise
this.loading = false; .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; const resolved_by = data ? data.resolved_by : null;
CommentsStore.update(this.discussionId, this.noteId, !this.isResolved, resolved_by); CommentsStore.update(this.discussionId, this.noteId, !this.isResolved, resolved_by);
this.discussion.updateHeadline(data); this.discussion.updateHeadline(data);
gl.mrWidget.checkStatus(); gl.mrWidget.checkStatus();
} else {
new Flash(errorFlashMsg);
}
this.updateTooltip(); this.updateTooltip();
}).catch(() => { })
new Flash(errorFlashMsg); .catch(() => new Flash('An error occurred when trying to resolve a comment. Please try again.'));
});
} }
}, },
mounted: function () { 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 Flash */
/* global CommentsStore */ /* global CommentsStore */
@ -32,27 +31,22 @@ class ResolveServiceClass {
promise = this.resolveAll(mergeRequestId, discussionId); promise = this.resolveAll(mergeRequestId, discussionId);
} }
promise.then((response) => { promise
discussion.loading = false; .then(resp => resp.json())
.then((data) => {
if (response.status === 200) { discussion.loading = false;
const data = response.json(); const resolvedBy = data ? data.resolved_by : null;
const resolved_by = data ? data.resolved_by : null;
if (isResolved) { if (isResolved) {
discussion.unResolveAllNotes(); discussion.unResolveAllNotes();
} else { } else {
discussion.resolveAllNotes(resolved_by); discussion.resolveAllNotes(resolvedBy);
} }
gl.mrWidget.checkStatus(); gl.mrWidget.checkStatus();
discussion.updateHeadline(data); 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) { resolveAll(mergeRequestId, discussionId) {
@ -62,7 +56,7 @@ class ResolveServiceClass {
return this.discussionResource.save({ return this.discussionResource.save({
mergeRequestId, mergeRequestId,
discussionId discussionId,
}, {}); }, {});
} }
@ -73,7 +67,7 @@ class ResolveServiceClass {
return this.discussionResource.delete({ return this.discussionResource.delete({
mergeRequestId, mergeRequestId,
discussionId discussionId,
}, {}); }, {});
} }
} }

View File

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

View File

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

View File

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

View File

@ -99,8 +99,10 @@ document.addEventListener('DOMContentLoaded', () => {
page: currentPath, page: currentPath,
}, document.title, currentPath); }, document.title, currentPath);
this.updateGroups(response.json()); return response.json().then((data) => {
this.updatePagination(response.headers); this.updateGroups(data);
this.updatePagination(response.headers);
});
}) })
.catch(this.handleErrorResponse); .catch(this.handleErrorResponse);
}, },
@ -114,18 +116,19 @@ document.addEventListener('DOMContentLoaded', () => {
}, },
leaveGroup(group, collection) { leaveGroup(group, collection) {
this.service.leaveGroup(group.leavePath) this.service.leaveGroup(group.leavePath)
.then(resp => resp.json())
.then((response) => { .then((response) => {
$.scrollTo(0); $.scrollTo(0);
this.store.removeGroup(group, collection); this.store.removeGroup(group, collection);
// eslint-disable-next-line no-new // 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.'; 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'; 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({ this.poll = new Poll({
resource: this.service, resource: this.service,
method: 'getData', method: 'getData',
successCallback: (res) => { successCallback: res => res.json().then(data => this.store.updateState(data)),
const data = res.json();
this.store.updateState(data);
},
errorCallback(err) { errorCallback(err) {
throw new Error(err); throw new Error(err);
}, },

View File

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

View File

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

View File

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

View File

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

View File

@ -40,10 +40,10 @@ export default class pipelinesMediator {
} }
successCallback(response) { successCallback(response) {
const data = response.json(); return response.json().then((data) => {
this.state.isLoading = false;
this.state.isLoading = false; this.store.storePipeline(data);
this.store.storePipeline(data); });
} }
errorCallback() { 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 */ /* 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 Mousetrap */
/* global findFileURL */
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import findAndFollowLink from './shortcuts_dashboard_navigation'; import findAndFollowLink from './shortcuts_dashboard_navigation';
@ -20,6 +19,7 @@ import findAndFollowLink from './shortcuts_dashboard_navigation';
const $globalDropdownMenu = $('.global-dropdown-menu'); const $globalDropdownMenu = $('.global-dropdown-menu');
const $globalDropdownToggle = $('.global-dropdown-toggle'); const $globalDropdownToggle = $('.global-dropdown-toggle');
const findFileURL = document.body.dataset.findFile;
$('.global-dropdown').on('hide.bs.dropdown', () => { $('.global-dropdown').on('hide.bs.dropdown', () => {
$globalDropdownMenu.removeClass('shortcuts'); $globalDropdownMenu.removeClass('shortcuts');

View File

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

View File

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

View File

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

View File

@ -44,9 +44,8 @@
text: this.$slots.textarea[0].elm.value, text: this.$slots.textarea[0].elm.value,
}, },
) )
.then((res) => { .then(resp => resp.json())
const data = res.json(); .then((data) => {
this.markdownPreviewLoading = false; this.markdownPreviewLoading = false;
this.markdownPreview = data.body; 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) => { Vue.http.interceptors.push((request, next) => {
if ($.rails) { if ($.rails) {
// eslint-disable-next-line no-param-reassign request.headers.set('X-CSRF-Token', $.rails.csrfToken());
request.headers['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-positive,
.award-control-icon-super-positive { .award-control-icon-super-positive {
@include transition(opacity, transform);
position: absolute; position: absolute;
left: 10px; left: 10px;
bottom: 6px; bottom: 6px;
opacity: 0; opacity: 0;
@include transition(opacity, transform);
} }
.award-control-text { .award-control-text {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -11,7 +11,7 @@
.is-dragging { .is-dragging {
// Important because plugin sets inline CSS // Important because plugin sets inline CSS
opacity: 1!important; opacity: 1 !important;
* { * {
-webkit-user-select: none; -webkit-user-select: none;
@ -19,8 +19,8 @@
-ms-user-select: none; -ms-user-select: none;
user-select: none; user-select: none;
// !important to make sure no style can override this when dragging // !important to make sure no style can override this when dragging
cursor: -webkit-grabbing!important; cursor: -webkit-grabbing !important;
cursor: grabbing!important; cursor: grabbing !important;
} }
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -5,13 +5,13 @@
} }
.example { .example {
padding: 15px;
border: 1px dashed $ui-dev-kit-example-border;
margin-bottom: 15px;
&::before { &::before {
content: "Example"; content: "Example";
color: $ui-dev-kit-example-color; 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.wiki-pages-list.content-list {
& ul { ul {
list-style: none; list-style: none;
margin-left: 0; margin-left: 0;
padding-left: 15px; padding-left: 15px;
} }
& ul li { ul li {
padding: 5px 0; padding: 5px 0;
} }
} }

View File

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

View File

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

View File

@ -170,7 +170,7 @@ class ApplicationController < ActionController::Base
end end
def check_password_expiration 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 return redirect_to new_profile_password_path
end end
end end

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -50,12 +50,12 @@ module ButtonHelper
def http_clone_button(project, placement = 'right', append_link: true) def http_clone_button(project, placement = 'right', append_link: true)
klass = 'http-selector' 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 protocol = gitlab_config.protocol.upcase
tooltip_title = 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 } _("Set a password on your account to pull or push via %{protocol}.") % { protocol: protocol }
else else
_("Create a personal access token on your account to pull or push via %{protocol}.") % { protocol: protocol } _("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? def show_no_password_message?
cookies[:hide_no_password_message].blank? && !current_user.hide_no_password && 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 end
def link_to_set_password 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 link_to s_('SetPasswordToCloneLink|set a password'), edit_profile_password_path
else else
link_to s_('CreateTokenToCloneLink|create a personal access token'), profile_personal_access_tokens_path 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 || [] current_application_settings.restricted_visibility_levels || []
end 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 end

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -145,9 +145,9 @@
.form-group .form-group
.col-sm-offset-2.col-sm-10 .col-sm-offset-2.col-sm-10
.checkbox .checkbox
= f.label :signin_enabled do = f.label :password_authentication_enabled do
= f.check_box :signin_enabled = f.check_box :password_authentication_enabled
Sign-in enabled Password authentication enabled
- if omniauth_enabled? && button_based_providers.any? - if omniauth_enabled? && button_based_providers.any?
.form-group .form-group
= f.label :enabled_oauth_sign_in_sources, 'Enabled OAuth sign-in sources', class: 'control-label col-sm-2' = 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 - else
= render 'devise/shared/tabs_normal' = render 'devise/shared/tabs_normal'
.tab-content .tab-content
- if signin_enabled? || ldap_enabled? || crowd_enabled? - if password_authentication_enabled? || ldap_enabled? || crowd_enabled?
= render 'devise/shared/signin_box' = render 'devise/shared/signin_box'
-# Signup only makes sense if you can also sign-in -# 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' = render 'devise/shared/signup_box'
-# Show a message if none of the mechanisms above are enabled -# 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 %div
No authentication methods configured. 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-box.tab-pane{ id: "#{server['provider_name']}", role: 'tabpanel', class: active_when(i.zero? && !crowd_enabled?) }
.login-body .login-body
= render 'devise/sessions/new_ldap', server: server = render 'devise/sessions/new_ldap', server: server
- if signin_enabled? - if password_authentication_enabled?
.login-box.tab-pane{ id: 'ldap-standard', role: 'tabpanel' } .login-box.tab-pane{ id: 'ldap-standard', role: 'tabpanel' }
.login-body .login-body
= render 'devise/sessions/new_base' = render 'devise/sessions/new_base'
- elsif signin_enabled? - elsif password_authentication_enabled?
.login-box.tab-pane.active{ id: 'login-pane', role: 'tabpanel' } .login-box.tab-pane.active{ id: 'login-pane', role: 'tabpanel' }
.login-body .login-body
= render 'devise/sessions/new_base' = render 'devise/sessions/new_base'

View File

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

View File

@ -1,6 +1,6 @@
%ul.nav-links.new-session-tabs.nav-tabs{ role: 'tablist' } %ul.nav-links.new-session-tabs.nav-tabs{ role: 'tablist' }
%li.active{ role: 'presentation' } %li.active{ role: 'presentation' }
%a{ href: '#login-pane', data: { toggle: 'tab' }, role: 'tab' } Sign in %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' } %li{ role: 'presentation' }
%a{ href: '#register-pane', data: { toggle: 'tab' }, role: 'tab' } Register %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) = broadcast_message(message)

View File

@ -1,7 +1,7 @@
!!! 5 !!! 5
%html{ lang: I18n.locale, class: "#{page_class}" } %html{ lang: I18n.locale, class: "#{page_class}" }
= render "layouts/head" = 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 = render "layouts/init_auto_complete" if @gfm_form
- if show_new_nav? - if show_new_nav?
= render "layouts/header/new" = render "layouts/header/new"

View File

@ -75,7 +75,7 @@
%li %li
= link_to "Settings", profile_path = link_to "Settings", profile_path
%li %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.divider
%li %li
= link_to "Sign out", destroy_user_session_path, method: :delete, class: "sign-out-link" = link_to "Sign out", destroy_user_session_path, method: :delete, class: "sign-out-link"
@ -91,8 +91,3 @@
= yield :header_content = yield :header_content
= render 'shared/outdated_browser' = 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 %li
= link_to "Settings", profile_path = link_to "Settings", profile_path
%li %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.divider
%li %li
= link_to "Sign out", destroy_user_session_path, method: :delete, class: "sign-out-link" = 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;') = icon('times', class: 'js-navbar-toggle-left', style: 'display: none;')
= render 'shared/outdated_browser' = 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 = link_to profile_emails_path, title: 'Emails' do
%span %span
Emails Emails
- unless current_user.ldap_user? - if current_user.allow_password_authentication?
= nav_link(controller: :passwords) do = nav_link(controller: :passwords) do
= link_to edit_profile_password_path, title: 'Password' do = link_to edit_profile_password_path, title: 'Password' do
%span %span

View File

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

View File

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

View File

@ -8,7 +8,7 @@
%p %p
Metrics are automatically configured and monitored Metrics are automatically configured and monitored
based on a library of metrics from popular exporters. 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 .col-lg-9
.panel.panel-default.js-panel-monitored-metrics{ data: { "active-metrics" => "#{project_prometheus_active_metrics_path(@project, :json)}" } } .panel.panel-default.js-panel-monitored-metrics{ data: { "active-metrics" => "#{project_prometheus_active_metrics_path(@project, :json)}" } }
@ -41,5 +41,5 @@
%code %code
$CI_ENVIRONMENT_SLUG $CI_ENVIRONMENT_SLUG
to exporter&rsquo;s queries. 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 %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 end
Settings.gitlab['time_zone'] ||= nil Settings.gitlab['time_zone'] ||= nil
Settings.gitlab['signup_enabled'] ||= true if Settings.gitlab['signup_enabled'].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['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['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? 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| create_table "application_settings", force: :cascade do |t|
t.integer "default_projects_limit" t.integer "default_projects_limit"
t.boolean "signup_enabled" t.boolean "signup_enabled"
t.boolean "signin_enabled"
t.boolean "gravatar_enabled" t.boolean "gravatar_enabled"
t.text "sign_in_text" t.text "sign_in_text"
t.datetime "created_at" t.datetime "created_at"
@ -127,6 +126,7 @@ ActiveRecord::Schema.define(version: 20170707184244) do
t.boolean "help_page_hide_commercial_content", default: false t.boolean "help_page_hide_commercial_content", default: false
t.string "help_page_support_url" t.string "help_page_support_url"
t.integer "performance_bar_allowed_group_id" t.integer "performance_bar_allowed_group_id"
t.boolean "password_authentication_enabled"
end end
create_table "audit_events", force: :cascade do |t| create_table "audit_events", force: :cascade do |t|

View File

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

View File

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

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