Commit a4fa44ce authored by Achilleas Pipinellis's avatar Achilleas Pipinellis

Merge branch 'master' into 'docs/change-docs-reviewers'

# Conflicts:
#   doc/development/doc_styleguide.md
parents 5174b7ad 195c1057
......@@ -99,7 +99,7 @@ update-knapsack:
- export KNAPSACK_REPORT_PATH=knapsack/spinach_node_${CI_NODE_INDEX}_${CI_NODE_TOTAL}_report.json
- export KNAPSACK_GENERATE_REPORT=true
- cp knapsack/spinach_report.json ${KNAPSACK_REPORT_PATH}
- knapsack spinach "-r rerun" || retry '[ ! -e tmp/spinach-rerun.txt ] || bundle exec spinach -r rerun $(cat tmp/spinach-rerun.txt)'
- knapsack spinach "-r rerun" || retry '[[ -e tmp/spinach-rerun.txt ]] && bundle exec spinach -r rerun $(cat tmp/spinach-rerun.txt)'
artifacts:
expire_in: 31d
paths:
......
See the general Documentation guidelines http://docs.gitlab.com/ce/development/doc_styleguide.html.
See the general Documentation guidelines http://docs.gitlab.com/ce/development/doc_styleguide.html
## What does this MR do?
......
......@@ -61,7 +61,7 @@ linters:
# Separate rule, function, and mixin declarations with empty lines.
EmptyLineBetweenBlocks:
enabled: false
enabled: true
# Reports when you have an empty rule set.
EmptyRule:
......@@ -219,7 +219,7 @@ linters:
# Property values, @extend, @include, and @import directives, and variable
# declarations should always end with a semicolon.
TrailingSemicolon:
enabled: false
enabled: true
# Reports lines containing trailing whitespace.
TrailingWhitespace:
......
......@@ -4,6 +4,8 @@ v 8.13.0 (unreleased)
- Improve Merge When Build Succeeds triggers and execute on pipeline success. (!6675)
- Respond with 404 Not Found for non-existent tags (Linus Thiel)
- Truncate long labels with ellipsis in labels page
- Improve tabbing usability for sign in page (ClemMakesApps)
- Enforce TrailingSemicolon and EmptyLineBetweenBlocks in scss-lint
- Adding members no longer silently fails when there is extra whitespace
- Update runner version only when updating contacted_at
- Add link from system note to compare with previous version
......@@ -14,6 +16,7 @@ v 8.13.0 (unreleased)
- Add an example for testing a phoenix application with Gitlab CI in the docs (Manthan Mallikarjun)
- Updating verbiage on git basics to be more intuitive
- Clarify documentation for Runners API (Gennady Trafimenkov)
- The instrumentation for Banzai::Renderer has been restored
- Change user & group landing page routing from /u/:username to /:username
- Prevent running GfmAutocomplete setup for each diff note !6569
- Added documentation for .gitattributes files
......@@ -24,6 +27,7 @@ v 8.13.0 (unreleased)
- Create a new /templates namespace for the /licenses, /gitignores and /gitlab_ci_ymls API endpoints. !5717 (tbalthazar)
- Speed-up group milestones show page
- Fix inconsistent options dropdown caret on mobile viewports (ClemMakesApps)
- Extract project#update_merge_requests and SystemHooks to its own worker from GitPushService
- Don't include archived projects when creating group milestones. !4940 (Jeroen Jacobs)
- Add tag shortcut from the Commit page. !6543
- Keep refs for each deployment
......@@ -50,6 +54,7 @@ v 8.13.0 (unreleased)
- Add new issue button to each list on Issues Board
- Added soft wrap button to repository file/blob editor
- Update namespace validation to forbid reserved names (.git and .atom) (Will Starms)
- Show the time ago a merge request was deployed to an environment
- Add word-wrap to issue title on issue and milestone boards (ClemMakesApps)
- Fix todos page mobile viewport layout (ClemMakesApps)
- Fix inconsistent highlighting of already selected activity nav-links (ClemMakesApps)
......@@ -112,10 +117,12 @@ v 8.13.0 (unreleased)
- Fixes padding in all clipboard icons that have .btn class
- Fix a typo in doc/api/labels.md
- API: all unknown routing will be handled with 404 Not Found
- Add docs for request profiling
- Make guests unable to view MRs on private projects
v 8.12.7
- Use gitlab-markup gem instead of github-markup to fix `.rst` file rendering. !6659
- Fix GFM autocomplete setup being called several times
v 8.12.6
- Update mailroom to 0.8.1 in Gemfile.lock !6814
......@@ -263,6 +270,7 @@ v 8.12.0
- Remove prefixes from transition CSS property (ClemMakesApps)
- Add Sentry logging to API calls
- Add BroadcastMessage API
- Merge request tabs are fixed when scrolling page
- Use 'git update-ref' for safer web commits !6130
- Sort pipelines requested through the API
- Automatically expand hidden discussions when accessed by a permalink !5585 (Mike Greiling)
......@@ -369,6 +377,7 @@ v 8.11.7
- Avoid conflict with admin labels when importing GitHub labels. !6158
- Restores `fieldName` to allow only string values in `gl_dropdown.js`. !6234
- Allow the Rails cookie to be used for API authentication.
- Login/Register UX upgrade !6328
v 8.11.6
- Fix unnecessary horizontal scroll area in pipeline visualizations. !6005
......
......@@ -15,18 +15,17 @@
this.hideSidebar = bind(this.hideSidebar, this);
this.toggleSidebar = bind(this.toggleSidebar, this);
this.updateDropdown = bind(this.updateDropdown, this);
this.$document = $(document);
clearInterval(Build.interval);
// Init breakpoint checker
this.bp = Breakpoints.get();
$('.js-build-sidebar').niceScroll();
this.initSidebar();
this.populateJobs(this.build_stage);
this.updateStageDropdownText(this.build_stage);
this.hideSidebar();
$(document).off('click', '.js-sidebar-build-toggle').on('click', '.js-sidebar-build-toggle', this.toggleSidebar);
$(window).off('resize.build').on('resize.build', this.hideSidebar);
$(document).off('click', '.stage-item').on('click', '.stage-item', this.updateDropdown);
this.$document.off('click', '.stage-item').on('click', '.stage-item', this.updateDropdown);
$('#js-build-scroll > a').off('click').on('click', this.stepTrace);
this.updateArtifactRemoveDate();
if ($('#build-trace').length) {
......@@ -62,6 +61,21 @@
}
}
Build.prototype.initSidebar = function() {
this.$sidebar = $('.js-build-sidebar');
this.sidebarTranslationLimits = {
min: $('.navbar-gitlab').outerHeight() + $('.layout-nav').outerHeight()
}
this.sidebarTranslationLimits.max = this.sidebarTranslationLimits.min + $('.scrolling-tabs-container').outerHeight();
this.$sidebar.css({
top: this.sidebarTranslationLimits.max
});
this.$sidebar.niceScroll();
this.hideSidebar();
this.$document.off('click', '.js-sidebar-build-toggle').on('click', '.js-sidebar-build-toggle', this.toggleSidebar);
this.$document.off('scroll.translateSidebar').on('scroll.translateSidebar', this.translateSidebar.bind(this));
};
Build.prototype.getInitialBuildTrace = function() {
var removeRefreshStatuses = ['success', 'failed', 'canceled', 'skipped']
......@@ -129,15 +143,23 @@
Build.prototype.toggleSidebar = function() {
if (this.shouldHideSidebar()) {
return $('.js-build-sidebar').toggleClass('right-sidebar-expanded right-sidebar-collapsed');
return this.$sidebar.toggleClass('right-sidebar-expanded right-sidebar-collapsed');
}
};
Build.prototype.translateSidebar = function(e) {
var newPosition = this.sidebarTranslationLimits.max - document.body.scrollTop;
if (newPosition < this.sidebarTranslationLimits.min) newPosition = this.sidebarTranslationLimits.min;
this.$sidebar.css({
top: newPosition
});
};
Build.prototype.hideSidebar = function() {
if (this.shouldHideSidebar()) {
return $('.js-build-sidebar').removeClass('right-sidebar-expanded').addClass('right-sidebar-collapsed');
return this.$sidebar.removeClass('right-sidebar-expanded').addClass('right-sidebar-collapsed');
} else {
return $('.js-build-sidebar').removeClass('right-sidebar-collapsed').addClass('right-sidebar-expanded');
return this.$sidebar.removeClass('right-sidebar-collapsed').addClass('right-sidebar-expanded');
}
};
......
......@@ -8,6 +8,7 @@
Dispatcher = (function() {
function Dispatcher() {
this.initSearch();
this.initFieldErrors();
this.initPageScripts();
}
......@@ -20,6 +21,9 @@
path = page.split(':');
shortcut_handler = null;
switch (page) {
case 'sessions:new':
new UsernameValidator();
break;
case 'projects:boards:show':
case 'projects:boards:index':
shortcut_handler = new ShortcutsNavigation();
......@@ -140,12 +144,12 @@
break;
case 'groups:group_members:index':
new gl.MemberExpirationDate();
new GroupMembers();
new gl.Members();
new UsersSelect();
break;
case 'projects:project_members:index':
new gl.MemberExpirationDate();
new ProjectMembers();
new gl.Members();
new UsersSelect();
break;
case 'groups:new':
......@@ -291,6 +295,12 @@
}
};
Dispatcher.prototype.initFieldErrors = function() {
$('.show-gl-field-errors').each((i, form) => {
new gl.GlFieldErrors(form);
});
};
return Dispatcher;
})();
......
......@@ -25,7 +25,7 @@
return function(e) {
e.preventDefault();
e.stopPropagation();
return _this.input.val('').trigger('keyup').focus();
return _this.input.val('').trigger('input').focus();
};
})(this));
// Key events
......@@ -37,28 +37,16 @@
e.preventDefault()
}
})
.on('keyup', function(e) {
var keyCode;
keyCode = e.which;
if (ARROW_KEY_CODES.indexOf(keyCode) >= 0) {
return;
}
.on('input', function() {
if (this.input.val() !== "" && !$inputContainer.hasClass(HAS_VALUE_CLASS)) {
$inputContainer.addClass(HAS_VALUE_CLASS);
} else if (this.input.val() === "" && $inputContainer.hasClass(HAS_VALUE_CLASS)) {
$inputContainer.removeClass(HAS_VALUE_CLASS);
}
if (keyCode === 13 && !options.elIsInput) {
return false;
}
// Only filter asynchronously only if option remote is set
if (this.options.remote) {
clearTimeout(timeout);
return timeout = setTimeout(function() {
var blurField = this.shouldBlur(keyCode);
if (blurField && this.filterInputBlur) {
this.input.blur();
}
return this.options.query(this.input.val(), function(data) {
return this.options.callback(data);
}.bind(this));
......@@ -255,7 +243,7 @@
_this.fullData = data;
_this.parseData(_this.fullData);
if (_this.options.filterable && _this.filter && _this.filter.input) {
return _this.filter.input.trigger('keyup');
return _this.filter.input.trigger('input');
}
};
// Remote data
......@@ -487,7 +475,7 @@
// Triggering 'keyup' will re-render the dropdown which is not always required
// specially if we want to keep the state of the dropdown needed for bulk-assignment
if (!this.options.persistWhenHide) {
$input.trigger("keyup");
$input.trigger("input");
}
if (this.dropdown.find(".dropdown-toggle-page").length) {
$('.dropdown-menu', this.dropdown).removeClass(PAGE_TWO_CLASS);
......@@ -500,14 +488,27 @@
// Render the full menu
GitLabDropdown.prototype.renderMenu = function(html) {
var menu_html;
menu_html = "";
if (this.options.renderMenu) {
menu_html = this.options.renderMenu(html);
return this.options.renderMenu(html);
} else {
menu_html = $('<ul />').append(html);
var ul = document.createElement('ul');
for (var i = 0; i < html.length; i++) {
var el = html[i];
if (el instanceof jQuery) {
el = el.get(0);
}
if (typeof el === 'string') {
ul.innerHTML += el;
} else {
ul.appendChild(el);
}
}
return ul;
}
return menu_html;
};
// Append the menu into the dropdown
......@@ -521,7 +522,7 @@
};
GitLabDropdown.prototype.renderItem = function(data, group, index) {
var cssClass, field, fieldName, groupAttrs, html, selected, text, url, value;
var field, fieldName, html, selected, text, url, value;
if (group == null) {
group = false;
}
......@@ -529,18 +530,16 @@
// Render the row
index = false;
}
html = "";
// Divider
if (data === "divider") {
return "<li class='divider'></li>";
}
// Separator is a full-width divider
if (data === "separator") {
return "<li class='separator'></li>";
html = document.createElement('li');
if (data === 'divider' || data === 'separator') {
html.className = data;
return html;
}
// Header
if (data.header != null) {
return _.template('<li class="dropdown-header"><%- header %></li>')({ header: data.header });
html.className = 'dropdown-header';
html.innerHTML = data.header;
return html;
}
if (this.options.renderRow) {
// Call the render function
......@@ -567,24 +566,25 @@
} else {
text = data.text != null ? data.text : '';
}
cssClass = "";
if (selected) {
cssClass = "is-active";
}
if (this.highlight) {
text = this.highlightTextMatches(text, this.filterInput.val());
}
// Create the list item & the link
var link = document.createElement('a');
link.href = url;
link.innerHTML = text;
if (selected) {
link.className = 'is-active';
}
if (group) {
groupAttrs = 'data-group=' + group + ' data-index=' + index;
} else {
groupAttrs = '';
link.dataset.group = group;
link.dataset.index = index;
}
html = _.template('<li><a href="<%- url %>" <%- groupAttrs %> class="<%- cssClass %>"><%= text %></a></li>')({
url: url,
groupAttrs: groupAttrs,
cssClass: cssClass,
text: text
});
html.appendChild(link);
}
return html;
};
......
((global) => {
/*
* This class overrides the browser's validation error bubbles, displaying custom
* error messages for invalid fields instead. To begin validating any form, add the
* class `show-gl-field-errors` to the form element, and ensure error messages are
* declared in each inputs' title attribute.
*
* Example:
*
* <form class='show-gl-field-errors'>
* <input type='text' name='username' title='Username is required.'/>
*</form>
*
* */
const errorMessageClass = 'gl-field-error';
const inputErrorClass = 'gl-field-error-outline';
class GlFieldError {
constructor({ input, formErrors }) {
this.inputElement = $(input);
this.inputDomElement = this.inputElement.get(0);
this.form = formErrors;
this.errorMessage = this.inputElement.attr('title') || 'This field is required.';
this.fieldErrorElement = $(`<p class='${errorMessageClass} hide'>${ this.errorMessage }</p>`);
this.state = {
valid: false,
empty: true
};
this.initFieldValidation();
}
initFieldValidation() {
// hidden when injected into DOM
this.inputElement.after(this.fieldErrorElement);
this.inputElement.off('invalid').on('invalid', this.handleInvalidSubmit.bind(this));
this.scopedSiblings = this.safelySelectSiblings();
}
safelySelectSiblings() {
// Apply `ignoreSelector` in markup to siblings whose visibility should not be toggled with input validity
const ignoreSelector = '.validation-ignore';
const unignoredSiblings = this.inputElement.siblings(`p:not(${ignoreSelector})`);
const parentContainer = this.inputElement.parent('.form-group');
// Only select siblings when they're scoped within a form-group with one input
const safelyScoped = parentContainer.length && parentContainer.find('input').length === 1;
return safelyScoped ? unignoredSiblings : this.fieldErrorElement;
}
renderValidity() {
this.renderClear();
if (this.state.valid) {
return this.renderValid();
}
if (this.state.empty) {
return this.renderEmpty();
}
if (!this.state.valid) {
return this.renderInvalid();
}
}
handleInvalidSubmit(event) {
event.preventDefault();
const currentValue = this.accessCurrentValue();
this.state.valid = false;
this.state.empty = currentValue === '';
this.renderValidity();
this.form.focusOnFirstInvalid.apply(this.form);
// For UX, wait til after first invalid submission to check each keyup
this.inputElement.off('keyup.field_validator')
.on('keyup.field_validator', this.updateValidity.bind(this));
}
/* Get or set current input value */
accessCurrentValue(newVal) {
return newVal ? this.inputElement.val(newVal) : this.inputElement.val();
}
getInputValidity() {
return this.inputDomElement.validity.valid;
}
updateValidity() {
const inputVal = this.accessCurrentValue();
this.state.empty = !inputVal.length;
this.state.valid = this.getInputValidity();
this.renderValidity();
}
renderValid() {
return this.renderClear();
}
renderEmpty() {
return this.renderInvalid();
}
renderInvalid() {
this.inputElement.addClass(inputErrorClass);
this.scopedSiblings.hide();
return this.fieldErrorElement.show();
}
renderClear() {
const inputVal = this.accessCurrentValue();
if (!inputVal.split(' ').length) {
const trimmedInput = inputVal.trim();
this.accessCurrentValue(trimmedInput);
}
this.inputElement.removeClass(inputErrorClass);
this.scopedSiblings.hide();
this.fieldErrorElement.hide();
}
}
const customValidationFlag = 'no-gl-field-errors';
class GlFieldErrors {
constructor(form) {
this.form = $(form);
this.state = {
inputs: [],
valid: false
};
this.initValidators();
}
initValidators () {
// select all non-hidden inputs in form
this.state.inputs = this.form.find(':input:not([type=hidden])').toArray()
.filter((input) => !input.classList.contains(customValidationFlag))
.map((input) => new GlFieldError({ input, formErrors: this }));
this.form.on('submit', this.catchInvalidFormSubmit);
}
/* Neccessary to prevent intercept and override invalid form submit
* because Safari & iOS quietly allow form submission when form is invalid
* and prevents disabling of invalid submit button by application.js */
catchInvalidFormSubmit (event) {
if (!event.currentTarget.checkValidity()) {
event.preventDefault();
event.stopPropagation();
}
}
focusOnFirstInvalid () {
const firstInvalid = this.state.inputs.filter((input) => !input.inputDomElement.validity.valid)[0];
firstInvalid.inputElement.focus();
}
}
global.GlFieldErrors = GlFieldErrors;
})(window.gl || (window.gl = {}));
(function() {
this.GroupMembers = (function() {
function GroupMembers() {
$('li.group_member').bind('ajax:success', function() {
return $(this).fadeOut();
});
}
return GroupMembers;
})();
}).call(this);
......@@ -14,14 +14,18 @@
inputs.datepicker({
dateFormat: 'yy-mm-dd',
minDate: 1,
onSelect: toggleClearInput
onSelect: function () {
$(this).trigger('change');
toggleClearInput.call(this);
}
});
inputs.next('.js-clear-input').on('click', function(event) {
event.preventDefault();
var input = $(this).closest('.clearable-input').find('.js-access-expiration-date');
input.datepicker('setDate', null);
input.datepicker('setDate', null)
.trigger('change');
toggleClearInput.call(input);
});
......
((w) => {
w.gl = w.gl || {};
class Members {
constructor() {
this.addListeners();
}
addListeners() {
$('.project_member, .group_member').off('ajax:success').on('ajax:success', this.removeRow);
$('.js-member-update-control').off('change').on('change', this.formSubmit);
$('.js-edit-member-form').off('ajax:success').on('ajax:success', this.formSuccess);
}
removeRow(e) {
const $target = $(e.target);
if ($target.hasClass('btn-remove')) {
$target.closest('.member')
.fadeOut(function () {
$(this).remove();
});
}
}
formSubmit() {
$(this).closest('form').trigger("submit.rails").end().disable();
}
formSuccess() {
$(this).find('.js-member-update-control').enable();
}
}
gl.Members = Members;
})(window);
......@@ -71,6 +71,7 @@
this._location = location;
this.bindEvents();
this.activateTab(this.opts.action);
this.initAffix();
}
MergeRequestTabs.prototype.bindEvents = function() {
......@@ -380,6 +381,46 @@
// Only when sidebar is collapsed
};
MergeRequestTabs.prototype.initAffix = function () {
var $tabs = $('.js-tabs-affix');
// Screen space on small screens is usually very sparse
// So we dont affix the tabs on these
if (Breakpoints.get().getBreakpointSize() === 'xs' || !$tabs.length) return;
var tabsWidth = $tabs.outerWidth(),
$diffTabs = $('#diff-notes-app'),
offsetTop = $tabs.offset().top - ($('.navbar-fixed-top').height() + $('.layout-nav').height());
$tabs.off('affix.bs.affix affix-top.bs.affix')
.affix({
offset: {
top: offsetTop
}
}).on('affix.bs.affix', function () {
$tabs.css({
left: $tabs.offset().left,
width: tabsWidth
});
$diffTabs.css({
marginTop: $tabs.height()
});
}).on('affix-top.bs.affix', function () {
$tabs.css({
left: '',
width: ''
});
$diffTabs.css({
marginTop: ''
});
});
// Fix bug when reloading the page already scrolling
if ($tabs.hasClass('affix')) {
$tabs.trigger('affix.bs.affix');
}
};
return MergeRequestTabs;
})();
......
(function() {
((global) => {
var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
this.MergeRequestWidget = (function() {
const DEPLOYMENT_TEMPLATE = `<div class="mr-widget-heading" id="<%- id %>">
<div class="ci_widget ci-success">
<%= ci_success_icon %>
<span>
Deployed to
<a href="<%- url %>" target="_blank" class="environment">
<%- name %>
</a>
<span class="js-environment-timeago" data-toggle="tooltip" data-placement="top" data-title="<%- deployed_at_formatted %>">
<%- deployed_at %>
</span>
<a class="js-environment-link" href="<%- external_url %>" target="_blank">
<i class="fa fa-external-link"></i>
View on <%- external_url_formatted %>
</a>
</span>
</div>
</div>`;
global.MergeRequestWidget = (function() {
function MergeRequestWidget(opts) {
// Initialize MergeRequestWidget behavior
//
......@@ -10,17 +29,23 @@
// ci_status_url - String, URL to use to check CI status
//
this.opts = opts;
this.$widgetBody = $('.mr-widget-body');
$('#modal_merge_info').modal({
show: false
});
this.firstCICheck = true;
this.readyForCICheck = false;
this.readyForCIEnvironmentCheck = false;
this.cancel = false;
clearInterval(this.fetchBuildStatusInterval);
clearInterval(this.fetchBuildEnvironmentStatusInterval);
this.clearEventListeners();
this.addEventListeners();
this.getCIStatus(false);
this.getCIEnvironmentsStatus();
this.retrieveSuccessIcon();
this.pollCIStatus();
this.pollCIEnvironmentsStatus();
notifyPermissions();
}
......@@ -41,6 +66,7 @@
page = $('body').data('page').split(':').last();
if (allowedPages.indexOf(page) < 0) {
clearInterval(_this.fetchBuildStatusInterval);
clearInterval(_this.fetchBuildEnvironmentStatusInterval);
_this.cancelPolling();
return _this.clearEventListeners();
}
......@@ -48,6 +74,12 @@
})(this));
};
MergeRequestWidget.prototype.retrieveSuccessIcon = function() {
const $ciSuccessIcon = $('.js-success-icon');
this.$ciSuccessIcon = $ciSuccessIcon.html();
$ciSuccessIcon.remove();
}
MergeRequestWidget.prototype.mergeInProgress = function(deleteSourceBranch) {
if (deleteSourceBranch == null) {
deleteSourceBranch = false;
......@@ -62,7 +94,7 @@
urlSuffix = deleteSourceBranch ? '?deleted_source_branch=true' : '';
return window.location.href = window.location.pathname + urlSuffix;
} else if (data.merge_error) {
return $('.mr-widget-body').html("<h4>" + data.merge_error + "</h4>");
return this.$widgetBody.html("<h4>" + data.merge_error + "</h4>");
} else {
callback = function() {
return merge_request_widget.mergeInProgress(deleteSourceBranch);
......@@ -118,6 +150,7 @@
if (data.status === '') {
return;
}
if (data.environments && data.environments.length) _this.renderEnvironments(data.environments);
if (_this.firstCICheck || data.status !== _this.opts.ci_status && (data.status != null)) {
_this.opts.ci_status = data.status;
_this.showCIStatus(data.status);
......@@ -150,6 +183,41 @@
})(this));
};
MergeRequestWidget.prototype.pollCIEnvironmentsStatus = function() {
this.fetchBuildEnvironmentStatusInterval = setInterval(() => {
if (!this.readyForCIEnvironmentCheck) return;
this.getCIEnvironmentsStatus();
this.readyForCIEnvironmentCheck = false;
}, 300000);
};
MergeRequestWidget.prototype.getCIEnvironmentsStatus = function() {
$.getJSON(this.opts.ci_environments_status_url, (environments) => {
if (this.cancel) return;
this.readyForCIEnvironmentCheck = true;
if (environments && environments.length) this.renderEnvironments(environments);
});
};
MergeRequestWidget.prototype.renderEnvironments = function(environments) {
for (let i = 0; i < environments.length; i++) {
const environment = environments[i];
if ($(`.mr-state-widget #${ environment.id }`).length) return;
const $template = $(DEPLOYMENT_TEMPLATE);
if (!environment.external_url || !environment.external_url_formatted) $('.js-environment-link', $template).remove();
if (environment.deployed_at && environment.deployed_at_formatted) {
environment.deployed_at = $.timeago(environment.deployed_at) + '.';
} else {
$('.js-environment-timeago', $template).remove();
environment.name += '.';
}
environment.ci_success_icon = this.$ciSuccessIcon;
const templateString = _.unescape($template[0].outerHTML);
const template = _.template(templateString)(environment)
this.$widgetBody.before(template);
}
};
MergeRequestWidget.prototype.showCIStatus = function(state) {
var allowed_states;
if (state == null) {
......@@ -190,4 +258,4 @@
})();
}).call(this);
})(window.gl || (window.gl = {}));
(function() {
this.ProjectMembers = (function() {
function ProjectMembers() {
$('li.project_member').bind('ajax:success', function() {
return $(this).fadeOut();
});
}
return ProjectMembers;
})();
}).call(this);
......@@ -16,7 +16,13 @@
if (initialQuery.name) this.requestFile(initialQuery);
$('.reset-template', this.dropdown.parent()).on('click', () => {
if (this.currentTemplate) this.setInputValueToTemplateContent(false);
this.setInputValueToTemplateContent();
});
$('.no-template', this.dropdown.parent()).on('click', () => {
this.currentTemplate = '';
this.setInputValueToTemplateContent();
$('.dropdown-toggle-text', this.dropdown).text('Choose a template');
});
}
......
((global) => {
const debounceTimeoutDuration = 1000;
const invalidInputClass = 'gl-field-error-outline';
const successInputClass = 'gl-field-success-outline';
const unavailableMessageSelector = '.username .validation-error';
const successMessageSelector = '.username .validation-success';
const pendingMessageSelector = '.username .validation-pending';
const invalidMessageSelector = '.username .gl-field-error';
class UsernameValidator {
constructor() {
this.inputElement = $('#new_user_username');
this.inputDomElement = this.inputElement.get(0);
this.state = {
available: false,
valid: false,
pending: false,
empty: true
};
const debounceTimeout = _.debounce((username) => {
this.validateUsername(username);
}, debounceTimeoutDuration);
this.inputElement.on('keyup.username_check', () => {
const username = this.inputElement.val();
this.state.valid = this.inputDomElement.validity.valid;
this.state.empty = !username.length;
if (this.state.valid) {
return debounceTimeout(username);
}
this.renderState();
});
// Override generic field validation
this.inputElement.on('invalid', this.interceptInvalid.bind(this));
}
renderState() {
// Clear all state
this.clearFieldValidationState();
if (this.state.valid && this.state.available) {
return this.setSuccessState();
}
if (this.state.empty) {
return this.clearFieldValidationState();
}
if (this.state.pending) {
return this.setPendingState();
}
if (!this.state.available) {
return this.setUnavailableState();
}
if (!this.state.valid) {
return this.setInvalidState();
}
}
interceptInvalid(event) {
event.preventDefault();
event.stopPropagation();
}
validateUsername(username) {
if (this.state.valid) {
this.state.pending = true;
this.state.available = false;
this.renderState();
return $.ajax({
type: 'GET',
url: `/u/${username}/exists`,
dataType: 'json',
success: (res) => this.setAvailabilityState(res.exists)
});
}
}
setAvailabilityState(usernameTaken) {
if (usernameTaken) {
this.state.valid = false;
this.state.available = false;
} else {
this.state.available = true;
}
this.state.pending = false;
this.renderState();
}
clearFieldValidationState() {
this.inputElement.siblings('p').hide();
this.inputElement.removeClass(invalidInputClass)
.removeClass(successInputClass);
}
setUnavailableState() {
const $usernameUnavailableMessage = this.inputElement.siblings(unavailableMessageSelector);
this.inputElement.addClass(invalidInputClass).removeClass(successInputClass);
$usernameUnavailableMessage.show();
}
setSuccessState() {
const $usernameSuccessMessage = this.inputElement.siblings(successMessageSelector);
this.inputElement.addClass(successInputClass).removeClass(invalidInputClass);
$usernameSuccessMessage.show();
}
setPendingState() {
const $usernamePendingMessage = $(pendingMessageSelector);
if (this.state.pending) {
$usernamePendingMessage.show();
} else {
$usernamePendingMessage.hide();
}
}
setInvalidState() {
const $inputErrorMessage = $(invalidMessageSelector);
this.inputElement.addClass(invalidInputClass).removeClass(successInputClass);
$inputErrorMessage.show();
}
}
global.UsernameValidator = UsernameValidator;
})(window);
......@@ -325,6 +325,10 @@
};
UsersSelect.prototype.user = function(user_id, callback) {
if(!/^\d+$/.test(user_id)) {
return false;
}
var url;
url = this.buildUrl(this.userPath);
url = url.replace(':id', user_id);
......
......@@ -5,6 +5,7 @@
display: none;
&.hide { display: block; }
}
&.open .content {
display: block;
&.hide { display: none; }
......
......@@ -19,6 +19,7 @@
&.diff-collapsed {
padding: 5px;
.click-to-expand {
cursor: pointer;
}
......@@ -203,6 +204,7 @@
}
}
}
&.user-cover-block {
padding: 24px 0 0;
}
......
......@@ -25,7 +25,7 @@
&:focus {
background-color: $hover-background;
color: $hover-text;
border-color: $hover-border;;
border-color: $hover-border;
}
}
......@@ -152,7 +152,8 @@
@include btn-blue-medium;
}
&.btn-info {
&.btn-info,
&.btn-register {
@include btn-blue;
}
......@@ -240,6 +241,7 @@
width: 100%;
margin: 0;
margin-bottom: 15px;
&.btn {
padding: 6px 0;
}
......@@ -321,6 +323,7 @@
.btn-build {
margin-left: 10px;
i {
color: $gl-icon-color;
}
......@@ -328,6 +331,7 @@
.clone-dropdown-btn a {
color: $dropdown-link-color;
&:hover {
text-decoration: none;
}
......@@ -337,6 +341,7 @@
background-color: $background-color !important;
border: 1px solid lightgrey;
cursor: default;
&:active {
-moz-box-shadow: inset 0 0 0 white;
-webkit-box-shadow: inset 0 0 0 white;
......
......@@ -13,10 +13,12 @@
color: $text-color;
background: $background-color;
}
.bs-callout h4 {
margin-top: 0;
margin-bottom: 5px;
}
.bs-callout p:last-child {
margin-bottom: 0;
}
......@@ -27,16 +29,19 @@
border-color: #eed3d7;
color: #b94a48;
}
.bs-callout-warning {
background-color: #faf8f0;
border-color: #faebcc;
color: #8a6d3b;
}
.bs-callout-info {
background-color: #f4f8fa;
border-color: #bce8f1;
color: #34789a;
}
.bs-callout-success {
background-color: #dff0d8;
border-color: #5ca64d;
......
/** COLORS **/
.cgray { color: $gl-gray; }
.clgray { color: #bbb }
.clgray { color: #bbb; }
.cred { color: $gl-text-red; }
.cgreen { color: $gl-text-green; }
.cdark { color: #444 }
.cdark { color: #444; }
/** COMMON CLASSES **/
.prepend-top-0 { margin-top: 0; }
.prepend-top-5 { margin-top: 5px; }
.prepend-top-10 { margin-top: 10px }
.prepend-top-10 { margin-top: 10px; }
.prepend-top-default { margin-top: $gl-padding !important; }
.prepend-top-20 { margin-top: 20px }
.prepend-left-5 { margin-left: 5px }
.prepend-left-10 { margin-left: 10px }
.prepend-top-20 { margin-top: 20px; }
.prepend-left-5 { margin-left: 5px; }
.prepend-left-10 { margin-left: 10px; }
.prepend-left-default { margin-left: $gl-padding; }
.prepend-left-20 { margin-left: 20px }
.append-right-5 { margin-right: 5px }
.append-right-10 { margin-right: 10px }
.prepend-left-20 { margin-left: 20px; }
.append-right-5 { margin-right: 5px; }
.append-right-10 { margin-right: 10px; }
.append-right-default { margin-right: $gl-padding; }
.append-right-20 { margin-right: 20px }
.append-bottom-0 { margin-bottom: 0 }
.append-bottom-10 { margin-bottom: 10px }
.append-bottom-15 { margin-bottom: 15px }
.append-bottom-20 { margin-bottom: 20px }
.append-right-20 { margin-right: 20px; }
.append-bottom-0 { margin-bottom: 0; }
.append-bottom-10 { margin-bottom: 10px; }
.append-bottom-15 { margin-bottom: 15px; }
.append-bottom-20 { margin-bottom: 20px; }
.append-bottom-default { margin-bottom: $gl-padding; }
.inline { display: inline-block }
.center { text-align: center }
.inline { display: inline-block; }
.center { text-align: center; }
.underlined-link { text-decoration: underline; }
.hint { font-style: italic; color: #999; }
......@@ -97,6 +97,7 @@ span.update-author {
color: #999;
font-weight: normal;
font-style: italic;
strong {
font-weight: bold;
font-style: normal;
......@@ -128,7 +129,7 @@ p.time {
// Fix issue with notes & lists creating a bunch of bottom borders.
li.note {
img { max-width: 100% }
img { max-width: 100%; }
.note-title {
li {
border-bottom: none !important;
......@@ -172,6 +173,7 @@ li.note {
@extend .col-md-6;
text-align: left;
margin-top: 40px;
pre {
background: white;
border: none;
......@@ -197,6 +199,7 @@ li.note {
background: #c67;
color: #fff;
font-weight: bold;
a {
color: #fff;
text-decoration: underline;
......@@ -227,6 +230,7 @@ li.note {
&.milestone-closed {
background: $gray-light;
}
.progress {
margin-bottom: 0;
margin-top: 4px;
......@@ -286,6 +290,7 @@ table {
.footer-links {
margin-bottom: 20px;
a {
margin-right: 15px;
}
......
......@@ -12,6 +12,7 @@
.dropdown-menu,
.dropdown-menu-nav {
display: block;
@media (max-width: $screen-xs-max) {
width: 100%;
}
......@@ -48,6 +49,7 @@
margin-top: -6px;
color: $dropdown-toggle-icon-color;
font-size: 10px;
&.fa-spinner {
font-size: 16px;
margin-top: -8px;
......
......@@ -26,15 +26,6 @@
padding: 10px $gl-padding;
word-wrap: break-word;
border-radius: 3px 3px 0 0;
cursor: pointer;
&:hover {
background-color: $dark-background-color;
}
.diff-toggle-caret {
padding-right: 6px;
}
&.file-title-clear {
padding-left: 0;
......@@ -66,6 +57,7 @@
margin-top: -3px;
}
}
.file-content {
background: #fff;
......@@ -105,22 +97,27 @@
border: none;
margin: 0;
}
tr {
border-bottom: 1px solid #eee;
}
td {
&:first-child {
border-left: none;
}
&:last-child {
border-right: none;
}
}
td.blame-commit {
padding: 0 10px;
min-width: 400px;
background: $gray-light;
}
td.line-numbers {
float: none;
border-left: 1px solid #ddd;
......@@ -130,6 +127,7 @@
margin-right: 0;
}
}
td.lines {
padding: 0;
}
......@@ -146,8 +144,10 @@
border-left: 1px solid $border-color;
margin-bottom: 0;
background: white;
li {
color: #888;
p {
margin: 0;
color: #333;
......
......@@ -9,7 +9,7 @@ input {
input[type='text'].danger {
background: #f2dede!important;
border-color: #d66;
text-shadow: 0 1px 1px #fff
text-shadow: 0 1px 1px #fff;
}
.datetime-controls {
......@@ -73,8 +73,8 @@ label {
}
.form-control {
box-shadow: none;
border-radius: 3px;
@include box-shadow(none);
border-radius: 2px;
padding: $gl-vert-padding $gl-input-padding;
}
......@@ -117,9 +117,11 @@ label {
display: table-cell;
width: 200px !important;
}
.input-group-addon {
background-color: #f7f8fa;
}
.input-group-addon:not(:first-child):not(:last-child) {
border-left: 0;
border-right: 0;
......@@ -129,3 +131,8 @@ label {
.help-block {
margin-bottom: 0;
}
.gl-field-error {
color: $red-normal;
}
......@@ -62,7 +62,7 @@
}
i {
color: $white-light
color: $white-light;
}
path,
......
......@@ -168,6 +168,7 @@ header {
a {
color: $gl-text-color;
&:hover {
text-decoration: underline;
}
......
......@@ -60,6 +60,7 @@
padding-top: 1px;
margin: 0;
color: $gray-dark;
img {
position: relative;
top: 3px;
......@@ -128,6 +129,10 @@ ul.content-list {
color: $gl-dark-link-color;
}
.member-group-link {
color: $blue-normal;
}
.description {
p {
@include str-truncated;
......@@ -168,6 +173,14 @@ ul.content-list {
}
}
.member-controls {
float: none;
@media (min-width: $screen-sm-min) {
float: right;
}
}
// When dragging a list item
&.ui-sortable-helper {
border-bottom: none;
......
......@@ -37,6 +37,7 @@
0%, 10%, 100% {
fill: lighten($tanuki-yellow, 25%);
}
90% {
fill: $tanuki-yellow;
}
......@@ -48,6 +49,7 @@
10%, 80% {
fill: $tanuki-orange;
}
20%, 90% {
fill: lighten($tanuki-orange, 25%);
}
......@@ -59,6 +61,7 @@
10%, 80% {
fill: $tanuki-red;
}
20%, 90% {
fill: lighten($tanuki-red, 25%);
}
......@@ -70,6 +73,7 @@
20%, 70% {
fill: $tanuki-red;
}
30%, 80% {
fill: lighten($tanuki-red, 25%);
}
......@@ -81,6 +85,7 @@
30%, 60% {
fill: $tanuki-orange;
}
40%, 70% {
fill: lighten($tanuki-orange, 25%);
}
......@@ -92,6 +97,7 @@
30%, 60% {
fill: $tanuki-red;
}
40%, 70% {
fill: lighten($tanuki-red, 25%);
}
......@@ -103,6 +109,7 @@
40% {
fill: $tanuki-yellow;
}
60% {
fill: lighten($tanuki-yellow, 25%);
}
......
......@@ -34,6 +34,7 @@
&.active {
background: $gray-light;
a {
font-weight: 600;
}
......
......@@ -210,6 +210,7 @@
@media (max-width: $screen-xs-max) {
padding-bottom: 0;
width: 100%;
.btn, form, .dropdown, .dropdown-menu-toggle, .form-control {
margin: 0 0 10px;
display: block;
......
......@@ -13,6 +13,11 @@
.dropdown-menu-toggle {
line-height: 20px;
}
.badge {
margin-top: -2px;
margin-left: 5px;
}
}
.panel-body {
......
......@@ -93,7 +93,7 @@
background: none;
.select2-search-field input {
padding: $gl-padding / 2;
padding: 5px $gl-padding / 2;
font-size: 13px;
height: auto;
font-family: inherit;
......@@ -101,7 +101,7 @@
}
.select2-search-choice {
margin: 8px 0 0 8px;
margin: 5px 0 0 8px;
box-shadow: none;
border-color: $input-border;
color: $gl-text-color;
......@@ -137,6 +137,7 @@
.select2-results {
max-height: 350px;
.select2-highlighted {
background: $gl-primary;
}
......@@ -212,9 +213,11 @@
.group-image {
float: left;
}
.group-name {
font-weight: bold;
}
.group-path {
color: #999;
}
......@@ -239,6 +242,7 @@
color: #aaa;
font-weight: normal;
}
.namespace-path {
margin-left: 10px;
font-weight: bolder;
......
......@@ -48,6 +48,7 @@
&:before {
background: none;
}
.timeline-entry .timeline-entry-inner {
.timeline-icon {
display: none;
......
......@@ -48,31 +48,40 @@
.clearfix {
@include clearfix();
}
.center-block {
@include center-block();
}
.pull-right {
float: right !important;
}
.pull-left {
float: left !important;
}
.hide {
display: none;
}
.show {
display: block !important;
}
.invisible {
visibility: hidden;
}
.text-hide {
@include text-hide();
}
.hidden {
display: none !important;
visibility: hidden !important;
}
.affix {
position: fixed;
}
......@@ -146,6 +155,7 @@
padding: 6px 15px;
font-size: 13px;
font-weight: normal;
a {
color: #777;
}
......
......@@ -106,6 +106,7 @@
@extend .table-bordered;
margin: 12px 0;
color: #5c5d5e;
th {
background: #f8fafc;
}
......
......@@ -55,68 +55,68 @@
color: #000 !important;
}
.hll { background-color: #373b41 }
.c { color: #969896 } /* Comment */
.err { color: #c66 } /* Error */
.k { color: #b294bb } /* Keyword */
.l { color: #de935f } /* Literal */
.n { color: #c5c8c6 } /* Name */
.o { color: #8abeb7 } /* Operator */
.p { color: #c5c8c6 } /* Punctuation */
.cm { color: #969896 } /* Comment.Multiline */
.cp { color: #969896 } /* Comment.Preproc */
.c1 { color: #969896 } /* Comment.Single */
.cs { color: #969896 } /* Comment.Special */
.gd { color: #c66 } /* Generic.Deleted */
.ge { font-style: italic } /* Generic.Emph */
.gh { color: #c5c8c6; font-weight: bold } /* Generic.Heading */
.gi { color: #b5bd68 } /* Generic.Inserted */
.gp { color: #969896; font-weight: bold } /* Generic.Prompt */
.gs { font-weight: bold } /* Generic.Strong */
.gu { color: #8abeb7; font-weight: bold } /* Generic.Subheading */
.kc { color: #b294bb } /* Keyword.Constant */
.kd { color: #b294bb } /* Keyword.Declaration */
.kn { color: #8abeb7 } /* Keyword.Namespace */
.kp { color: #b294bb } /* Keyword.Pseudo */
.kr { color: #b294bb } /* Keyword.Reserved */
.kt { color: #f0c674 } /* Keyword.Type */
.ld { color: #b5bd68 } /* Literal.Date */
.m { color: #de935f } /* Literal.Number */
.s { color: #b5bd68 } /* Literal.String */
.na { color: #81a2be } /* Name.Attribute */
.nb { color: #c5c8c6 } /* Name.Builtin */
.nc { color: #f0c674 } /* Name.Class */
.no { color: #c66 } /* Name.Constant */
.nd { color: #8abeb7 } /* Name.Decorator */
.ni { color: #c5c8c6 } /* Name.Entity */
.ne { color: #c66 } /* Name.Exception */
.nf { color: #81a2be } /* Name.Function */
.nl { color: #c5c8c6 } /* Name.Label */
.nn { color: #f0c674 } /* Name.Namespace */
.nx { color: #81a2be } /* Name.Other */
.py { color: #c5c8c6 } /* Name.Property */
.nt { color: #8abeb7 } /* Name.Tag */
.nv { color: #c66 } /* Name.Variable */
.ow { color: #8abeb7 } /* Operator.Word */
.w { color: #c5c8c6 } /* Text.Whitespace */
.mf { color: #de935f } /* Literal.Number.Float */
.mh { color: #de935f } /* Literal.Number.Hex */
.mi { color: #de935f } /* Literal.Number.Integer */
.mo { color: #de935f } /* Literal.Number.Oct */
.sb { color: #b5bd68 } /* Literal.String.Backtick */
.sc { color: #c5c8c6 } /* Literal.String.Char */
.sd { color: #969896 } /* Literal.String.Doc */
.s2 { color: #b5bd68 } /* Literal.String.Double */
.se { color: #de935f } /* Literal.String.Escape */
.sh { color: #b5bd68 } /* Literal.String.Heredoc */
.si { color: #de935f } /* Literal.String.Interpol */
.sx { color: #b5bd68 } /* Literal.String.Other */
.sr { color: #b5bd68 } /* Literal.String.Regex */
.s1 { color: #b5bd68 } /* Literal.String.Single */
.ss { color: #b5bd68 } /* Literal.String.Symbol */
.bp { color: #c5c8c6 } /* Name.Builtin.Pseudo */
.vc { color: #c66 } /* Name.Variable.Class */
.vg { color: #c66 } /* Name.Variable.Global */
.vi { color: #c66 } /* Name.Variable.Instance */
.il { color: #de935f } /* Literal.Number.Integer.Long */
.hll { background-color: #373b41; }
.c { color: #969896; } /* Comment */
.err { color: #c66; } /* Error */
.k { color: #b294bb; } /* Keyword */
.l { color: #de935f; } /* Literal */
.n { color: #c5c8c6; } /* Name */
.o { color: #8abeb7; } /* Operator */
.p { color: #c5c8c6; } /* Punctuation */
.cm { color: #969896; } /* Comment.Multiline */
.cp { color: #969896; } /* Comment.Preproc */
.c1 { color: #969896; } /* Comment.Single */
.cs { color: #969896; } /* Comment.Special */
.gd { color: #c66; } /* Generic.Deleted */
.ge { font-style: italic; } /* Generic.Emph */
.gh { color: #c5c8c6; font-weight: bold; } /* Generic.Heading */
.gi { color: #b5bd68; } /* Generic.Inserted */
.gp { color: #969896; font-weight: bold; } /* Generic.Prompt */
.gs { font-weight: bold; } /* Generic.Strong */
.gu { color: #8abeb7; font-weight: bold; } /* Generic.Subheading */
.kc { color: #b294bb; } /* Keyword.Constant */
.kd { color: #b294bb; } /* Keyword.Declaration */
.kn { color: #8abeb7; } /* Keyword.Namespace */
.kp { color: #b294bb; } /* Keyword.Pseudo */
.kr { color: #b294bb; } /* Keyword.Reserved */
.kt { color: #f0c674; } /* Keyword.Type */
.ld { color: #b5bd68; } /* Literal.Date */
.m { color: #de935f; } /* Literal.Number */
.s { color: #b5bd68; } /* Literal.String */
.na { color: #81a2be; } /* Name.Attribute */
.nb { color: #c5c8c6; } /* Name.Builtin */
.nc { color: #f0c674; } /* Name.Class */
.no { color: #c66; } /* Name.Constant */
.nd { color: #8abeb7; } /* Name.Decorator */
.ni { color: #c5c8c6; } /* Name.Entity */
.ne { color: #c66; } /* Name.Exception */
.nf { color: #81a2be; } /* Name.Function */
.nl { color: #c5c8c6; } /* Name.Label */
.nn { color: #f0c674; } /* Name.Namespace */
.nx { color: #81a2be; } /* Name.Other */
.py { color: #c5c8c6; } /* Name.Property */
.nt { color: #8abeb7; } /* Name.Tag */
.nv { color: #c66; } /* Name.Variable */
.ow { color: #8abeb7; } /* Operator.Word */
.w { color: #c5c8c6; } /* Text.Whitespace */
.mf { color: #de935f; } /* Literal.Number.Float */
.mh { color: #de935f; } /* Literal.Number.Hex */
.mi { color: #de935f; } /* Literal.Number.Integer */
.mo { color: #de935f; } /* Literal.Number.Oct */
.sb { color: #b5bd68; } /* Literal.String.Backtick */
.sc { color: #c5c8c6; } /* Literal.String.Char */
.sd { color: #969896; } /* Literal.String.Doc */
.s2 { color: #b5bd68; } /* Literal.String.Double */
.se { color: #de935f; } /* Literal.String.Escape */
.sh { color: #b5bd68; } /* Literal.String.Heredoc */
.si { color: #de935f; } /* Literal.String.Interpol */
.sx { color: #b5bd68; } /* Literal.String.Other */
.sr { color: #b5bd68; } /* Literal.String.Regex */
.s1 { color: #b5bd68; } /* Literal.String.Single */
.ss { color: #b5bd68; } /* Literal.String.Symbol */
.bp { color: #c5c8c6; } /* Name.Builtin.Pseudo */
.vc { color: #c66; } /* Name.Variable.Class */
.vg { color: #c66; } /* Name.Variable.Global */
.vi { color: #c66; } /* Name.Variable.Instance */
.il { color: #de935f; } /* Literal.Number.Integer.Long */
}
......@@ -55,65 +55,65 @@
color: #000 !important;
}
.hll { background-color: #49483e }
.c { color: #75715e } /* Comment */
.err { color: #960050; background-color: #1e0010 } /* Error */
.k { color: #66d9ef } /* Keyword */
.l { color: #ae81ff } /* Literal */
.n { color: #f8f8f2 } /* Name */
.o { color: #f92672 } /* Operator */
.p { color: #f8f8f2 } /* Punctuation */
.cm { color: #75715e } /* Comment.Multiline */
.cp { color: #75715e } /* Comment.Preproc */
.c1 { color: #75715e } /* Comment.Single */
.cs { color: #75715e } /* Comment.Special */
.ge { font-style: italic } /* Generic.Emph */
.gs { font-weight: bold } /* Generic.Strong */
.kc { color: #66d9ef } /* Keyword.Constant */
.kd { color: #66d9ef } /* Keyword.Declaration */
.kn { color: #f92672 } /* Keyword.Namespace */
.kp { color: #66d9ef } /* Keyword.Pseudo */
.kr { color: #66d9ef } /* Keyword.Reserved */
.kt { color: #66d9ef } /* Keyword.Type */
.ld { color: #e6db74 } /* Literal.Date */
.m { color: #ae81ff } /* Literal.Number */
.s { color: #e6db74 } /* Literal.String */
.na { color: #a6e22e } /* Name.Attribute */
.nb { color: #f8f8f2 } /* Name.Builtin */
.nc { color: #a6e22e } /* Name.Class */
.no { color: #66d9ef } /* Name.Constant */
.nd { color: #a6e22e } /* Name.Decorator */
.ni { color: #f8f8f2 } /* Name.Entity */
.ne { color: #a6e22e } /* Name.Exception */
.nf { color: #a6e22e } /* Name.Function */
.nl { color: #f8f8f2 } /* Name.Label */
.nn { color: #f8f8f2 } /* Name.Namespace */
.nx { color: #a6e22e } /* Name.Other */
.py { color: #f8f8f2 } /* Name.Property */
.nt { color: #f92672 } /* Name.Tag */
.nv { color: #f8f8f2 } /* Name.Variable */
.ow { color: #f92672 } /* Operator.Word */
.w { color: #f8f8f2 } /* Text.Whitespace */
.mf { color: #ae81ff } /* Literal.Number.Float */
.mh { color: #ae81ff } /* Literal.Number.Hex */
.mi { color: #ae81ff } /* Literal.Number.Integer */
.mo { color: #ae81ff } /* Literal.Number.Oct */
.sb { color: #e6db74 } /* Literal.String.Backtick */
.sc { color: #e6db74 } /* Literal.String.Char */
.sd { color: #e6db74 } /* Literal.String.Doc */
.s2 { color: #e6db74 } /* Literal.String.Double */
.se { color: #ae81ff } /* Literal.String.Escape */
.sh { color: #e6db74 } /* Literal.String.Heredoc */
.si { color: #e6db74 } /* Literal.String.Interpol */
.sx { color: #e6db74 } /* Literal.String.Other */
.sr { color: #e6db74 } /* Literal.String.Regex */
.s1 { color: #e6db74 } /* Literal.String.Single */
.ss { color: #e6db74 } /* Literal.String.Symbol */
.bp { color: #f8f8f2 } /* Name.Builtin.Pseudo */
.vc { color: #f8f8f2 } /* Name.Variable.Class */
.vg { color: #f8f8f2 } /* Name.Variable.Global */
.vi { color: #f8f8f2 } /* Name.Variable.Instance */
.il { color: #ae81ff } /* Literal.Number.Integer.Long */
.hll { background-color: #49483e; }
.c { color: #75715e; } /* Comment */
.err { color: #960050; background-color: #1e0010; } /* Error */
.k { color: #66d9ef; } /* Keyword */
.l { color: #ae81ff; } /* Literal */
.n { color: #f8f8f2; } /* Name */
.o { color: #f92672; } /* Operator */
.p { color: #f8f8f2; } /* Punctuation */
.cm { color: #75715e; } /* Comment.Multiline */
.cp { color: #75715e; } /* Comment.Preproc */
.c1 { color: #75715e; } /* Comment.Single */
.cs { color: #75715e; } /* Comment.Special */
.ge { font-style: italic; } /* Generic.Emph */
.gs { font-weight: bold; } /* Generic.Strong */
.kc { color: #66d9ef; } /* Keyword.Constant */
.kd { color: #66d9ef; } /* Keyword.Declaration */
.kn { color: #f92672; } /* Keyword.Namespace */
.kp { color: #66d9ef; } /* Keyword.Pseudo */
.kr { color: #66d9ef; } /* Keyword.Reserved */
.kt { color: #66d9ef; } /* Keyword.Type */
.ld { color: #e6db74; } /* Literal.Date */
.m { color: #ae81ff; } /* Literal.Number */
.s { color: #e6db74; } /* Literal.String */
.na { color: #a6e22e; } /* Name.Attribute */
.nb { color: #f8f8f2; } /* Name.Builtin */
.nc { color: #a6e22e; } /* Name.Class */
.no { color: #66d9ef; } /* Name.Constant */
.nd { color: #a6e22e; } /* Name.Decorator */
.ni { color: #f8f8f2; } /* Name.Entity */
.ne { color: #a6e22e; } /* Name.Exception */
.nf { color: #a6e22e; } /* Name.Function */
.nl { color: #f8f8f2; } /* Name.Label */
.nn { color: #f8f8f2; } /* Name.Namespace */
.nx { color: #a6e22e; } /* Name.Other */
.py { color: #f8f8f2; } /* Name.Property */
.nt { color: #f92672; } /* Name.Tag */
.nv { color: #f8f8f2; } /* Name.Variable */
.ow { color: #f92672; } /* Operator.Word */
.w { color: #f8f8f2; } /* Text.Whitespace */
.mf { color: #ae81ff; } /* Literal.Number.Float */
.mh { color: #ae81ff; } /* Literal.Number.Hex */
.mi { color: #ae81ff; } /* Literal.Number.Integer */
.mo { color: #ae81ff; } /* Literal.Number.Oct */
.sb { color: #e6db74; } /* Literal.String.Backtick */
.sc { color: #e6db74; } /* Literal.String.Char */
.sd { color: #e6db74; } /* Literal.String.Doc */
.s2 { color: #e6db74; } /* Literal.String.Double */
.se { color: #ae81ff; } /* Literal.String.Escape */
.sh { color: #e6db74; } /* Literal.String.Heredoc */
.si { color: #e6db74; } /* Literal.String.Interpol */
.sx { color: #e6db74; } /* Literal.String.Other */
.sr { color: #e6db74; } /* Literal.String.Regex */
.s1 { color: #e6db74; } /* Literal.String.Single */
.ss { color: #e6db74; } /* Literal.String.Symbol */
.bp { color: #f8f8f2; } /* Name.Builtin.Pseudo */
.vc { color: #f8f8f2; } /* Name.Variable.Class */
.vg { color: #f8f8f2; } /* Name.Variable.Global */
.vi { color: #f8f8f2; } /* Name.Variable.Instance */
.il { color: #ae81ff; } /* Literal.Number.Integer.Long */
.gu { color: #75715e; } /* Generic.Subheading & Diff Unified/Comment? */
.gd { color: #f92672; } /* Generic.Deleted & Diff Deleted */
.gi { color: #a6e22e; } /* Generic.Inserted & Diff Inserted */
......
......@@ -72,72 +72,72 @@
green #859900 operators, other keywords
*/
.c { color: #586e75 } /* Comment */
.err { color: #93a1a1 } /* Error */
.g { color: #93a1a1 } /* Generic */
.k { color: #859900 } /* Keyword */
.l { color: #93a1a1 } /* Literal */
.n { color: #93a1a1 } /* Name */
.o { color: #859900 } /* Operator */
.x { color: #cb4b16 } /* Other */
.p { color: #93a1a1 } /* Punctuation */
.cm { color: #586e75 } /* Comment.Multiline */
.cp { color: #859900 } /* Comment.Preproc */
.c1 { color: #586e75 } /* Comment.Single */
.cs { color: #859900 } /* Comment.Special */
.gd { color: #2aa198 } /* Generic.Deleted */
.ge { color: #93a1a1; font-style: italic } /* Generic.Emph */
.gr { color: #dc322f } /* Generic.Error */
.gh { color: #cb4b16 } /* Generic.Heading */
.gi { color: #859900 } /* Generic.Inserted */
.go { color: #93a1a1 } /* Generic.Output */
.gp { color: #93a1a1 } /* Generic.Prompt */
.gs { color: #93a1a1; font-weight: bold } /* Generic.Strong */
.gu { color: #cb4b16 } /* Generic.Subheading */
.gt { color: #93a1a1 } /* Generic.Traceback */
.kc { color: #cb4b16 } /* Keyword.Constant */
.kd { color: #268bd2 } /* Keyword.Declaration */
.kn { color: #859900 } /* Keyword.Namespace */
.kp { color: #859900 } /* Keyword.Pseudo */
.kr { color: #268bd2 } /* Keyword.Reserved */
.kt { color: #dc322f } /* Keyword.Type */
.ld { color: #93a1a1 } /* Literal.Date */
.m { color: #2aa198 } /* Literal.Number */
.s { color: #2aa198 } /* Literal.String */
.na { color: #93a1a1 } /* Name.Attribute */
.nb { color: #b58900 } /* Name.Builtin */
.nc { color: #268bd2 } /* Name.Class */
.no { color: #cb4b16 } /* Name.Constant */
.nd { color: #268bd2 } /* Name.Decorator */
.ni { color: #cb4b16 } /* Name.Entity */
.ne { color: #cb4b16 } /* Name.Exception */
.nf { color: #268bd2 } /* Name.Function */
.nl { color: #93a1a1 } /* Name.Label */
.nn { color: #93a1a1 } /* Name.Namespace */
.nx { color: #93a1a1 } /* Name.Other */
.py { color: #93a1a1 } /* Name.Property */
.nt { color: #268bd2 } /* Name.Tag */
.nv { color: #268bd2 } /* Name.Variable */
.ow { color: #859900 } /* Operator.Word */
.w { color: #93a1a1 } /* Text.Whitespace */
.mf { color: #2aa198 } /* Literal.Number.Float */
.mh { color: #2aa198 } /* Literal.Number.Hex */
.mi { color: #2aa198 } /* Literal.Number.Integer */
.mo { color: #2aa198 } /* Literal.Number.Oct */
.sb { color: #586e75 } /* Literal.String.Backtick */
.sc { color: #2aa198 } /* Literal.String.Char */
.sd { color: #93a1a1 } /* Literal.String.Doc */
.s2 { color: #2aa198 } /* Literal.String.Double */
.se { color: #cb4b16 } /* Literal.String.Escape */
.sh { color: #93a1a1 } /* Literal.String.Heredoc */
.si { color: #2aa198 } /* Literal.String.Interpol */
.sx { color: #2aa198 } /* Literal.String.Other */
.sr { color: #dc322f } /* Literal.String.Regex */
.s1 { color: #2aa198 } /* Literal.String.Single */
.ss { color: #2aa198 } /* Literal.String.Symbol */
.bp { color: #268bd2 } /* Name.Builtin.Pseudo */
.vc { color: #268bd2 } /* Name.Variable.Class */
.vg { color: #268bd2 } /* Name.Variable.Global */
.vi { color: #268bd2 } /* Name.Variable.Instance */
.il { color: #2aa198 } /* Literal.Number.Integer.Long */
.c { color: #586e75; } /* Comment */
.err { color: #93a1a1; } /* Error */
.g { color: #93a1a1; } /* Generic */
.k { color: #859900; } /* Keyword */
.l { color: #93a1a1; } /* Literal */
.n { color: #93a1a1; } /* Name */
.o { color: #859900; } /* Operator */
.x { color: #cb4b16; } /* Other */
.p { color: #93a1a1; } /* Punctuation */
.cm { color: #586e75; } /* Comment.Multiline */
.cp { color: #859900; } /* Comment.Preproc */
.c1 { color: #586e75; } /* Comment.Single */
.cs { color: #859900; } /* Comment.Special */
.gd { color: #2aa198; } /* Generic.Deleted */
.ge { color: #93a1a1; font-style: italic; } /* Generic.Emph */
.gr { color: #dc322f; } /* Generic.Error */
.gh { color: #cb4b16; } /* Generic.Heading */
.gi { color: #859900; } /* Generic.Inserted */
.go { color: #93a1a1; } /* Generic.Output */
.gp { color: #93a1a1; } /* Generic.Prompt */
.gs { color: #93a1a1; font-weight: bold; } /* Generic.Strong */
.gu { color: #cb4b16; } /* Generic.Subheading */
.gt { color: #93a1a1; } /* Generic.Traceback */
.kc { color: #cb4b16; } /* Keyword.Constant */
.kd { color: #268bd2; } /* Keyword.Declaration */
.kn { color: #859900; } /* Keyword.Namespace */
.kp { color: #859900; } /* Keyword.Pseudo */
.kr { color: #268bd2; } /* Keyword.Reserved */
.kt { color: #dc322f; } /* Keyword.Type */
.ld { color: #93a1a1; } /* Literal.Date */
.m { color: #2aa198; } /* Literal.Number */
.s { color: #2aa198; } /* Literal.String */
.na { color: #93a1a1; } /* Name.Attribute */
.nb { color: #b58900; } /* Name.Builtin */
.nc { color: #268bd2; } /* Name.Class */
.no { color: #cb4b16; } /* Name.Constant */
.nd { color: #268bd2; } /* Name.Decorator */
.ni { color: #cb4b16; } /* Name.Entity */
.ne { color: #cb4b16; } /* Name.Exception */
.nf { color: #268bd2; } /* Name.Function */
.nl { color: #93a1a1; } /* Name.Label */
.nn { color: #93a1a1; } /* Name.Namespace */
.nx { color: #93a1a1; } /* Name.Other */
.py { color: #93a1a1; } /* Name.Property */
.nt { color: #268bd2; } /* Name.Tag */
.nv { color: #268bd2; } /* Name.Variable */
.ow { color: #859900; } /* Operator.Word */
.w { color: #93a1a1; } /* Text.Whitespace */
.mf { color: #2aa198; } /* Literal.Number.Float */
.mh { color: #2aa198; } /* Literal.Number.Hex */
.mi { color: #2aa198; } /* Literal.Number.Integer */
.mo { color: #2aa198; } /* Literal.Number.Oct */
.sb { color: #586e75; } /* Literal.String.Backtick */
.sc { color: #2aa198; } /* Literal.String.Char */
.sd { color: #93a1a1; } /* Literal.String.Doc */
.s2 { color: #2aa198; } /* Literal.String.Double */
.se { color: #cb4b16; } /* Literal.String.Escape */
.sh { color: #93a1a1; } /* Literal.String.Heredoc */
.si { color: #2aa198; } /* Literal.String.Interpol */
.sx { color: #2aa198; } /* Literal.String.Other */
.sr { color: #dc322f; } /* Literal.String.Regex */
.s1 { color: #2aa198; } /* Literal.String.Single */
.ss { color: #2aa198; } /* Literal.String.Symbol */
.bp { color: #268bd2; } /* Name.Builtin.Pseudo */
.vc { color: #268bd2; } /* Name.Variable.Class */
.vg { color: #268bd2; } /* Name.Variable.Global */
.vi { color: #268bd2; } /* Name.Variable.Instance */
.il { color: #2aa198; } /* Literal.Number.Integer.Long */
}
......@@ -78,72 +78,72 @@
green #859900 operators, other keywords
*/
.c { color: #93a1a1 } /* Comment */
.err { color: #586e75 } /* Error */
.g { color: #586e75 } /* Generic */
.k { color: #859900 } /* Keyword */
.l { color: #586e75 } /* Literal */
.n { color: #586e75 } /* Name */
.o { color: #859900 } /* Operator */
.x { color: #cb4b16 } /* Other */
.p { color: #586e75 } /* Punctuation */
.cm { color: #93a1a1 } /* Comment.Multiline */
.cp { color: #859900 } /* Comment.Preproc */
.c1 { color: #93a1a1 } /* Comment.Single */
.cs { color: #859900 } /* Comment.Special */
.gd { color: #2aa198 } /* Generic.Deleted */
.ge { color: #586e75; font-style: italic } /* Generic.Emph */
.gr { color: #dc322f } /* Generic.Error */
.gh { color: #cb4b16 } /* Generic.Heading */
.gi { color: #859900 } /* Generic.Inserted */
.go { color: #586e75 } /* Generic.Output */
.gp { color: #586e75 } /* Generic.Prompt */
.gs { color: #586e75; font-weight: bold } /* Generic.Strong */
.gu { color: #cb4b16 } /* Generic.Subheading */
.gt { color: #586e75 } /* Generic.Traceback */
.kc { color: #cb4b16 } /* Keyword.Constant */
.kd { color: #268bd2 } /* Keyword.Declaration */
.kn { color: #859900 } /* Keyword.Namespace */
.kp { color: #859900 } /* Keyword.Pseudo */
.kr { color: #268bd2 } /* Keyword.Reserved */
.kt { color: #dc322f } /* Keyword.Type */
.ld { color: #586e75 } /* Literal.Date */
.m { color: #2aa198 } /* Literal.Number */
.s { color: #2aa198 } /* Literal.String */
.na { color: #586e75 } /* Name.Attribute */
.nb { color: #b58900 } /* Name.Builtin */
.nc { color: #268bd2 } /* Name.Class */
.no { color: #cb4b16 } /* Name.Constant */
.nd { color: #268bd2 } /* Name.Decorator */
.ni { color: #cb4b16 } /* Name.Entity */
.ne { color: #cb4b16 } /* Name.Exception */
.nf { color: #268bd2 } /* Name.Function */
.nl { color: #586e75 } /* Name.Label */
.nn { color: #586e75 } /* Name.Namespace */
.nx { color: #586e75 } /* Name.Other */
.py { color: #586e75 } /* Name.Property */
.nt { color: #268bd2 } /* Name.Tag */
.nv { color: #268bd2 } /* Name.Variable */
.ow { color: #859900 } /* Operator.Word */
.w { color: #586e75 } /* Text.Whitespace */
.mf { color: #2aa198 } /* Literal.Number.Float */
.mh { color: #2aa198 } /* Literal.Number.Hex */
.mi { color: #2aa198 } /* Literal.Number.Integer */
.mo { color: #2aa198 } /* Literal.Number.Oct */
.sb { color: #93a1a1 } /* Literal.String.Backtick */
.sc { color: #2aa198 } /* Literal.String.Char */
.sd { color: #586e75 } /* Literal.String.Doc */
.s2 { color: #2aa198 } /* Literal.String.Double */
.se { color: #cb4b16 } /* Literal.String.Escape */
.sh { color: #586e75 } /* Literal.String.Heredoc */
.si { color: #2aa198 } /* Literal.String.Interpol */
.sx { color: #2aa198 } /* Literal.String.Other */
.sr { color: #dc322f } /* Literal.String.Regex */
.s1 { color: #2aa198 } /* Literal.String.Single */
.ss { color: #2aa198 } /* Literal.String.Symbol */
.bp { color: #268bd2 } /* Name.Builtin.Pseudo */
.vc { color: #268bd2 } /* Name.Variable.Class */
.vg { color: #268bd2 } /* Name.Variable.Global */
.vi { color: #268bd2 } /* Name.Variable.Instance */
.il { color: #2aa198 } /* Literal.Number.Integer.Long */
.c { color: #93a1a1; } /* Comment */
.err { color: #586e75; } /* Error */
.g { color: #586e75; } /* Generic */
.k { color: #859900; } /* Keyword */
.l { color: #586e75; } /* Literal */
.n { color: #586e75; } /* Name */
.o { color: #859900; } /* Operator */
.x { color: #cb4b16; } /* Other */
.p { color: #586e75; } /* Punctuation */
.cm { color: #93a1a1; } /* Comment.Multiline */
.cp { color: #859900; } /* Comment.Preproc */
.c1 { color: #93a1a1; } /* Comment.Single */
.cs { color: #859900; } /* Comment.Special */
.gd { color: #2aa198; } /* Generic.Deleted */
.ge { color: #586e75; font-style: italic; } /* Generic.Emph */
.gr { color: #dc322f; } /* Generic.Error */
.gh { color: #cb4b16; } /* Generic.Heading */
.gi { color: #859900; } /* Generic.Inserted */
.go { color: #586e75; } /* Generic.Output */
.gp { color: #586e75; } /* Generic.Prompt */
.gs { color: #586e75; font-weight: bold; } /* Generic.Strong */
.gu { color: #cb4b16; } /* Generic.Subheading */
.gt { color: #586e75; } /* Generic.Traceback */
.kc { color: #cb4b16; } /* Keyword.Constant */
.kd { color: #268bd2; } /* Keyword.Declaration */
.kn { color: #859900; } /* Keyword.Namespace */
.kp { color: #859900; } /* Keyword.Pseudo */
.kr { color: #268bd2; } /* Keyword.Reserved */
.kt { color: #dc322f; } /* Keyword.Type */
.ld { color: #586e75; } /* Literal.Date */
.m { color: #2aa198; } /* Literal.Number */
.s { color: #2aa198; } /* Literal.String */
.na { color: #586e75; } /* Name.Attribute */
.nb { color: #b58900; } /* Name.Builtin */
.nc { color: #268bd2; } /* Name.Class */
.no { color: #cb4b16; } /* Name.Constant */
.nd { color: #268bd2; } /* Name.Decorator */
.ni { color: #cb4b16; } /* Name.Entity */
.ne { color: #cb4b16; } /* Name.Exception */
.nf { color: #268bd2; } /* Name.Function */
.nl { color: #586e75; } /* Name.Label */
.nn { color: #586e75; } /* Name.Namespace */
.nx { color: #586e75; } /* Name.Other */
.py { color: #586e75; } /* Name.Property */
.nt { color: #268bd2; } /* Name.Tag */
.nv { color: #268bd2; } /* Name.Variable */
.ow { color: #859900; } /* Operator.Word */
.w { color: #586e75; } /* Text.Whitespace */
.mf { color: #2aa198; } /* Literal.Number.Float */
.mh { color: #2aa198; } /* Literal.Number.Hex */
.mi { color: #2aa198; } /* Literal.Number.Integer */
.mo { color: #2aa198; } /* Literal.Number.Oct */
.sb { color: #93a1a1; } /* Literal.String.Backtick */
.sc { color: #2aa198; } /* Literal.String.Char */
.sd { color: #586e75; } /* Literal.String.Doc */
.s2 { color: #2aa198; } /* Literal.String.Double */
.se { color: #cb4b16; } /* Literal.String.Escape */
.sh { color: #586e75; } /* Literal.String.Heredoc */
.si { color: #2aa198; } /* Literal.String.Interpol */
.sx { color: #2aa198; } /* Literal.String.Other */
.sr { color: #dc322f; } /* Literal.String.Regex */
.s1 { color: #2aa198; } /* Literal.String.Single */
.ss { color: #2aa198; } /* Literal.String.Symbol */
.bp { color: #268bd2; } /* Name.Builtin.Pseudo */
.vc { color: #268bd2; } /* Name.Variable.Class */
.vg { color: #268bd2; } /* Name.Variable.Global */
.vi { color: #268bd2; } /* Name.Variable.Instance */
.il { color: #2aa198; } /* Literal.Number.Integer.Long */
}
......@@ -86,7 +86,7 @@
background-color: #fafe3d !important;
}
.hll { background-color: #f8f8f8 }
.hll { background-color: #f8f8f8; }
.c { color: #998; font-style: italic; }
.err { color: #a61717; background-color: #e3d2d2; }
.k { font-weight: bold; }
......
......@@ -78,7 +78,7 @@ span.highlight_word {
background-color: #fafe3d !important;
}
.hll { background-color: #f8f8f8 }
.hll { background-color: #f8f8f8; }
.c { color: #998; font-style: italic; }
.err { color: #a61717; background-color: #e3d2d2; }
.k { font-weight: bold; }
......
......@@ -2,22 +2,28 @@ img {
max-width: 100%;
height: auto;
}
p.details {
font-style: italic;
color: #777
color: #777;
}
.footer > p {
font-size: small;
color: #777
color: #777;
}
pre.commit-message {
white-space: pre-wrap;
}
.file-stats > a {
text-decoration: none;
> .new-file {
color: #090;
}
> .deleted-file {
color: #b00;
}
......
......@@ -22,7 +22,7 @@
.admin-filter form {
.select2-container {
width: 100%
width: 100%;
}
.controls {
......@@ -31,7 +31,7 @@
.form-actions {
padding-left: 130px;
background: #fff
background: #fff;
}
.visibility-levels {
......@@ -106,26 +106,33 @@
.table {
table-layout: fixed;
}
.subheading {
padding-bottom: $gl-padding;
}
.message {
word-wrap: break-word;
}
.btn {
white-space: normal;
padding: $gl-btn-padding;
}
th {
width: 15%;
&.wide {
width: 55%;
}
}
@media (max-width: $screen-sm-max) {
th {
width: 100%;
}
td {
width: 100%;
float: left;
......@@ -137,6 +144,7 @@
margin-left: $btn-side-margin;
margin-top: 3px;
}
span {
font-size: 19px;
}
......
......@@ -137,6 +137,7 @@
.retry-link {
color: $gl-link-color;
&:hover {
text-decoration: underline;
}
......@@ -218,6 +219,7 @@
.build-detail-row {
margin-bottom: 5px;
&:last-of-type {
margin-bottom: 0;
}
......@@ -233,3 +235,9 @@
right: 0;
margin-top: -17px;
}
@media (min-width: $screen-md-min) {
.sub-nav.build {
width: calc(100% + #{$gutter_width});
}
}
......@@ -51,6 +51,7 @@
margin-left: 4px;
}
}
.commit-committer-link,
.commit-author-link {
color: $gl-gray;
......@@ -108,21 +109,25 @@
line-height: 20px;
}
}
.new-file {
a {
color: $gl-text-green;
}
}
.renamed-file {
a {
color: $gl-text-orange;
}
}
.deleted-file {
a {
color: $gl-text-red;
}
}
.edit-file {
a {
color: $gl-text-color;
......@@ -158,6 +163,7 @@
position: absolute;
z-index: 1;
}
> textarea {
background-color: rgba(0, 0, 0, 0.0);
font-family: inherit;
......
......@@ -161,6 +161,7 @@
.branch-commit {
color: $gl-gray;
.commit-id, .commit-row-message {
color: $gl-gray;
}
......
......@@ -5,6 +5,7 @@
background: $background-color;
border-top-left-radius: 0;
}
border-top-left-radius: 0;
}
}
......@@ -17,6 +18,7 @@
float: left;
@extend .col-md-2;
}
.btn {
margin-left: 5px;
float: left;
......
......@@ -33,6 +33,19 @@
font-size: smaller;
}
}
.file-title {
cursor: pointer;
&:hover {
background-color: $dark-background-color;
}
.diff-toggle-caret {
padding-right: 6px;
}
}
.diff-content {
overflow: auto;
overflow-y: hidden;
......@@ -123,15 +136,18 @@
max-width: 50px;
width: 35px;
@include user-select(none);
a {
float: left;
width: 35px;
font-weight: normal;
&:hover {
text-decoration: underline;
}
}
}
.line_content {
display: block;
margin: 0;
......@@ -151,10 +167,12 @@
white-space: pre-wrap;
}
}
.image {
background: #ddd;
text-align: center;
padding: 30px;
.wrap {
display: inline-block;
}
......@@ -163,6 +181,7 @@
display: inline-block;
background-color: #fff;
line-height: 0;
img {
border: 1px solid #fff;
background-image: linear-gradient(45deg, #e5e5e5 25%, transparent 25%, transparent 75%, #e5e5e5 75%, #e5e5e5 100%),
......@@ -171,6 +190,7 @@
background-position: 0 0, 5px 5px;
max-width: 100%;
}
&.deleted {
border: 1px solid $deleted;
}
......@@ -179,6 +199,7 @@
border: 1px solid $added;
}
}
.image-info {
font-size: 12px;
margin: 5px 0 0;
......@@ -193,6 +214,7 @@
margin: auto;
position: relative;
}
.swipe-wrap {
overflow: hidden;
border-left: 1px solid #999;
......@@ -201,10 +223,12 @@
top: 13px;
right: 7px;
}
.frame {
top: 0;
right: 0;
position: absolute;
&.deleted {
margin: 0;
display: block;
......@@ -212,6 +236,7 @@
right: 7px;
}
}
.swipe-bar {
display: block;
height: 100%;
......@@ -219,14 +244,17 @@
z-index: 100;
position: absolute;
cursor: pointer;
&:hover {
.top-handle {
background-position: -15px 3px;
}
.bottom-handle {
background-position: -15px -11px;
}
}
.top-handle {
display: block;
height: 14px;
......@@ -235,6 +263,7 @@
top: 0;
background: image-url('swipemode_sprites.gif') 0 3px no-repeat;
}
.bottom-handle {
display: block;
height: 14px;
......@@ -252,12 +281,14 @@
margin: auto;
position: relative;
}
.frame.added, .frame.deleted {
position: absolute;
display: block;
top: 0;
left: 0;
}
.controls {
display: block;
height: 14px;
......@@ -311,6 +342,7 @@
}
//.view.onion-skin
}
.view-modes {
padding: 10px;
text-align: center;
......@@ -328,19 +360,24 @@
border-left: 1px solid #c1c1c1;
padding: 0 12px 0 16px;
cursor: pointer;
&:first-child {
border-left: none;
}
&:hover {
text-decoration: underline;
}
&.active {
&:hover {
text-decoration: none;
}
cursor: default;
color: #333;
}
&.disabled {
display: none;
}
......
......@@ -15,6 +15,7 @@
.cancel-btn {
color: #b94a48;
&:hover {
color: #b94a48;
}
......@@ -70,16 +71,20 @@
.soft-wrap-toggle {
margin: 0 $btn-side-margin;
.soft-wrap {
display: block;
}
.no-wrap {
display: none;
}
&.soft-wrap-active {
.soft-wrap {
display: none;
}
.no-wrap {
display: block;
}
......
......@@ -52,13 +52,13 @@
}
}
.table.builds.environments {
.table.ci-table.environments {
.icon-container {
width: 20px;
text-align: center;
}
.branch-commit {
.commit-id {
margin-right: 0;
......
......@@ -78,6 +78,7 @@
margin-bottom: 0;
}
}
.event-note-icon {
color: #777;
float: left;
......@@ -86,6 +87,7 @@
margin-right: 5px;
}
}
.event_icon {
position: relative;
float: right;
......@@ -95,12 +97,13 @@
background: $gray-light;
margin-left: 10px;
top: -6px;
img {
width: 20px;
}
}
&:last-child { border: none }
&:last-child { border: none; }
.event_commits {
li {
......@@ -109,6 +112,7 @@
padding: 3px;
padding-left: 0;
border: none;
.commit-row-title {
font-size: $gl-font-size;
}
......@@ -117,6 +121,7 @@
&.commits-stat {
display: block;
padding: 0 3px 0 0;
&:hover {
background: none;
}
......@@ -158,6 +163,7 @@
overflow: visible;
max-width: 100%;
}
.avatar {
display: none;
}
......
.member-search-form {
float: left;
input[type='search'] {
width: 225px;
vertical-align: bottom;
@media (max-width: $screen-xs-max) {
width: 100px;
vertical-align: bottom;
}
}
}
.milestone-row {
@include str-truncated(90%);
}
......@@ -48,6 +34,7 @@
.group-right-buttons {
position: absolute;
right: 16px;
.btn {
@include btn-gray;
padding: 3px 10px;
......
......@@ -23,28 +23,28 @@
color: #555;
tbody:first-child tr:first-child {
padding-top: 0
padding-top: 0;
}
th {
padding-top: 15px;
line-height: 1.5;
color: #333;
text-align: left
text-align: left;
}
td {
padding-top: 3px;
padding-bottom: 3px;
vertical-align: top;
line-height: 20px
line-height: 20px;
}
.shortcut {
padding-right: 10px;
color: #999;
text-align: right;
white-space: nowrap
white-space: nowrap;
}
.key {
......
......@@ -27,6 +27,7 @@
margin-right: 5px;
margin-bottom: 5px;
display: inline-block;
.color-label {
padding: 6px 10px;
}
......@@ -128,7 +129,7 @@
}
.selectbox {
display: none
display: none;
}
.btn-clipboard {
......@@ -199,7 +200,7 @@
display: none;
/* Small devices (tablets, 768px and up) */
@media (min-width: $screen-sm-min) {
display: block
display: block;
}
width: $sidebar_collapsed_width;
......@@ -276,7 +277,7 @@
}
&.btn-primary {
@extend .btn-primary
@extend .btn-primary;
}
}
......@@ -400,6 +401,7 @@
.js-issuable-selector {
width: 100%;
}
@media (max-width: $screen-sm-max) {
margin-bottom: $gl-padding;
}
......
......@@ -37,6 +37,7 @@ ul.related-merge-requests > li {
display: -ms-flexbox;
display: -webkit-flex;
display: flex;
.merge-request-id {
flex-shrink: 0;
}
......
.suggest-colors {
margin-top: 5px;
a {
border-radius: 4px;
width: 30px;
......
......@@ -3,6 +3,7 @@
font-size: 19px;
color: red;
}
.correct-syntax {
font-size: 19px;
color: #47a447;
......
......@@ -17,6 +17,7 @@
line-height: 1.5;
p {
font-size: 18px;
color: #888;
}
......@@ -36,10 +37,14 @@
}
}
.login-box {
background: #fafafa;
border-radius: 10px;
box-shadow: 0 0 2px #ccc;
p {
font-size: 13px;
}
.login-box, .omniauth-container {
box-shadow: 0 0 0 1px $border-color;
border-bottom-right-radius: 2px;
border-bottom-left-radius: 2px;
padding: 15px;
.login-heading h3 {
......@@ -58,42 +63,127 @@
a.forgot {
float: right;
padding-top: 6px
padding-top: 6px;
}
.nav .active a {
background: transparent;
}
}
.form-control {
font-size: 14px;
padding: 10px 8px;
width: 100%;
height: auto;
&.top {
border-radius: 5px 5px 0 0;
margin-bottom: 0;
// Styles the glowing border of focused input for username async validation
.login-body {
font-size: 13px;
input + p {
margin-top: 5px;
}
.gl-field-success-outline {
border: 1px solid $green-normal;
&:focus {
box-shadow: 0 0 0 1px $green-normal inset, 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 4px 0 $green-normal;
border: 0 none;
}
}
.gl-field-error-outline {
border: 1px solid $red-normal;
&:focus {
box-shadow: 0 0 0 1px $red-normal inset, 0 1px 1px rgba(0, 0, 0, 0.075) inset, 0 0 4px 0 rgba(210, 40, 82, 0.6);
border: 0 none;
}
}
.username .validation-success,
.gl-field-success-message {
color: $green-normal;
}
.username .validation-error,
.gl-field-error-message {
color: $red-normal;
}
.gl-field-hint {
color: $gl-text-color;
}
}
}
&.bottom {
border-radius: 0 0 5px 5px;
border-top: 0;
margin-bottom: 20px;
.omniauth-container {
p {
margin: 0;
}
}
.new-session-tabs {
display: -webkit-flex;
display: flex;
box-shadow: 0 0 0 1px $border-color;
border-top-right-radius: 2px;
border-top-left-radius: 2px;
li {
flex: 1;
text-align: center;
&:last-of-type {
border-left: 1px solid $border-color;
}
&:not(.active) {
background-color: $gray-light;
}
a {
width: 100%;
font-size: 18px;
&.middle {
border-top: 0;
margin-bottom: 0;
border-radius: 0;
&:hover {
border: 1px solid transparent;
}
}
&.active {
border-bottom: 1px solid $border-color;
a {
border: none;
border-bottom: 2px solid $link-underline-blue;
color: $black;
&:hover {
border-bottom: 2px solid $link-underline-blue;
}
}
}
}
}
.form-control {
&:active, &:focus {
background-color: #fff;
}
}
label {
font-weight: normal;
}
.submit-container {
margin-top: 16px;
}
input[type="submit"] {
@extend .btn-block;
margin-bottom: 0;
}
.devise-errors {
h2 {
margin-top: 0;
......@@ -101,14 +191,6 @@
color: #a00;
}
}
.remember-me {
margin-top: -10px;
label {
font-weight: normal;
}
}
}
@media (max-width: $screen-xs-max) {
......@@ -127,3 +209,35 @@
height: 32px;
}
}
.devise-layout-html {
margin: 0;
padding: 0;
height: 100%;
}
// Fixes footer container to bottom of viewport
.devise-layout-html body {
// offset height of fixed header + 1 to avoid scroll
height: calc(100% - 51px);
margin: 0;
padding: 0;
.page-wrap {
min-height: 100%;
position: relative;
}
.footer-container, hr.footer-fixed {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 40px;
background: $white-light;
}
.navless-container {
padding: 65px; // height of footer + bottom padding of email confirmation link
}
}
.project-members-title {
padding-bottom: 10px;
border-bottom: 1px solid $border-color;
}
.member {
.list-item-name {
@media (min-width: $screen-sm-min) {
float: left;
width: 50%;
}
strong {
font-weight: 600;
}
}
.controls {
@media (min-width: $screen-sm-min) {
display: -webkit-flex;
display: flex;
width: 400px;
max-width: 50%;
}
}
.form-horizontal {
margin-top: 5px;
@media (min-width: $screen-sm-min) {
display: -webkit-flex;
display: flex;
width: 100%;
margin-top: 3px;
}
}
.btn-remove {
width: 100%;
@media (min-width: $screen-sm-min) {
width: auto;
}
}
}
.member-form-control {
@media (max-width: $screen-xs-max) {
padding: 5px 0;
margin-left: 0;
margin-right: 0;
}
@media (min-width: $screen-sm-min) {
width: 50%;
}
}
.member-access-text {
margin-left: auto;
line-height: 43px;
}
.member.existing-title {
@media (min-width: $screen-sm-min) {
float: left;
}
}
.member-search-form {
position: relative;
@media (min-width: $screen-sm-min) {
float: right;
}
.form-control {
width: 100%;
padding-right: 35px;
@media (min-width: $screen-sm-min) {
width: 350px;
}
}
}
.member-search-btn {
position: absolute;
right: 0;
top: 0;
height: 35px;
padding-left: 10px;
padding-right: 10px;
color: $gray-darkest;
background: transparent;
border: 0;
outline: 0;
}
......@@ -131,6 +131,7 @@ $colors: (
}
}
}
&.head {
background-color: map-get($colors, #{$color}_header_head_neutral);
border-color: map-get($colors, #{$color}_header_head_neutral);
......@@ -174,6 +175,7 @@ $colors: (
background-color: map-get($colors, #{$color}_line_not_chosen);
}
}
&.head {
background-color: map-get($colors, #{$color}_line_head_neutral);
......
......@@ -10,6 +10,7 @@
form {
margin-bottom: 0;
.clearfix {
margin-bottom: 0;
}
......@@ -46,6 +47,7 @@
&.right {
float: right;
a {
color: $gl-gray;
}
......@@ -121,6 +123,10 @@
color: #5c5d5e;
}
.js-deployment-link {
display: inline-block;
}
.mr-widget-body {
h4 {
font-weight: 600;
......@@ -188,6 +194,7 @@
padding-top: 2px;
padding-bottom: 2px;
list-style: none;
&:hover {
background: none;
}
......@@ -211,6 +218,7 @@
padding-top: 20px;
padding-bottom: 10px;
}
svg {
width: 230px;
}
......@@ -276,12 +284,6 @@
line-height: 31px;
}
.builds {
.table-holder {
overflow-x: auto;
}
}
.panel-new-merge-request {
.panel-heading {
padding: 5px 10px;
......@@ -369,7 +371,7 @@
}
.table-holder {
.builds {
.ci-table {
th {
background-color: $white-light;
......@@ -433,3 +435,12 @@
margin-bottom: 20px;
}
}
.merge-request-tabs {
background-color: #fff;
&.affix {
top: 100px;
z-index: 9;
}
}
......@@ -59,6 +59,7 @@
color: $gl-placeholder-color;
margin-right: 5px;
}
.avatar {
float: none;
}
......
......@@ -11,6 +11,7 @@
filter: alpha(opacity=100);
}
}
.diff-file,
.discussion {
.new-note {
......@@ -194,6 +195,7 @@
min-height: 140px;
max-height: 500px;
}
.note-form-actions {
background: transparent;
}
......
......@@ -147,9 +147,18 @@ ul.notes {
// Diff code in discussion view
.discussion-body .diff-file {
.file-title {
cursor: default;
&:hover {
background-color: $gray-light;
}
}
.diff-header > span {
margin-right: 10px;
}
.line_content {
white-space: pre-wrap;
}
......@@ -345,6 +354,7 @@ ul.notes {
width: 32px;
// "hide" it by default
display: none;
&:hover {
background: $gl-info;
color: #fff;
......
......@@ -20,7 +20,7 @@
margin: 4px;
}
.table.builds {
.table.ci-table {
min-width: 1200px;
.branch-commit {
......@@ -44,13 +44,20 @@
overflow: auto;
}
.table.builds {
.table.ci-table {
min-width: 900px;
&.pipeline {
min-width: 650px;
}
&.builds-page {
tr {
height: 71px;
}
}
tr {
th {
padding: 16px 8px;
......@@ -176,7 +183,7 @@
&::after {
content: '';
width: 8px;
position: absolute;;
position: absolute;
right: -7px;
bottom: 8px;
border-bottom: 2px solid $border-color;
......@@ -353,6 +360,7 @@
&:hover {
background-color: $gray-lighter;
.dropdown-menu-toggle {
background-color: transparent;
}
......@@ -536,6 +544,7 @@
height: 29px;
top: -9px;
}
.curve {
display: block;
}
......@@ -621,19 +630,31 @@
}
}
.pipelines.tab-pane {
.tab-pane {
.content-list.pipelines {
overflow: auto;
}
&.pipelines {
.stage {
max-width: 100px;
width: 100px;
.content-list.pipelines {
overflow: auto;
}
.stage {
max-width: 100px;
width: 100px;
}
.pipeline-actions {
min-width: initial;
}
}
.pipeline-actions {
min-width: initial;
&.builds {
.ci-table {
tr {
height: 71px;
}
}
}
}
......
......@@ -243,6 +243,7 @@
.btn {
-webkit-flex-grow: 1;
flex-grow: 1;
&:first-child {
margin-left: 0;
}
......
......@@ -17,34 +17,43 @@
&.features .control-label {
font-weight: normal;
}
.form-group {
margin-bottom: 5px;
}
&> .form-group {
padding-left: 0;
}
}
.help-block {
margin-bottom: 10px;
}
.project-path {
padding-right: 0;
.form-control {
border-radius: $border-radius-base;
}
}
.input-group > div {
&:last-child {
padding-right: 0;
}
}
@media (max-width: $screen-xs-max) {
.input-group > div {
margin-bottom: 14px;
&:last-child {
margin-bottom: 0;
}
}
fieldset > .form-group:first-child {
padding-right: 0;
}
......@@ -56,6 +65,7 @@
border-radius: 3px;
border: 1px solid #e5e5e5;
}
&+ .select2 a {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
......@@ -201,6 +211,7 @@
pointer-events: none;
}
}
.count {
@include btn-gray;
display: inline-block;
......@@ -361,10 +372,12 @@ a.deploy-project-label {
margin: $gl-padding;
text-align: center;
width: 169px;
&:hover, &.forked {
background-color: $row-hover;
border-color: $row-hover-border;
}
.no-avatar {
width: 100px;
height: 100px;
......@@ -372,17 +385,20 @@ a.deploy-project-label {
border: 1px solid $gray-dark;
margin: 0 auto;
border-radius: 50%;
i {
font-size: 100px;
color: $gray-dark;
}
}
a {
display: block;
width: 100%;
height: 100%;
padding-top: $gl-padding;
color: $gl-gray;
.caption {
min-height: 30px;
padding: $gl-padding 0;
......@@ -644,6 +660,7 @@ pre.light-well {
.clone-options {
display: table-cell;
a.btn {
width: 100%;
}
......@@ -832,6 +849,7 @@ pre.light-well {
.form-control {
min-width: 100px;
}
.select2-choice {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
......
......@@ -6,6 +6,7 @@
&.runner-state-shared {
background: #32b186;
}
&.runner-state-specific {
background: #3498db;
}
......
......@@ -65,6 +65,7 @@
.ci-status-icon-success {
color: $gl-success;
}
.ci-status-icon-failed {
color: $gl-danger;
}
......@@ -77,6 +78,7 @@
.ci-status-icon-running {
color: $blue-normal;
}
.ci-status-icon-canceled,
.ci-status-icon-disabled,
.ci-status-icon-not-found,
......
......@@ -5,6 +5,7 @@
.file-finder {
width: 50%;
.file-finder-input {
width: 95%;
display: inline-block;
......
This diff is collapsed.
......@@ -45,6 +45,10 @@ class ApplicationController < ActionController::Base
redirect_to request.referer.present? ? :back : default, options
end
def not_found
render_404
end
protected
# This filter handles both private tokens and personal access tokens
......
class Projects::GroupLinksController < Projects::ApplicationController
layout 'project_settings'
before_action :authorize_admin_project!
before_action :authorize_admin_project_member!, only: [:update]
def index
@group_links = project.project_group_links.all
......@@ -27,9 +28,26 @@ class Projects::GroupLinksController < Projects::ApplicationController
redirect_to namespace_project_group_links_path(project.namespace, project)
end
def update
@group_link = @project.project_group_links.find(params[:id])
@group_link.update_attributes(group_link_params)
end
def destroy
project.project_group_links.find(params[:id]).destroy
redirect_to namespace_project_group_links_path(project.namespace, project)
respond_to do |format|
format.html do
redirect_to namespace_project_group_links_path(project.namespace, project)
end
format.js { head :ok }
end
end
protected
def group_link_params
params.require(:group_link).permit(:group_access, :expires_at)
end
end
......@@ -10,7 +10,7 @@ class Projects::MergeRequestsController < Projects::ApplicationController
before_action :module_enabled
before_action :merge_request, only: [
:edit, :update, :show, :diffs, :commits, :conflicts, :builds, :pipelines, :merge, :merge_check,
:ci_status, :toggle_subscription, :cancel_merge_when_build_succeeds, :remove_wip, :resolve_conflicts, :assign_related_issues
:ci_status, :ci_environments_status, :toggle_subscription, :cancel_merge_when_build_succeeds, :remove_wip, :resolve_conflicts, :assign_related_issues
]
before_action :validates_merge_request, only: [:show, :diffs, :commits, :builds, :pipelines]
before_action :define_show_vars, only: [:show, :diffs, :commits, :conflicts, :builds, :pipelines]
......@@ -403,6 +403,30 @@ class Projects::MergeRequestsController < Projects::ApplicationController
render json: response
end
def ci_environments_status
environments =
begin
@merge_request.environments.map do |environment|
next unless can?(current_user, :read_environment, environment)
project = environment.project
deployment = environment.first_deployment_for(@merge_request.diff_head_commit)
{
id: environment.id,
name: environment.name,
url: namespace_project_environment_path(project.namespace, project, environment),
external_url: environment.external_url,
external_url_formatted: environment.formatted_external_url,
deployed_at: deployment.try(:created_at),
deployed_at_formatted: deployment.try(:formatted_deployment_time)
}
end.compact
end
render json: environments
end
protected
def selected_target_project
......
......@@ -5,34 +5,23 @@ class Projects::ProjectMembersController < Projects::ApplicationController
before_action :authorize_admin_project_member!, except: [:index, :leave, :request_access]
def index
@group_links = @project.project_group_links
@project_members = @project.project_members
@project_members = @project_members.non_invite unless can?(current_user, :admin_project, @project)
if params[:search].present?
users = @project.users.search(params[:search]).to_a
@project_members = @project_members.where(user_id: users)
end
@project_members = @project_members.order('access_level DESC')
@group = @project.group
if @group
@group_members = @group.group_members
@group_members = @group_members.non_invite unless can?(current_user, :admin_group, @group)
if params[:search].present?
users = @group.users.search(params[:search]).to_a
@group_members = @group_members.where(user_id: users)
end
@group_members = @group_members.order('access_level DESC')
@group_links = @project.project_group_links.where(group_id: @project.invited_groups.search(params[:search]).select(:id))
end
@project_members = @project_members.order(access_level: :desc).page(params[:page])
@requesters = AccessRequestsFinder.new(@project).execute(current_user)
@project_member = @project.project_members.new
@project_group_links = @project.project_group_links
end
def create
......@@ -43,6 +32,21 @@ class Projects::ProjectMembersController < Projects::ApplicationController
current_user: current_user
)
if params[:group_ids].present?
group_ids = params[:group_ids].split(',')
groups = Group.where(id: group_ids)
groups.each do |group|
next unless can?(current_user, :read_group, group)
project.project_group_links.create(
group: group,
group_access: params[:access_level],
expires_at: params[:expires_at]
)
end
end
redirect_to namespace_project_project_members_path(@project.namespace, @project)
end
......
class UsersController < ApplicationController
skip_before_action :authenticate_user!
before_action :user
before_action :user, except: [:exists]
before_action :authorize_read_user!, only: [:show]
def show
......@@ -85,6 +85,10 @@ class UsersController < ApplicationController
render 'calendar_activities', layout: false
end
def exists
render json: { exists: Namespace.where(path: params[:username].downcase).any? }
end
private
def authorize_read_user!
......
module Ci
class Build < CommitStatus
include TokenAuthenticatable
include AfterCommitQueue
belongs_to :runner, class_name: 'Ci::Runner'
belongs_to :trigger_request, class_name: 'Ci::TriggerRequest'
......@@ -75,25 +76,20 @@ module Ci
state_machine :status do
after_transition pending: :running do |build|
build.execute_hooks
build.run_after_commit do
BuildHooksWorker.perform_async(id)
end
end
after_transition any => [:success, :failed, :canceled] do |build|
build.update_coverage
build.execute_hooks
build.run_after_commit do
BuildFinishedWorker.perform_async(id)
end
end
after_transition any => [:success] do |build|
if build.environment.present?
service = CreateDeploymentService.new(
build.project, build.user,
environment: build.environment,
sha: build.sha,
ref: build.ref,
tag: build.tag,
options: build.options.to_h[:environment],
variables: build.variables)
service.execute(build)
build.run_after_commit do
BuildSuccessWorker.perform_async(id)
end
end
end
......
......@@ -76,7 +76,11 @@ module Ci
end
after_transition do |pipeline, transition|
pipeline.execute_hooks unless transition.loopback?
next if transition.loopback?
pipeline.run_after_commit do
PipelineHooksWorker.perform_async(id)
end
end
end
......
......@@ -84,6 +84,10 @@ class Deployment < ActiveRecord::Base
take
end
def formatted_deployment_time
created_at.to_time.in_time_zone.to_s(:medium)
end
private
def ref_path
......
......@@ -48,7 +48,22 @@ class Environment < ActiveRecord::Base
self.name == "production"
end
def first_deployment_for(commit)
ref = project.repository.ref_name_for_sha(ref_path, commit.sha)
return nil unless ref
deployment_id = ref.split('/').last
deployments.find(deployment_id)
end
def ref_path
"refs/environments/#{Shellwords.shellescape(name)}"
end
def formatted_external_url
return nil unless external_url
external_url.gsub(/\A.*?:\/\//, '')
end
end
......@@ -688,12 +688,15 @@ class MergeRequest < ActiveRecord::Base
def environments
return [] unless diff_head_commit
environments = source_project.environments_for(
source_branch, diff_head_commit)
environments += target_project.environments_for(
target_branch, diff_head_commit, with_tags: true)
environments.uniq
@environments ||=
begin
environments = source_project.environments_for(
source_branch, diff_head_commit)
environments += target_project.environments_for(
target_branch, diff_head_commit, with_tags: true)
environments.uniq
end
end
def state_human_name
......
......@@ -490,7 +490,7 @@ class Project < ActiveRecord::Base
end
def import_url
if import_data && super
if import_data && super.present?
import_url = Gitlab::UrlSanitizer.new(super, credentials: import_data.credentials)
import_url.full_url
else
......@@ -829,11 +829,6 @@ class Project < ActiveRecord::Base
end
end
def update_merge_requests(oldrev, newrev, ref, user)
MergeRequests::RefreshService.new(self, user).
execute(oldrev, newrev, ref)
end
def valid_repo?
repository.exists?
rescue
......
......@@ -719,6 +719,14 @@ class Repository
end
end
def ref_name_for_sha(ref_path, sha)
args = %W(#{Gitlab.config.git.bin_path} for-each-ref --count=1 #{ref_path} --contains #{sha})
# Not found -> ["", 0]
# Found -> ["b8d95eb4969eefacb0a58f6a28f6803f8070e7b9 commit\trefs/environments/production/77\n", 0]
Gitlab::Popen.popen(args, path_to_repo).first.split.last
end
def refs_contains_sha(ref_type, sha)
args = %W(#{Gitlab.config.git.bin_path} #{ref_type} --contains #{sha})
names = Gitlab::Popen.popen(args, path_to_repo).first
......
......@@ -2,25 +2,35 @@ require_relative 'base_service'
class CreateDeploymentService < BaseService
def execute(deployable = nil)
environment = find_or_create_environment
return unless executable?
deployment = project.deployments.create(
environment: environment,
ActiveRecord::Base.transaction do
@deployable = deployable
@environment = prepare_environment
deploy.tap do |deployment|
deployment.update_merge_request_metrics!
end
end
end
private
def executable?
project && name.present?
end
def deploy
project.deployments.create(
environment: @environment,
ref: params[:ref],
tag: params[:tag],
sha: params[:sha],
user: current_user,
deployable: deployable
)
deployment.update_merge_request_metrics!
deployment
deployable: @deployable)
end
private
def find_or_create_environment
def prepare_environment
project.environments.find_or_create_by(name: expanded_name) do |environment|
environment.external_url = expanded_url
end
......
......@@ -63,13 +63,12 @@ class GitPushService < BaseService
protected
def update_merge_requests
@project.update_merge_requests(params[:oldrev], params[:newrev], params[:ref], current_user)
UpdateMergeRequestsWorker.perform_async(@project.id, current_user.id, params[:oldrev], params[:newrev], params[:ref])
EventCreateService.new.push(@project, current_user, build_push_data)
SystemHooksService.new.execute_hooks(build_push_data_system_hook.dup, :push_hooks)
@project.execute_hooks(build_push_data.dup, :push_hooks)
@project.execute_services(build_push_data.dup, :push_hooks)
Ci::CreatePipelineService.new(project, current_user, build_push_data).execute
Ci::CreatePipelineService.new(@project, current_user, build_push_data).execute
ProjectCacheWorker.perform_async(@project.id)
end
......@@ -148,16 +147,6 @@ class GitPushService < BaseService
push_commits)
end
def build_push_data_system_hook
@push_data_system ||= Gitlab::DataBuilder::Push.build(
@project,
current_user,
params[:oldrev],
params[:newrev],
params[:ref],
[])
end
def push_to_existing_branch?
# Return if this is not a push to a branch (e.g. new commits)
Gitlab::Git.branch_ref?(params[:ref]) && !Gitlab::Git.blank_ref?(params[:oldrev])
......
- page_title "Preview | Appearance"
= render 'devise/shared/tab_single', tab_title: 'Sign in preview'
.login-box
.login-heading
%h3 Existing user? Sign in
%form
= text_field_tag :login, nil, class: "form-control top", placeholder: "Username or Email"
= password_field_tag :password, nil, class: "form-control bottom", placeholder: "Password"
= button_tag "Sign in", class: "btn-create btn"
%form.show-gl-field-errors
.form-group
= label_tag :login
= text_field_tag :login, nil, class: "form-control top", title: 'Please provide your username or email address.'
.form-group
= label_tag :password
= password_field_tag :password, nil, class: "form-control bottom", title: 'This field is required.'
.form-group
= button_tag "Sign in", class: "btn-create btn"
......@@ -71,7 +71,7 @@
.col-md-6
%h4 Recent builds served by this Runner
%table.table.builds.runner-builds
%table.table.ci-table.runner-builds
%thead
%tr
%th Build
......
= render 'devise/shared/tab_single', tab_title: 'Resend confirmation instructions'
.login-box
.login-heading
%h3 Resend confirmation instructions
.login-body
= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f|
= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post, class: 'show-gl-field-errors' }) do |f|
.devise-errors
= devise_error_messages!
.clearfix.append-bottom-20
= f.email_field :email, placeholder: 'Email', class: "form-control", required: true
.form-group
= f.label :email
= f.email_field :email, class: "form-control", required: true, title: 'Please provide a valid email address.'
.clearfix
= f.submit "Resend confirmation instructions", class: 'btn btn-success'
= f.submit "Resend", class: 'btn btn-success'
.clearfix.prepend-top-20
= render 'devise/shared/sign_in_link'
= render 'devise/shared/tab_single', tab_title:'Change your password'
.login-box
.login-heading
%h3 Change your password
.login-body
= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f|
= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put, class: 'show-gl-field-errors' }) do |f|
.devise-errors
= devise_error_messages!
= f.hidden_field :reset_password_token
%div
= f.password_field :password, class: "form-control top", placeholder: "New password", required: true
%div
= f.password_field :password_confirmation, class: "form-control bottom", placeholder: "Confirm new password", required: true
.form-group
= f.label 'New password', for: :password
= f.password_field :password, class: "form-control top", required: true, title: 'This field is required'
.form-group
= f.label 'Confirm new password', for: :password_confirmation
= f.password_field :password_confirmation, class: "form-control bottom", title: 'This field is required', required: true
.clearfix
= f.submit "Change your password", class: "btn btn-primary"
.clearfix.prepend-top-20
%p
= link_to "Didn't receive confirmation instructions?", new_confirmation_path(resource_name)
= render 'devise/shared/sign_in_link'
%span.light Didn't receive a confirmation email?
= link_to "Request a new one", new_confirmation_path(resource_name)
= render 'devise/shared/sign_in_link'
= render 'devise/shared/tab_single', tab_title: 'Reset Password'
.login-box
.login-heading
%h3 Reset password
.login-body
= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f|
= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post, class: 'show-gl-field-errors' }) do |f|
.devise-errors
= devise_error_messages!
.clearfix.append-bottom-20
= f.email_field :email, placeholder: "Email", class: "form-control", required: true, value: params[:user_email], autofocus: true
.form-group
= f.label :email
= f.email_field :email, class: "form-control", required: true, value: params[:user_email], autofocus: true, title: 'Please provide a valid email address.'
.clearfix
= f.submit "Reset password", class: "btn-primary btn"
......
= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f|
= f.text_field :login, class: "form-control top", placeholder: "Username or Email", autofocus: "autofocus", autocapitalize: "off", autocorrect: "off"
= f.password_field :password, class: "form-control bottom", placeholder: "Password"
= form_for(resource, as: resource_name, url: session_path(resource_name), html: { class: 'new_user show-gl-field-errors', 'aria-live' => 'assertive'}) do |f|
%div.form-group
= f.label "Username or email", for: :login
= f.text_field :login, class: "form-control top", autofocus: "autofocus", autocapitalize: "off", autocorrect: "off", required: true, title: "This field is required."
%div.form-group
= f.label :password
= f.password_field :password, class: "form-control bottom", required: true, title: "This field is required."
- if devise_mapping.rememberable?
.remember-me.checkbox
%label{for: "user_remember_me"}
......@@ -8,5 +12,5 @@
%span Remember me
.pull-right
= link_to "Forgot your password?", new_password_path(resource_name)
%div
%div.submit-container
= f.submit "Sign in", class: "btn btn-save"
= form_tag(omniauth_authorize_path(:user, :crowd), id: 'new_crowd_user' ) do
= text_field_tag :username, nil, {class: "form-control top", placeholder: "Username", autofocus: "autofocus"}
= password_field_tag :password, nil, {class: "form-control bottom", placeholder: "Password"}
= form_tag(omniauth_authorize_path(:user, :crowd), id: 'new_crowd_user', class: 'show-gl-field-errors') do
.form-group
= label_tag 'Username or email', for: :username
= text_field_tag :username, nil, {class: "form-control top", title: "This field is required", autofocus: "autofocus", required: true }
.form-group
= label_tag :password
= password_field_tag :password, nil, { class: "form-control bottom", title: "This field is required.", required: true }
- if devise_mapping.rememberable?
.remember-me.checkbox
%label{for: "remember_me"}
......
= form_tag(omniauth_callback_path(:user, server['provider_name']), id: 'new_ldap_user') do
= text_field_tag :username, nil, {class: "form-control top", placeholder: "#{server['label']} Login", autofocus: "autofocus"}
= password_field_tag :password, nil, {class: "form-control bottom", placeholder: "Password"}
= form_tag(omniauth_callback_path(:user, server['provider_name']), id: 'new_ldap_user', class: "show-gl-field-errors") do
.form-group
= label_tag "#{server['label']} Login", for: :username
= text_field_tag :username, nil, {class: "form-control top", title: "This field is required.", autofocus: "autofocus", required: true }
.form-group
= label_tag :password
= password_field_tag :password, nil, { class: "form-control bottom", title: "This field is required.", required: true }
- if devise_mapping.rememberable?
.remember-me.checkbox
%label{for: "remember_me"}
......
- page_title "Sign in"
%div
- if signin_enabled? || ldap_enabled? || crowd_enabled?
= render 'devise/shared/signin_box'
- if form_based_providers.any?
= render 'devise/shared/tabs_ldap'
- else
= render 'devise/shared/tabs_normal'
.tab-content
- if signin_enabled? || ldap_enabled? || crowd_enabled?
= render 'devise/shared/signin_box'
-# Omniauth fits between signin/ldap signin and signup and does not have a surrounding box
- if omniauth_enabled? && devise_mapping.omniauthable? && button_based_providers_enabled?
.clearfix.prepend-top-20
= render 'devise/shared/omniauth_box'
-# Signup only makes sense if you can also sign-in
- if signin_enabled? && signup_enabled?
.prepend-top-20
-# Signup only makes sense if you can also sign-in
- if signin_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?)
%div
No authentication methods configured.
- if omniauth_enabled? && devise_mapping.omniauthable? && button_based_providers_enabled?
.clearfix
= render 'devise/shared/omniauth_box'
......@@ -3,20 +3,19 @@
= page_specific_javascript_tag('u2f.js')
%div
= render 'devise/shared/tab_single', tab_title: 'Two-Factor Authentication'
.login-box
.login-heading
%h3 Two-Factor Authentication
.login-body
- if @user.two_factor_otp_enabled?
%h5 Authenticate via Two-Factor App
= form_for(resource, as: resource_name, url: session_path(resource_name), method: :post) do |f|
= form_for(resource, as: resource_name, url: session_path(resource_name), method: :post, html: { class: 'edit_user show-gl-field-errors' }) do |f|
- resource_params = params[resource_name].presence || params
= f.hidden_field :remember_me, value: resource_params.fetch(:remember_me, 0)
= f.text_field :otp_attempt, class: 'form-control', placeholder: 'Two-Factor Authentication code', required: true, autofocus: true, autocomplete: 'off'
%p.help-block.hint Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes.
.prepend-top-20
= f.submit "Verify code", class: "btn btn-save"
.form-group
= f.label 'Two-Factor Authentication code', name: :otp_attempt
= f.text_field :otp_attempt, class: 'form-control', required: true, autofocus: true, autocomplete: 'off', title: 'This field is required.'
%p.help-block.hint Enter the code from the two-factor app on your mobile device. If you've lost your device, you may enter one of your recovery codes.
.prepend-top-20
= f.submit "Verify code", class: "btn btn-save"
- if @user.two_factor_u2f_enabled?
%hr
= render "u2f/authenticate", locals: { params: params, resource: resource, resource_name: resource_name }
%p
%span.light
Sign in with &nbsp;
- providers = enabled_button_based_providers
- providers.each do |provider|
%div.omniauth-container
%p
%span.light
- has_icon = provider_has_icon?(provider)
= link_to provider_image_tag(provider), omniauth_authorize_path(:user, provider), method: :post, class: (has_icon ? 'oauth-image-link' : 'btn'), "data-no-turbolink" => "true"
Sign in with &nbsp;
- providers = enabled_button_based_providers
- providers.each do |provider|
%span.light
- has_icon = provider_has_icon?(provider)
= link_to provider_image_tag(provider), omniauth_authorize_path(:user, provider), method: :post, class: (has_icon ? 'oauth-image-link' : 'btn'), "data-no-turbolink" => "true"
%p
%span.light
Already have login and password?
%strong
= link_to "Sign in", new_session_path(resource_name)
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment