Commit b76c7038 authored by sytses's avatar sytses

Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce

parents 67861a04 2511c19f
...@@ -2,7 +2,6 @@ source 'https://rubygems.org' ...@@ -2,7 +2,6 @@ source 'https://rubygems.org'
gem 'rails', '4.2.8' gem 'rails', '4.2.8'
gem 'rails-deprecated_sanitizer', '~> 1.0.3' gem 'rails-deprecated_sanitizer', '~> 1.0.3'
gem 'bootsnap', '~> 1.0.0'
# Responders respond_to and respond_with # Responders respond_to and respond_with
gem 'responders', '~> 2.0' gem 'responders', '~> 2.0'
...@@ -123,6 +122,7 @@ gem 'asciidoctor', '~> 1.5.2' ...@@ -123,6 +122,7 @@ gem 'asciidoctor', '~> 1.5.2'
gem 'asciidoctor-plantuml', '0.0.7' gem 'asciidoctor-plantuml', '0.0.7'
gem 'rouge', '~> 2.0' gem 'rouge', '~> 2.0'
gem 'truncato', '~> 0.7.8' gem 'truncato', '~> 0.7.8'
gem 'bootstrap_form', '~> 2.7.0'
# See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s # See https://groups.google.com/forum/#!topic/ruby-security-ann/aSbgDiwb24s
# and https://groups.google.com/forum/#!topic/ruby-security-ann/Dy7YiKb_pMM # and https://groups.google.com/forum/#!topic/ruby-security-ann/Dy7YiKb_pMM
...@@ -384,7 +384,7 @@ gem 'vmstat', '~> 2.3.0' ...@@ -384,7 +384,7 @@ gem 'vmstat', '~> 2.3.0'
gem 'sys-filesystem', '~> 1.1.6' gem 'sys-filesystem', '~> 1.1.6'
# Gitaly GRPC client # Gitaly GRPC client
gem 'gitaly', '~> 0.8.0' gem 'gitaly', '~> 0.9.0'
gem 'toml-rb', '~> 0.3.15', require: false gem 'toml-rb', '~> 0.3.15', require: false
......
...@@ -83,11 +83,10 @@ GEM ...@@ -83,11 +83,10 @@ GEM
bindata (2.3.5) bindata (2.3.5)
binding_of_caller (0.7.2) binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1) debug_inspector (>= 0.0.1)
bootsnap (1.0.0)
msgpack (~> 1.0)
bootstrap-sass (3.3.6) bootstrap-sass (3.3.6)
autoprefixer-rails (>= 5.2.1) autoprefixer-rails (>= 5.2.1)
sass (>= 3.3.4) sass (>= 3.3.4)
bootstrap_form (2.7.0)
brakeman (3.6.1) brakeman (3.6.1)
browser (2.2.0) browser (2.2.0)
builder (3.2.3) builder (3.2.3)
...@@ -277,7 +276,7 @@ GEM ...@@ -277,7 +276,7 @@ GEM
po_to_json (>= 1.0.0) po_to_json (>= 1.0.0)
rails (>= 3.2.0) rails (>= 3.2.0)
gherkin-ruby (0.3.2) gherkin-ruby (0.3.2)
gitaly (0.8.0) gitaly (0.9.0)
google-protobuf (~> 3.1) google-protobuf (~> 3.1)
grpc (~> 1.0) grpc (~> 1.0)
github-linguist (4.7.6) github-linguist (4.7.6)
...@@ -464,7 +463,6 @@ GEM ...@@ -464,7 +463,6 @@ GEM
minitest (5.7.0) minitest (5.7.0)
mmap2 (2.2.6) mmap2 (2.2.6)
mousetrap-rails (1.4.6) mousetrap-rails (1.4.6)
msgpack (1.1.0)
multi_json (1.12.1) multi_json (1.12.1)
multi_xml (0.6.0) multi_xml (0.6.0)
multipart-post (2.0.0) multipart-post (2.0.0)
...@@ -928,8 +926,8 @@ DEPENDENCIES ...@@ -928,8 +926,8 @@ DEPENDENCIES
benchmark-ips (~> 2.3.0) benchmark-ips (~> 2.3.0)
better_errors (~> 2.1.0) better_errors (~> 2.1.0)
binding_of_caller (~> 0.7.2) binding_of_caller (~> 0.7.2)
bootsnap (~> 1.0.0)
bootstrap-sass (~> 3.3.0) bootstrap-sass (~> 3.3.0)
bootstrap_form (~> 2.7.0)
brakeman (~> 3.6.0) brakeman (~> 3.6.0)
browser (~> 2.2) browser (~> 2.2)
bullet (~> 5.5.0) bullet (~> 5.5.0)
...@@ -977,7 +975,7 @@ DEPENDENCIES ...@@ -977,7 +975,7 @@ DEPENDENCIES
gettext (~> 3.2.2) gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0) gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0) gettext_i18n_rails_js (~> 1.2.0)
gitaly (~> 0.8.0) gitaly (~> 0.9.0)
github-linguist (~> 4.7.0) github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1) gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-markup (~> 1.5.1) gitlab-markup (~> 1.5.1)
......
This diff is collapsed.
...@@ -17,7 +17,7 @@ export default { ...@@ -17,7 +17,7 @@ export default {
methods: { methods: {
submit(e) { submit(e) {
e.preventDefault(); e.preventDefault();
if (this.title.trim() === '') return; if (this.title.trim() === '') return Promise.resolve();
this.error = false; this.error = false;
...@@ -29,7 +29,10 @@ export default { ...@@ -29,7 +29,10 @@ export default {
assignees: [], assignees: [],
}); });
this.list.newIssue(issue) eventHub.$emit(`scroll-board-list-${this.list.id}`);
this.cancel();
return this.list.newIssue(issue)
.then(() => { .then(() => {
// Need this because our jQuery very kindly disables buttons on ALL form submissions // Need this because our jQuery very kindly disables buttons on ALL form submissions
$(this.$refs.submitButton).enable(); $(this.$refs.submitButton).enable();
...@@ -47,9 +50,6 @@ export default { ...@@ -47,9 +50,6 @@ export default {
// Show error message // Show error message
this.error = true; this.error = true;
}); });
eventHub.$emit(`scroll-board-list-${this.list.id}`);
this.cancel();
}, },
cancel() { cancel() {
this.title = ''; this.title = '';
......
...@@ -112,8 +112,7 @@ class List { ...@@ -112,8 +112,7 @@ class List {
.then((resp) => { .then((resp) => {
const data = resp.json(); const data = resp.json();
issue.id = data.iid; issue.id = data.iid;
})
.then(() => {
if (this.issuesSize > 1) { if (this.issuesSize > 1) {
const moveBeforeIid = this.issues[1].id; const moveBeforeIid = this.issues[1].id;
gl.boardService.moveIssue(issue.id, null, null, null, moveBeforeIid); gl.boardService.moveIssue(issue.id, null, null, null, moveBeforeIid);
......
...@@ -403,6 +403,14 @@ export default { ...@@ -403,6 +403,14 @@ export default {
return ''; return '';
}, },
displayEnvironmentActions() {
return this.hasManualActions ||
this.externalURL ||
this.monitoringUrl ||
this.hasStopAction ||
this.canRetry;
},
/** /**
* Constructs folder URL based on the current location and the folder id. * Constructs folder URL based on the current location and the folder id.
* *
...@@ -535,9 +543,12 @@ export default { ...@@ -535,9 +543,12 @@ export default {
</span> </span>
</div> </div>
<div class="table-section section-30 table-button-footer" role="gridcell"> <div
v-if="!model.isFolder && displayEnvironmentActions"
class="table-section section-30 table-button-footer"
role="gridcell">
<div <div
v-if="!model.isFolder"
class="btn-group table-action-buttons" class="btn-group table-action-buttons"
role="group"> role="group">
......
...@@ -40,6 +40,10 @@ class FilteredSearchManager { ...@@ -40,6 +40,10 @@ class FilteredSearchManager {
return []; return [];
}) })
.then((searches) => { .then((searches) => {
if (!searches) {
return;
}
// Put any searches that may have come in before // Put any searches that may have come in before
// we fetched the saved searches ahead of the already saved ones // we fetched the saved searches ahead of the already saved ones
const resultantSearches = this.recentSearchesStore.setRecentSearches( const resultantSearches = this.recentSearchesStore.setRecentSearches(
...@@ -487,6 +491,7 @@ class FilteredSearchManager { ...@@ -487,6 +491,7 @@ class FilteredSearchManager {
} }
searchState(e) { searchState(e) {
e.preventDefault();
const target = e.currentTarget; const target = e.currentTarget;
// remove focus outline after click // remove focus outline after click
target.blur(); target.blur();
......
...@@ -47,8 +47,8 @@ export default class GroupsStore { ...@@ -47,8 +47,8 @@ export default class GroupsStore {
// Map groups to an object // Map groups to an object
groups.map((group) => { groups.map((group) => {
mappedGroups[group.id] = group; mappedGroups[`id${group.id}`] = group;
mappedGroups[group.id].subGroups = {}; mappedGroups[`id${group.id}`].subGroups = {};
return group; return group;
}); });
...@@ -56,26 +56,27 @@ export default class GroupsStore { ...@@ -56,26 +56,27 @@ export default class GroupsStore {
const currentGroup = mappedGroups[key]; const currentGroup = mappedGroups[key];
if (currentGroup.parentId) { if (currentGroup.parentId) {
// If the group is not at the root level, add it to its parent array of subGroups. // If the group is not at the root level, add it to its parent array of subGroups.
const findParentGroup = mappedGroups[currentGroup.parentId]; const findParentGroup = mappedGroups[`id${currentGroup.parentId}`];
if (findParentGroup) { if (findParentGroup) {
mappedGroups[currentGroup.parentId].subGroups[currentGroup.id] = currentGroup; mappedGroups[`id${currentGroup.parentId}`].subGroups[`id${currentGroup.id}`] = currentGroup;
mappedGroups[currentGroup.parentId].isOpen = true; // Expand group if it has subgroups mappedGroups[`id${currentGroup.parentId}`].isOpen = true; // Expand group if it has subgroups
} else if (parentGroup && parentGroup.id === currentGroup.parentId) { } else if (parentGroup && parentGroup.id === currentGroup.parentId) {
tree[currentGroup.id] = currentGroup; tree[`id${currentGroup.id}`] = currentGroup;
} else { } else {
// Means the groups hast no direct parent. // No parent found. We save it for later processing
// Save for later processing, we will add them to its corresponding base group
orphans.push(currentGroup); orphans.push(currentGroup);
// Add to tree to preserve original order
tree[`id${currentGroup.id}`] = currentGroup;
} }
} else { } else {
// If the group is at the root level, add it to first level elements array. // If the group is at the top level, add it to first level elements array.
tree[currentGroup.id] = currentGroup; tree[`id${currentGroup.id}`] = currentGroup;
} }
return key; return key;
}); });
// Hopefully this array will be empty for most cases
if (orphans.length) { if (orphans.length) {
orphans.map((orphan) => { orphans.map((orphan) => {
let found = false; let found = false;
...@@ -83,11 +84,23 @@ export default class GroupsStore { ...@@ -83,11 +84,23 @@ export default class GroupsStore {
Object.keys(tree).map((key) => { Object.keys(tree).map((key) => {
const group = tree[key]; const group = tree[key];
if (currentOrphan.fullPath.lastIndexOf(group.fullPath) === 0) {
if (
group &&
currentOrphan.fullPath.lastIndexOf(group.fullPath) === 0 &&
// Make sure the currently selected orphan is not the same as the group
// we are checking here otherwise it will end up in an infinite loop
currentOrphan.id !== group.id
) {
group.subGroups[currentOrphan.id] = currentOrphan; group.subGroups[currentOrphan.id] = currentOrphan;
group.isOpen = true; group.isOpen = true;
currentOrphan.isOrphan = true; currentOrphan.isOrphan = true;
found = true; found = true;
// Delete if group was put at the top level. If not the group will be displayed twice.
if (tree[`id${currentOrphan.id}`]) {
delete tree[`id${currentOrphan.id}`];
}
} }
return key; return key;
...@@ -95,7 +108,8 @@ export default class GroupsStore { ...@@ -95,7 +108,8 @@ export default class GroupsStore {
if (!found) { if (!found) {
currentOrphan.isOrphan = true; currentOrphan.isOrphan = true;
tree[currentOrphan.id] = currentOrphan;
tree[`id${currentOrphan.id}`] = currentOrphan;
} }
return orphan; return orphan;
...@@ -140,7 +154,7 @@ export default class GroupsStore { ...@@ -140,7 +154,7 @@ export default class GroupsStore {
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
removeGroup(group, collection) { removeGroup(group, collection) {
Vue.delete(collection, group.id); Vue.delete(collection, `id${group.id}`);
} }
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
......
...@@ -204,13 +204,7 @@ export default { ...@@ -204,13 +204,7 @@ export default {
method: 'getData', method: 'getData',
successCallback: (res) => { successCallback: (res) => {
const data = res.json(); const data = res.json();
const shouldUpdate = this.store.stateShouldUpdate(data);
this.store.updateState(data); this.store.updateState(data);
if (this.showForm && (shouldUpdate.title || shouldUpdate.description)) {
this.store.formState.lockedWarningVisible = true;
}
}, },
errorCallback(err) { errorCallback(err) {
throw new Error(err); throw new Error(err);
......
...@@ -12,6 +12,10 @@ export default class Store { ...@@ -12,6 +12,10 @@ export default class Store {
} }
updateState(data) { updateState(data) {
if (this.stateShouldUpdate(data)) {
this.formState.lockedWarningVisible = true;
}
this.state.titleHtml = data.title; this.state.titleHtml = data.title;
this.state.titleText = data.title_text; this.state.titleText = data.title_text;
this.state.descriptionHtml = data.description; this.state.descriptionHtml = data.description;
...@@ -23,10 +27,8 @@ export default class Store { ...@@ -23,10 +27,8 @@ export default class Store {
} }
stateShouldUpdate(data) { stateShouldUpdate(data) {
return { return this.state.titleText !== data.title_text ||
title: this.state.titleText !== data.title_text, this.state.descriptionText !== data.description_text;
description: this.state.descriptionText !== data.description_text,
};
} }
setFormState(state) { setFormState(state) {
......
...@@ -86,18 +86,25 @@ ...@@ -86,18 +86,25 @@
// This is required to handle non-unicode characters in hash // This is required to handle non-unicode characters in hash
hash = decodeURIComponent(hash); hash = decodeURIComponent(hash);
var fixedTabs = document.querySelector('.js-tabs-affix');
var fixedNav = document.querySelector('.navbar-gitlab');
var adjustment = 0;
if (fixedNav) adjustment -= fixedNav.offsetHeight;
// scroll to user-generated markdown anchor if we cannot find a match // scroll to user-generated markdown anchor if we cannot find a match
if (document.getElementById(hash) === null) { if (document.getElementById(hash) === null) {
var target = document.getElementById('user-content-' + hash); var target = document.getElementById('user-content-' + hash);
if (target && target.scrollIntoView) { if (target && target.scrollIntoView) {
target.scrollIntoView(true); target.scrollIntoView(true);
window.scrollBy(0, adjustment);
} }
} else { } else {
// only adjust for fixedTabs when not targeting user-generated content // only adjust for fixedTabs when not targeting user-generated content
var fixedTabs = document.querySelector('.js-tabs-affix');
if (fixedTabs) { if (fixedTabs) {
window.scrollBy(0, -fixedTabs.offsetHeight); adjustment -= fixedTabs.offsetHeight;
} }
window.scrollBy(0, adjustment);
} }
}; };
......
This diff is collapsed.
...@@ -155,7 +155,10 @@ import BlobForkSuggestion from './blob/blob_fork_suggestion'; ...@@ -155,7 +155,10 @@ import BlobForkSuggestion from './blob/blob_fork_suggestion';
scrollToElement(container) { scrollToElement(container) {
if (location.hash) { if (location.hash) {
const offset = -$('.js-tabs-affix').outerHeight(); const offset = 0 - (
$('.navbar-gitlab').outerHeight() +
$('.js-tabs-affix').outerHeight()
);
const $el = $(`${container} ${location.hash}:not(.match)`); const $el = $(`${container} ${location.hash}:not(.match)`);
if ($el.length) { if ($el.length) {
$.scrollTo($el[0], { offset }); $.scrollTo($el[0], { offset });
...@@ -291,7 +294,7 @@ import BlobForkSuggestion from './blob/blob_fork_suggestion'; ...@@ -291,7 +294,7 @@ import BlobForkSuggestion from './blob/blob_fork_suggestion';
// Scroll any linked note into view // Scroll any linked note into view
// Similar to `toggler_behavior` in the discussion tab // Similar to `toggler_behavior` in the discussion tab
const hash = window.gl.utils.getLocationHash(); const hash = window.gl.utils.getLocationHash();
const anchor = hash && $container.find(`[id="${hash}"]`); const anchor = hash && $container.find(`.note[id="${hash}"]`);
if (anchor && anchor.length > 0) { if (anchor && anchor.length > 0) {
const notesContent = anchor.closest('.notes_content'); const notesContent = anchor.closest('.notes_content');
const lineType = notesContent.hasClass('new') ? 'new' : 'old'; const lineType = notesContent.hasClass('new') ? 'new' : 'old';
...@@ -301,6 +304,7 @@ import BlobForkSuggestion from './blob/blob_fork_suggestion'; ...@@ -301,6 +304,7 @@ import BlobForkSuggestion from './blob/blob_fork_suggestion';
forceShow: true, forceShow: true,
}); });
anchor[0].scrollIntoView(); anchor[0].scrollIntoView();
window.gl.utils.handleLocationHash();
// We have multiple elements on the page with `#note_xxx` // We have multiple elements on the page with `#note_xxx`
// (discussion and diff tabs) and `:target` only applies to the first // (discussion and diff tabs) and `:target` only applies to the first
anchor.addClass('target'); anchor.addClass('target');
......
This source diff could not be displayed because it is too large. You can view the blob instead.
export default {
EMPTY: 'empty',
LOADING: 'loading',
LIST: 'list',
};
import PrometheusMetrics from './prometheus_metrics';
$(() => {
const prometheusMetrics = new PrometheusMetrics('.js-prometheus-metrics-monitoring');
prometheusMetrics.loadActiveMetrics();
});
import PANEL_STATE from './constants';
export default class PrometheusMetrics {
constructor(wrapperSelector) {
this.backOffRequestCounter = 0;
this.$wrapper = $(wrapperSelector);
this.$monitoredMetricsPanel = this.$wrapper.find('.js-panel-monitored-metrics');
this.$monitoredMetricsCount = this.$monitoredMetricsPanel.find('.js-monitored-count');
this.$monitoredMetricsLoading = this.$monitoredMetricsPanel.find('.js-loading-metrics');
this.$monitoredMetricsEmpty = this.$monitoredMetricsPanel.find('.js-empty-metrics');
this.$monitoredMetricsList = this.$monitoredMetricsPanel.find('.js-metrics-list');
this.$missingEnvVarPanel = this.$wrapper.find('.js-panel-missing-env-vars');
this.$panelToggle = this.$missingEnvVarPanel.find('.js-panel-toggle');
this.$missingEnvVarMetricCount = this.$missingEnvVarPanel.find('.js-env-var-count');
this.$missingEnvVarMetricsList = this.$missingEnvVarPanel.find('.js-missing-var-metrics-list');
this.activeMetricsEndpoint = this.$monitoredMetricsPanel.data('active-metrics');
this.$panelToggle.on('click', e => this.handlePanelToggle(e));
}
/* eslint-disable class-methods-use-this */
handlePanelToggle(e) {
const $toggleBtn = $(e.currentTarget);
const $currentPanelBody = $toggleBtn.closest('.panel').find('.panel-body');
$currentPanelBody.toggleClass('hidden');
if ($toggleBtn.hasClass('fa-caret-down')) {
$toggleBtn.removeClass('fa-caret-down').addClass('fa-caret-right');
} else {
$toggleBtn.removeClass('fa-caret-right').addClass('fa-caret-down');
}
}
showMonitoringMetricsPanelState(stateName) {
switch (stateName) {
case PANEL_STATE.LOADING:
this.$monitoredMetricsLoading.removeClass('hidden');
this.$monitoredMetricsEmpty.addClass('hidden');
this.$monitoredMetricsList.addClass('hidden');
break;
case PANEL_STATE.LIST:
this.$monitoredMetricsLoading.addClass('hidden');
this.$monitoredMetricsEmpty.addClass('hidden');
this.$monitoredMetricsList.removeClass('hidden');
break;
default:
this.$monitoredMetricsLoading.addClass('hidden');
this.$monitoredMetricsEmpty.removeClass('hidden');
this.$monitoredMetricsList.addClass('hidden');
break;
}
}
populateActiveMetrics(metrics) {
let totalMonitoredMetrics = 0;
let totalMissingEnvVarMetrics = 0;
metrics.forEach((metric) => {
this.$monitoredMetricsList.append(`<li>${metric.group}<span class="badge">${metric.active_metrics}</span></li>`);
totalMonitoredMetrics += metric.active_metrics;
if (metric.metrics_missing_requirements > 0) {
this.$missingEnvVarMetricsList.append(`<li>${metric.group}</li>`);
totalMissingEnvVarMetrics += 1;
}
});
this.$monitoredMetricsCount.text(totalMonitoredMetrics);
this.showMonitoringMetricsPanelState(PANEL_STATE.LIST);
if (totalMissingEnvVarMetrics > 0) {
this.$missingEnvVarPanel.removeClass('hidden');
this.$missingEnvVarPanel.find('.flash-container').off('click');
this.$missingEnvVarMetricCount.text(totalMissingEnvVarMetrics);
}
}
loadActiveMetrics() {
this.showMonitoringMetricsPanelState(PANEL_STATE.LOADING);
gl.utils.backOff((next, stop) => {
$.getJSON(this.activeMetricsEndpoint)
.done((res) => {
if (res && res.success) {
stop(res);
} else {
this.backOffRequestCounter = this.backOffRequestCounter += 1;
if (this.backOffRequestCounter < 3) {
next();
} else {
stop(res);
}
}
})
.fail(stop);
})
.then((res) => {
if (res && res.data && res.data.length) {
this.populateActiveMetrics(res.data);
} else {
this.showMonitoringMetricsPanelState(PANEL_STATE.EMPTY);
}
})
.catch(() => {
this.showMonitoringMetricsPanelState(PANEL_STATE.EMPTY);
});
}
}
...@@ -10,8 +10,6 @@ import Cookies from 'js-cookie'; ...@@ -10,8 +10,6 @@ import Cookies from 'js-cookie';
this.$sidebarInner = this.sidebar.find('.issuable-sidebar'); this.$sidebarInner = this.sidebar.find('.issuable-sidebar');
this.$navGitlab = $('.navbar-gitlab'); this.$navGitlab = $('.navbar-gitlab');
this.$layoutNav = $('.layout-nav');
this.$subScroll = $('.sub-nav-scroll');
this.$rightSidebar = $('.js-right-sidebar'); this.$rightSidebar = $('.js-right-sidebar');
this.removeListeners(); this.removeListeners();
...@@ -215,7 +213,7 @@ import Cookies from 'js-cookie'; ...@@ -215,7 +213,7 @@ import Cookies from 'js-cookie';
}; };
Sidebar.prototype.setSidebarHeight = function() { Sidebar.prototype.setSidebarHeight = function() {
const $navHeight = this.$navGitlab.outerHeight() + this.$layoutNav.outerHeight() + (this.$subScroll ? this.$subScroll.outerHeight() : 0); const $navHeight = this.$navGitlab.outerHeight();
const diff = $navHeight - $(window).scrollTop(); const diff = $navHeight - $(window).scrollTop();
if (diff > 0) { if (diff > 0) {
this.$rightSidebar.outerHeight($(window).height() - diff); this.$rightSidebar.outerHeight($(window).height() - diff);
......
...@@ -4,7 +4,7 @@ function expandSectionParent($section, $content) { ...@@ -4,7 +4,7 @@ function expandSectionParent($section, $content) {
} }
function expandSection($section) { function expandSection($section) {
$section.find('.js-settings-toggle').text('Close'); $section.find('.js-settings-toggle').text('Collapse');
const $content = $section.find('.settings-content'); const $content = $section.find('.settings-content');
$content.addClass('expanded').off('scroll.expandSection').scrollTop(0); $content.addClass('expanded').off('scroll.expandSection').scrollTop(0);
......
...@@ -643,7 +643,7 @@ UsersSelect.prototype.formatResult = function(user) { ...@@ -643,7 +643,7 @@ UsersSelect.prototype.formatResult = function(user) {
} else { } else {
avatar = gon.default_avatar_url; avatar = gon.default_avatar_url;
} }
return "<div class='user-result " + (!user.username ? 'no-username' : void 0) + "'> <div class='user-image'><img class='avatar s24' src='" + avatar + "'></div> <div class='user-name'>" + user.name + "</div> <div class='user-username'>" + (user.username || "") + "</div> </div>"; return "<div class='user-result " + (!user.username ? 'no-username' : void 0) + "'> <div class='user-image'><img class='avatar avatar-inline s32' src='" + avatar + "'></div> <div class='user-name dropdown-menu-user-full-name'>" + user.name + "</div> <div class='user-username dropdown-menu-user-username'>" + ("@" + user.username || "") + "</div> </div>";
}; };
UsersSelect.prototype.formatSelection = function(user) { UsersSelect.prototype.formatSelection = function(user) {
......
...@@ -395,6 +395,11 @@ ...@@ -395,6 +395,11 @@
.dropdown-menu-align-right { .dropdown-menu-align-right {
left: auto; left: auto;
right: 0; right: 0;
margin-top: -5px;
@media (max-width: $screen-xs-max) {
left: 0;
}
} }
.dropdown-menu-selectable { .dropdown-menu-selectable {
......
...@@ -12,6 +12,12 @@ ...@@ -12,6 +12,12 @@
&.readme-holder { &.readme-holder {
margin: $gl-padding 0; margin: $gl-padding 0;
&.limited-width-container .file-content {
max-width: $limited-layout-width-sm;
margin-left: auto;
margin-right: auto;
}
} }
table { table {
......
...@@ -346,6 +346,7 @@ header { ...@@ -346,6 +346,7 @@ header {
width: auto; width: auto;
min-width: 140px; min-width: 140px;
margin-top: -5px; margin-top: -5px;
left: auto;
.current-user { .current-user {
padding: 5px 18px; padding: 5px 18px;
......
...@@ -53,7 +53,7 @@ body { ...@@ -53,7 +53,7 @@ body {
} }
&.limit-container-width-sm { &.limit-container-width-sm {
max-width: 790px; max-width: $limited-layout-width-sm;
} }
} }
......
...@@ -45,8 +45,7 @@ ...@@ -45,8 +45,7 @@
li { li {
display: flex; display: flex;
a, a {
.btn-link {
padding: $gl-btn-padding; padding: $gl-btn-padding;
padding-bottom: 11px; padding-bottom: 11px;
font-size: 14px; font-size: 14px;
...@@ -68,29 +67,7 @@ ...@@ -68,29 +67,7 @@
} }
} }
.btn-link { &.active a {
padding-top: 16px;
padding-left: 15px;
padding-right: 15px;
border-left: none;
border-right: none;
border-top: none;
border-radius: 0;
&:hover,
&:active,
&:focus {
background-color: transparent;
}
&:active {
outline: 0;
box-shadow: none;
}
}
&.active a,
&.active .btn-link {
border-bottom: 2px solid $link-underline-blue; border-bottom: 2px solid $link-underline-blue;
color: $black; color: $black;
font-weight: 600; font-weight: 600;
......
...@@ -44,6 +44,10 @@ ...@@ -44,6 +44,10 @@
&:target, &:target,
&.target { &.target {
background: $line-target-blue; background: $line-target-blue;
&.system-note .note-body .note-text.system-note-commit-list::after {
background: linear-gradient(rgba($line-target-blue, 0.1) -100px, $line-target-blue 100%);
}
} }
.avatar { .avatar {
......
...@@ -161,6 +161,7 @@ $progress-color: #c0392b; ...@@ -161,6 +161,7 @@ $progress-color: #c0392b;
$header-height: 50px; $header-height: 50px;
$fixed-layout-width: 1280px; $fixed-layout-width: 1280px;
$limited-layout-width: 990px; $limited-layout-width: 990px;
$limited-layout-width-sm: 790px;
$gl-avatar-size: 40px; $gl-avatar-size: 40px;
$error-exclamation-point: $red-500; $error-exclamation-point: $red-500;
$border-radius-default: 3px; $border-radius-default: 3px;
...@@ -323,6 +324,7 @@ $note-disabled-comment-color: #b2b2b2; ...@@ -323,6 +324,7 @@ $note-disabled-comment-color: #b2b2b2;
$note-targe3-outside: #fffff0; $note-targe3-outside: #fffff0;
$note-targe3-inside: #ffffd3; $note-targe3-inside: #ffffd3;
$note-line2-border: #ddd; $note-line2-border: #ddd;
$note-icon-gutter-width: 55px;
/* /*
......
...@@ -83,6 +83,7 @@ ...@@ -83,6 +83,7 @@
.avatar { .avatar {
float: none; float: none;
margin-right: 0;
} }
} }
......
...@@ -11,7 +11,9 @@ ...@@ -11,7 +11,9 @@
.commit-box, .commit-box,
.info-well, .info-well,
.commit-ci-menu, .commit-ci-menu,
.files-changed { .files-changed,
.limited-header-width,
.limited-width-notes {
@extend .fixed-width-container; @extend .fixed-width-container;
} }
......
...@@ -136,10 +136,6 @@ ...@@ -136,10 +136,6 @@
width: 250px; width: 250px;
} }
@media (min-width: $screen-md-min) {
width: 350px;
}
&.input-short { &.input-short {
@media (min-width: $screen-md-min) { @media (min-width: $screen-md-min) {
width: 170px; width: 170px;
......
...@@ -419,7 +419,7 @@ ...@@ -419,7 +419,7 @@
.commit { .commit {
margin: 0; margin: 0;
padding: 10px 0; padding: 10px;
list-style: none; list-style: none;
&:hover { &:hover {
......
...@@ -148,8 +148,20 @@ ...@@ -148,8 +148,20 @@
padding: 6px 0; padding: 6px 0;
} }
.notes-form > li { .notes.notes-form > li.timeline-entry {
border: 0; @include notes-media('max', $screen-sm-max) {
padding: 0;
}
.timeline-content {
@include notes-media('max', $screen-sm-max) {
margin: 0;
}
}
.timeline-entry-inner {
border: 0;
}
} }
.note-edit-form { .note-edit-form {
......
...@@ -14,16 +14,6 @@ ul.notes { ...@@ -14,16 +14,6 @@ ul.notes {
margin: 0; margin: 0;
padding: 0; padding: 0;
.timeline-content {
margin-left: 55px;
&.timeline-content-form {
@include notes-media('max', $screen-sm-max) {
margin-left: 0;
}
}
}
.note-created-ago, .note-created-ago,
.note-updated-at { .note-updated-at {
white-space: nowrap; white-space: nowrap;
...@@ -46,17 +36,49 @@ ul.notes { ...@@ -46,17 +36,49 @@ ul.notes {
} }
} }
> li { > li { // .timeline-entry
padding: $gl-padding $gl-btn-padding; padding: 0;
display: block; display: block;
position: relative; position: relative;
border-bottom: 1px solid $white-normal; border-bottom: 0;
@include notes-media('min', $screen-sm-min) {
padding-left: $note-icon-gutter-width;
}
&:last-child { .timeline-entry-inner {
// Override `.timeline > li:last-child { border-bottom: none; }` padding: $gl-padding $gl-btn-padding;
border-bottom: 1px solid $white-normal; border-bottom: 1px solid $white-normal;
} }
&:target,
&.target {
border-bottom: 1px solid $white-normal;
&:not(:first-child) {
border-top: 1px solid $white-normal;
margin-top: -1px;
}
.timeline-entry-inner {
border-bottom: 0;
}
}
.timeline-icon {
@include notes-media('min', $screen-sm-min) {
margin-left: -$note-icon-gutter-width;
}
}
.timeline-content {
margin-left: $note-icon-gutter-width;
@include notes-media('min', $screen-sm-min) {
margin-left: 0;
}
}
&.being-posted { &.being-posted {
pointer-events: none; pointer-events: none;
opacity: 0.5; opacity: 0.5;
...@@ -73,7 +95,7 @@ ul.notes { ...@@ -73,7 +95,7 @@ ul.notes {
} }
&.note-discussion { &.note-discussion {
&.timeline-entry { .timeline-entry-inner {
padding: $gl-padding 10px; padding: $gl-padding 10px;
} }
} }
...@@ -152,13 +174,8 @@ ul.notes { ...@@ -152,13 +174,8 @@ ul.notes {
.system-note { .system-note {
font-size: 14px; font-size: 14px;
padding-left: 0;
clear: both; clear: both;
@include notes-media('min', $screen-sm-min) {
margin-left: 65px;
}
.note-header-info { .note-header-info {
padding-bottom: 0; padding-bottom: 0;
} }
...@@ -192,13 +209,16 @@ ul.notes { ...@@ -192,13 +209,16 @@ ul.notes {
.timeline-icon { .timeline-icon {
float: left; float: left;
@include notes-media('min', $screen-sm-min) {
margin-left: 0;
width: auto;
}
svg { svg {
width: 16px; width: 16px;
height: 16px; height: 16px;
fill: $gray-darkest; fill: $gray-darkest;
position: absolute; margin-top: 2px;
left: 0;
top: 2px;
} }
} }
...@@ -250,7 +270,7 @@ ul.notes { ...@@ -250,7 +270,7 @@ ul.notes {
&::after { &::after {
content: ''; content: '';
width: 100%; width: 100%;
height: 67px; height: 70px;
position: absolute; position: absolute;
left: 0; left: 0;
bottom: 0; bottom: 0;
...@@ -639,15 +659,12 @@ ul.notes { ...@@ -639,15 +659,12 @@ ul.notes {
.discussion-body, .discussion-body,
.diff-file { .diff-file {
.notes .note { .notes .note {
padding-left: $gl-padding; border-bottom: 1px solid $white-normal;
padding-right: $gl-padding;
&.system-note {
padding-left: 0;
@media (min-width: $screen-sm-min) { .timeline-entry-inner {
margin-left: 70px; padding-left: $gl-padding;
} padding-right: $gl-padding;
border-bottom: none;
} }
} }
} }
......
...@@ -133,7 +133,7 @@ ...@@ -133,7 +133,7 @@
overflow: hidden; overflow: hidden;
display: inline-block; display: inline-block;
white-space: nowrap; white-space: nowrap;
vertical-align: top; vertical-align: middle;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
......
...@@ -380,7 +380,7 @@ a.deploy-project-label { ...@@ -380,7 +380,7 @@ a.deploy-project-label {
padding: 0; padding: 0;
background: transparent; background: transparent;
border: none; border: none;
line-height: 36px; line-height: 34px;
margin: 0; margin: 0;
> li + li::before { > li + li::before {
......
...@@ -126,3 +126,66 @@ ...@@ -126,3 +126,66 @@
margin-left: 5px; margin-left: 5px;
} }
} }
.prometheus-metrics-monitoring {
.panel {
.panel-toggle {
width: 14px;
}
.badge {
font-size: inherit;
}
.panel-heading .badge-count {
color: $white-light;
background: $common-gray-dark;
}
.panel-body {
padding: 0;
}
.flash-container {
margin-bottom: 0;
cursor: default;
.flash-notice {
border-radius: 0;
}
}
}
.loading-metrics,
.empty-metrics {
padding: 30px 10px;
p,
.btn {
margin-top: 10px;
margin-bottom: 0;
}
}
.loading-metrics .metrics-load-spinner {
color: $loading-color;
}
.metrics-list {
margin-bottom: 0;
li {
padding: $gl-padding;
.badge {
margin-left: 5px;
background: $badge-bg;
}
}
/* Ensure we don't add border if there's only single li */
li + li {
border-top: 1px solid $border-color;
}
}
}
.tree-holder { .tree-holder {
> .nav-block { .nav-block {
margin: 11px 0; margin: 10px 0;
@media (min-width: $screen-sm-min) {
display: flex;
.tree-ref-container {
flex: 1;
}
.tree-controls {
text-align: right;
.btn-group {
margin-left: 10px;
}
}
.tree-ref-holder {
float: left;
margin-right: 15px;
}
.repo-breadcrumb {
li:last-of-type {
position: relative;
}
}
.add-to-tree-dropdown {
position: absolute;
left: 18px;
}
}
}
@media (max-width: $screen-xs-max) {
.repo-breadcrumb {
margin-top: 10px;
position: relative;
.dropdown-menu {
min-width: 100%;
width: 100%;
left: inherit;
right: 0;
}
}
.add-to-tree-dropdown {
position: absolute;
left: 0;
right: 0;
}
.tree-controls {
margin-bottom: 10px;
.btn,
.dropdown,
.btn-group {
width: 100%;
}
.btn {
margin: 10px 0 0;
}
}
} }
.file-finder { .file-finder {
...@@ -131,11 +197,6 @@ ...@@ -131,11 +197,6 @@
} }
} }
.tree-ref-holder {
float: left;
margin-right: 15px;
}
.blob-commit-info { .blob-commit-info {
list-style: none; list-style: none;
margin: 0; margin: 0;
...@@ -159,16 +220,6 @@ ...@@ -159,16 +220,6 @@
color: $md-link-color; color: $md-link-color;
} }
.tree-controls {
float: right;
position: relative;
z-index: 2;
.project-action-button {
margin-left: $btn-side-margin;
}
}
.repo-charts { .repo-charts {
.sub-header { .sub-header {
margin: 20px 0; margin: 20px 0;
......
...@@ -40,6 +40,10 @@ class ApplicationController < ActionController::Base ...@@ -40,6 +40,10 @@ class ApplicationController < ActionController::Base
render_404 render_404
end end
rescue_from(ActionController::UnknownFormat) do
render_404
end
rescue_from Gitlab::Access::AccessDeniedError do |exception| rescue_from Gitlab::Access::AccessDeniedError do |exception|
render_403 render_403
end end
......
...@@ -22,6 +22,22 @@ class Projects::DeploymentsController < Projects::ApplicationController ...@@ -22,6 +22,22 @@ class Projects::DeploymentsController < Projects::ApplicationController
render_404 render_404
end end
def additional_metrics
return render_404 unless deployment.has_additional_metrics?
respond_to do |format|
format.json do
metrics = deployment.additional_metrics
if metrics.any?
render json: metrics
else
head :no_content
end
end
end
end
private private
def deployment def deployment
......
...@@ -129,6 +129,16 @@ class Projects::EnvironmentsController < Projects::ApplicationController ...@@ -129,6 +129,16 @@ class Projects::EnvironmentsController < Projects::ApplicationController
end end
end end
def additional_metrics
respond_to do |format|
format.json do
additional_metrics = environment.additional_metrics || {}
render json: additional_metrics, status: additional_metrics.any? ? :ok : :no_content
end
end
end
private private
def verify_api_request! def verify_api_request!
......
...@@ -575,10 +575,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -575,10 +575,10 @@ class Projects::MergeRequestsController < Projects::ApplicationController
def merge_request_params def merge_request_params
params.require(:merge_request) params.require(:merge_request)
.permit(merge_request_params_ce) .permit(merge_request_params_attributes)
end end
def merge_request_params_ce def merge_request_params_attributes
[ [
:assignee_id, :assignee_id,
:description, :description,
...@@ -598,7 +598,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController ...@@ -598,7 +598,11 @@ class Projects::MergeRequestsController < Projects::ApplicationController
end end
def merge_params def merge_params
params.permit(:should_remove_source_branch, :commit_message) params.permit(merge_params_attributes)
end
def merge_params_attributes
[:should_remove_source_branch, :commit_message]
end end
# Make sure merge requests created before 8.0 # Make sure merge requests created before 8.0
......
class Projects::PrometheusController < Projects::ApplicationController
before_action :authorize_read_project!
before_action :require_prometheus_metrics!
def active_metrics
respond_to do |format|
format.json do
matched_metrics = project.prometheus_service.matched_metrics || {}
if matched_metrics.any?
render json: matched_metrics
else
head :no_content
end
end
end
end
private
def require_prometheus_metrics!
render_404 unless project.prometheus_service.present?
end
end
...@@ -41,7 +41,7 @@ class IssuesFinder < IssuableFinder ...@@ -41,7 +41,7 @@ class IssuesFinder < IssuableFinder
def self.not_restricted_by_confidentiality(user) def self.not_restricted_by_confidentiality(user)
return Issue.where('issues.confidential IS NOT TRUE') if user.blank? return Issue.where('issues.confidential IS NOT TRUE') if user.blank?
return Issue.all if user.admin? return Issue.all if user.full_private_access?
Issue.where(' Issue.where('
issues.confidential IS NOT TRUE issues.confidential IS NOT TRUE
......
...@@ -85,20 +85,20 @@ module CommitsHelper ...@@ -85,20 +85,20 @@ module CommitsHelper
if @path.blank? if @path.blank?
return link_to( return link_to(
"Browse Files", _("Browse Files"),
namespace_project_tree_path(project.namespace, project, commit), namespace_project_tree_path(project.namespace, project, commit),
class: "btn btn-default" class: "btn btn-default"
) )
elsif @repo.blob_at(commit.id, @path) elsif @repo.blob_at(commit.id, @path)
return link_to( return link_to(
"Browse File", _("Browse File"),
namespace_project_blob_path(project.namespace, project, namespace_project_blob_path(project.namespace, project,
tree_join(commit.id, @path)), tree_join(commit.id, @path)),
class: "btn btn-default" class: "btn btn-default"
) )
elsif @path.present? elsif @path.present?
return link_to( return link_to(
"Browse Directory", _("Browse Directory"),
namespace_project_tree_path(project.namespace, project, namespace_project_tree_path(project.namespace, project,
tree_join(commit.id, @path)), tree_join(commit.id, @path)),
class: "btn btn-default" class: "btn btn-default"
......
...@@ -15,7 +15,7 @@ module GroupsHelper ...@@ -15,7 +15,7 @@ module GroupsHelper
@has_group_title = true @has_group_title = true
full_title = '' full_title = ''
group.ancestors.each do |parent| group.ancestors.reverse.each do |parent|
full_title += link_to(simple_sanitize(parent.name), group_path(parent), class: 'group-path hidable') full_title += link_to(simple_sanitize(parent.name), group_path(parent), class: 'group-path hidable')
full_title += '<span class="hidable"> / </span>'.html_safe full_title += '<span class="hidable"> / </span>'.html_safe
end end
......
...@@ -4,4 +4,14 @@ module UsersHelper ...@@ -4,4 +4,14 @@ module UsersHelper
title: user.email, title: user.email,
class: 'has-tooltip commit-committer-link') class: 'has-tooltip commit-committer-link')
end end
def user_email_help_text(user)
return 'We also use email for avatar detection if no avatar is uploaded.' unless user.unconfirmed_email.present?
confirmation_link = link_to 'Resend confirmation e-mail', user_confirmation_path(user: { email: @user.unconfirmed_email }), method: :post
h('Please click the link in the confirmation email before continuing. It was sent to ') +
content_tag(:strong) { user.unconfirmed_email } + h('.') +
content_tag(:p) { confirmation_link }
end
end end
...@@ -114,6 +114,17 @@ class Deployment < ActiveRecord::Base ...@@ -114,6 +114,17 @@ class Deployment < ActiveRecord::Base
project.monitoring_service.deployment_metrics(self) project.monitoring_service.deployment_metrics(self)
end end
def has_additional_metrics?
project.prometheus_service.present?
end
def additional_metrics
return {} unless project.prometheus_service.present?
metrics = project.prometheus_service.additional_deployment_metrics(self)
metrics&.merge(deployment_time: created_at.to_i) || {}
end
private private
def ref_path def ref_path
......
...@@ -157,6 +157,16 @@ class Environment < ActiveRecord::Base ...@@ -157,6 +157,16 @@ class Environment < ActiveRecord::Base
project.monitoring_service.environment_metrics(self) if has_metrics? project.monitoring_service.environment_metrics(self) if has_metrics?
end end
def has_additional_metrics?
project.prometheus_service.present? && available? && last_deployment.present?
end
def additional_metrics
if has_additional_metrics?
project.prometheus_service.additional_environment_metrics(self)
end
end
# An environment name is not necessarily suitable for use in URLs, DNS # An environment name is not necessarily suitable for use in URLs, DNS
# or other third-party contexts, so provide a slugified version. A slug has # or other third-party contexts, so provide a slugified version. A slug has
# the following properties: # the following properties:
......
...@@ -90,7 +90,7 @@ class ProjectFeature < ActiveRecord::Base ...@@ -90,7 +90,7 @@ class ProjectFeature < ActiveRecord::Base
when DISABLED when DISABLED
false false
when PRIVATE when PRIVATE
user && (project.team.member?(user) || user.admin?) user && (project.team.member?(user) || user.full_private_access?)
when ENABLED when ENABLED
true true
else else
......
...@@ -28,17 +28,6 @@ class PrometheusService < MonitoringService ...@@ -28,17 +28,6 @@ class PrometheusService < MonitoringService
'Prometheus monitoring' 'Prometheus monitoring'
end end
def help
<<-MD.strip_heredoc
Retrieves the Kubernetes node metrics `container_cpu_usage_seconds_total`
and `container_memory_usage_bytes` from the configured Prometheus server.
If you are not using [Auto-Deploy](https://docs.gitlab.com/ee/ci/autodeploy/index.html)
or have set up your own Prometheus server, an `environment` label is required on each metric to
[identify the Environment](https://docs.gitlab.com/ce/user/project/integrations/prometheus.html#metrics-and-labels).
MD
end
def self.to_param def self.to_param
'prometheus' 'prometheus'
end end
...@@ -50,6 +39,7 @@ class PrometheusService < MonitoringService ...@@ -50,6 +39,7 @@ class PrometheusService < MonitoringService
name: 'api_url', name: 'api_url',
title: 'API URL', title: 'API URL',
placeholder: 'Prometheus API Base URL, like http://prometheus.example.com/', placeholder: 'Prometheus API Base URL, like http://prometheus.example.com/',
help: 'By default, Prometheus listens on ‘http://localhost:9090’. It’s not recommended to change the default address and port as this might affect or conflict with other services running on the GitLab server.',
required: true required: true
} }
] ]
...@@ -65,23 +55,34 @@ class PrometheusService < MonitoringService ...@@ -65,23 +55,34 @@ class PrometheusService < MonitoringService
end end
def environment_metrics(environment) def environment_metrics(environment)
with_reactive_cache(Gitlab::Prometheus::Queries::EnvironmentQuery.name, environment.id, &:itself) with_reactive_cache(Gitlab::Prometheus::Queries::EnvironmentQuery.name, environment.id, &method(:rename_data_to_metrics))
end end
def deployment_metrics(deployment) def deployment_metrics(deployment)
metrics = with_reactive_cache(Gitlab::Prometheus::Queries::DeploymentQuery.name, deployment.id, &:itself) metrics = with_reactive_cache(Gitlab::Prometheus::Queries::DeploymentQuery.name, deployment.id, &method(:rename_data_to_metrics))
metrics&.merge(deployment_time: created_at.to_i) || {} metrics&.merge(deployment_time: created_at.to_i) || {}
end end
def additional_environment_metrics(environment)
with_reactive_cache(Gitlab::Prometheus::Queries::AdditionalMetricsEnvironmentQuery.name, environment.id, &:itself)
end
def additional_deployment_metrics(deployment)
with_reactive_cache(Gitlab::Prometheus::Queries::AdditionalMetricsDeploymentQuery.name, deployment.id, &:itself)
end
def matched_metrics
with_reactive_cache(Gitlab::Prometheus::Queries::MatchedMetricsQuery.name, &:itself)
end
# Cache metrics for specific environment # Cache metrics for specific environment
def calculate_reactive_cache(query_class_name, *args) def calculate_reactive_cache(query_class_name, *args)
return unless active? && project && !project.pending_delete? return unless active? && project && !project.pending_delete?
metrics = Kernel.const_get(query_class_name).new(client).query(*args) data = Kernel.const_get(query_class_name).new(client).query(*args)
{ {
success: true, success: true,
metrics: metrics, data: data,
last_update: Time.now.utc last_update: Time.now.utc
} }
rescue Gitlab::PrometheusError => err rescue Gitlab::PrometheusError => err
...@@ -91,4 +92,11 @@ class PrometheusService < MonitoringService ...@@ -91,4 +92,11 @@ class PrometheusService < MonitoringService
def client def client
@prometheus ||= Gitlab::PrometheusClient.new(api_url: api_url) @prometheus ||= Gitlab::PrometheusClient.new(api_url: api_url)
end end
private
def rename_data_to_metrics(metrics)
metrics[:metrics] = metrics.delete :data
metrics
end
end end
...@@ -984,6 +984,12 @@ class User < ActiveRecord::Base ...@@ -984,6 +984,12 @@ class User < ActiveRecord::Base
self.admin = (new_level == 'admin') self.admin = (new_level == 'admin')
end end
# Does the user have access to all private groups & projects?
# Overridden in EE to also check auditor?
def full_private_access?
admin?
end
def update_two_factor_requirement def update_two_factor_requirement
periods = expanded_groups_requiring_two_factor_authentication.pluck(:two_factor_grace_period) periods = expanded_groups_requiring_two_factor_authentication.pluck(:two_factor_grace_period)
......
...@@ -18,5 +18,4 @@ ...@@ -18,5 +18,4 @@
- if current_user - if current_user
To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page. To see all merge requests you should visit #{link_to 'dashboard', merge_requests_dashboard_path} page.
.prepend-top-default = render 'shared/merge_requests'
= render 'shared/merge_requests'
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
= icon('caret-down') = icon('caret-down')
.dropdown-menu-nav.dropdown-menu-align-right .dropdown-menu-nav.dropdown-menu-align-right
%ul %ul
- if @group - if @group&.persisted?
- create_group_project = can?(current_user, :create_projects, @group) - create_group_project = can?(current_user, :create_projects, @group)
- create_group_subgroup = can?(current_user, :create_subgroup, @group) - create_group_subgroup = can?(current_user, :create_subgroup, @group)
- if create_group_project || create_group_subgroup - if create_group_project || create_group_subgroup
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
%li.divider %li.divider
%li.dropdown-bold-header GitLab %li.dropdown-bold-header GitLab
- if @project && @project.persisted? - if @project&.persisted?
- create_project_issue = can?(current_user, :create_issue, @project) - create_project_issue = can?(current_user, :create_issue, @project)
- merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project)) - merge_project = can?(current_user, :create_merge_request, @project) ? @project : (current_user && current_user.fork_of(@project))
- create_project_snippet = can?(current_user, :create_project_snippet, @project) - create_project_snippet = can?(current_user, :create_project_snippet, @project)
......
= render 'profiles/head' = render 'profiles/head'
= form_for @user, url: profile_path, method: :put, html: { multipart: true, class: "edit-user prepend-top-default" }, authenticity_token: true do |f| = bootstrap_form_for @user, url: profile_path, method: :put, html: { multipart: true, class: 'edit-user prepend-top-default' }, authenticity_token: true do |f|
= form_errors(@user) = form_errors(@user)
.row .row
...@@ -11,11 +11,11 @@ ...@@ -11,11 +11,11 @@
- if @user.avatar? - if @user.avatar?
You can change your avatar here You can change your avatar here
- if gravatar_enabled? - if gravatar_enabled?
or remove the current avatar to revert to #{link_to Gitlab.config.gravatar.host, "http://" + Gitlab.config.gravatar.host} or remove the current avatar to revert to #{link_to Gitlab.config.gravatar.host, 'http://' + Gitlab.config.gravatar.host}
- else - else
You can upload an avatar here You can upload an avatar here
- if gravatar_enabled? - if gravatar_enabled?
or change it at #{link_to Gitlab.config.gravatar.host, "http://" + Gitlab.config.gravatar.host} or change it at #{link_to Gitlab.config.gravatar.host, 'http://' + Gitlab.config.gravatar.host}
.col-lg-9 .col-lg-9
.clearfix.avatar-image.append-bottom-default .clearfix.avatar-image.append-bottom-default
= link_to avatar_icon(@user, 400), target: '_blank', rel: 'noopener noreferrer' do = link_to avatar_icon(@user, 400), target: '_blank', rel: 'noopener noreferrer' do
...@@ -26,12 +26,12 @@ ...@@ -26,12 +26,12 @@
%a.btn.js-choose-user-avatar-button %a.btn.js-choose-user-avatar-button
Browse file... Browse file...
%span.avatar-file-name.prepend-left-default.js-avatar-filename No file chosen %span.avatar-file-name.prepend-left-default.js-avatar-filename No file chosen
= f.file_field :avatar, class: "js-user-avatar-input hidden", accept: "image/*" = f.file_field_without_bootstrap :avatar, class: 'js-user-avatar-input hidden', accept: 'image/*'
.help-block .help-block
The maximum file size allowed is 200KB. The maximum file size allowed is 200KB.
- if @user.avatar? - if @user.avatar?
%hr %hr
= link_to 'Remove avatar', profile_avatar_path, data: { confirm: "Avatar will be removed. Are you sure?" }, method: :delete, class: "btn btn-gray" = link_to 'Remove avatar', profile_avatar_path, data: { confirm: 'Avatar will be removed. Are you sure?' }, method: :delete, class: 'btn btn-gray'
%hr %hr
.row .row
.col-lg-3.profile-settings-sidebar .col-lg-3.profile-settings-sidebar
...@@ -43,91 +43,50 @@ ...@@ -43,91 +43,50 @@
Some options are unavailable for LDAP accounts Some options are unavailable for LDAP accounts
.col-lg-9 .col-lg-9
.row .row
.form-group.col-md-9 = f.text_field :name, required: true, wrapper: { class: 'col-md-9' },
= f.label :name, class: "label-light" help: 'Enter your name, so people you know can recognize you.'
= f.text_field :name, class: "form-control", required: true = f.text_field :id, readonly: true, label: 'User ID', wrapper: { class: 'col-md-3' }
%span.help-block Enter your name, so people you know can recognize you.
.form-group.col-md-3 - if @user.external_email?
= f.label :id, class: 'label-light' do = f.text_field :email, required: true, readonly: true, help: 'Your email address was automatically set based on your #{email_provider_label} account.'
User ID - else
= f.text_field :id, class: 'form-control', readonly: true = f.text_field :email, required: true, value: (@user.email unless @user.temp_oauth_email?),
help: user_email_help_text(@user)
= f.select :public_email, options_for_select(@user.all_emails, selected: @user.public_email),
.form-group { help: 'This email will be displayed on your public profile.', include_blank: 'Do not show on profile' },
= f.label :email, class: "label-light" control_class: 'select2'
- if @user.external_email? = f.select :preferred_language, Gitlab::I18n::AVAILABLE_LANGUAGES.map { |value, label| [label, value] },
= f.text_field :email, class: "form-control", required: true, readonly: true { help: 'This feature is experimental and translations are not complete yet.' },
%span.help-block.light control_class: 'select2'
Your email address was automatically set based on your #{email_provider_label} account. = f.text_field :skype
- else = f.text_field :linkedin
- if @user.temp_oauth_email? = f.text_field :twitter
= f.text_field :email, class: "form-control", required: true, value: nil = f.text_field :website_url, label: 'Website'
- else = f.text_field :location
= f.text_field :email, class: "form-control", required: true = f.text_field :organization
- if @user.unconfirmed_email.present? = f.text_area :bio, rows: 4, maxlength: 250, help: 'Tell us about yourself in fewer than 250 characters.'
%span.help-block
Please click the link in the confirmation email before continuing. It was sent to
= succeed "." do
%strong= @user.unconfirmed_email
%p
= link_to "Resend confirmation e-mail", user_confirmation_path(user: { email: @user.unconfirmed_email }), method: :post
- else
%span.help-block We also use email for avatar detection if no avatar is uploaded.
.form-group
= f.label :public_email, class: "label-light"
= f.select :public_email, options_for_select(@user.all_emails, selected: @user.public_email), { include_blank: 'Do not show on profile' }, class: "select2"
%span.help-block This email will be displayed on your public profile.
.form-group
= f.label :preferred_language, class: "label-light"
= f.select :preferred_language, Gitlab::I18n::AVAILABLE_LANGUAGES.map { |value, label| [label, value] },
{}, class: "select2"
%span.help-block This feature is experimental and translations are not complete yet.
.form-group
= f.label :skype, class: "label-light"
= f.text_field :skype, class: "form-control"
.form-group
= f.label :linkedin, class: "label-light"
= f.text_field :linkedin, class: "form-control"
.form-group
= f.label :twitter, class: "label-light"
= f.text_field :twitter, class: "form-control"
.form-group
= f.label :website_url, 'Website', class: "label-light"
= f.text_field :website_url, class: "form-control"
.form-group
= f.label :location, 'Location', class: "label-light"
= f.text_field :location, class: "form-control"
.form-group
= f.label :organization, 'Organization', class: "label-light"
= f.text_field :organization, class: "form-control"
.form-group
= f.label :bio, class: "label-light"
= f.text_area :bio, rows: 4, class: "form-control", maxlength: 250
%span.help-block Tell us about yourself in fewer than 250 characters.
.prepend-top-default.append-bottom-default .prepend-top-default.append-bottom-default
= f.submit 'Update profile settings', class: "btn btn-success" = f.submit 'Update profile settings', class: 'btn btn-success'
= link_to "Cancel", user_path(current_user), class: "btn btn-cancel" = link_to 'Cancel', user_path(current_user), class: 'btn btn-cancel'
.modal.modal-profile-crop .modal.modal-profile-crop
.modal-dialog .modal-dialog
.modal-content .modal-content
.modal-header .modal-header
%button.close{ :type => "button", :'data-dismiss' => "modal" } %button.close{ type: 'button', 'data-dismiss': 'modal' }
%span %span
&times; &times;
%h4.modal-title %h4.modal-title
Position and size your new avatar Position and size your new avatar
.modal-body .modal-body
.profile-crop-image-container .profile-crop-image-container
%img.modal-profile-crop-image{ alt: "Avatar cropper" } %img.modal-profile-crop-image{ alt: 'Avatar cropper' }
.crop-controls .crop-controls
.btn-group .btn-group
%button.btn.btn-primary{ data: { method: "zoom", option: "0.1" } } %button.btn.btn-primary{ data: { method: 'zoom', option: '0.1' } }
%span.fa.fa-search-plus %span.fa.fa-search-plus
%button.btn.btn-primary{ data: { method: "zoom", option: "-0.1" } } %button.btn.btn-primary{ data: { method: 'zoom', option: '-0.1' } }
%span.fa.fa-search-minus %span.fa.fa-search-minus
.modal-footer .modal-footer
%button.btn.btn-primary.js-upload-user-avatar{ :type => "button" } %button.btn.btn-primary.js-upload-user-avatar{ type: 'button' }
Set new profile picture Set new profile picture
= link_to namespace_project_find_file_path(@project.namespace, @project, @ref), class: 'btn btn-grouped shortcuts-find-file', rel: 'nofollow' do = link_to namespace_project_find_file_path(@project.namespace, @project, @ref), class: 'btn shortcuts-find-file', rel: 'nofollow' do
= icon('search') = icon('search')
%span= _('Find file') %span= _('Find file')
- blame = local_assigns.fetch(:blame, false) - blame = local_assigns.fetch(:blame, false)
.nav-block .nav-block
.tree-ref-container
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'blob', path: @path
%ul.breadcrumb.repo-breadcrumb
%li
= link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
= @project.path
- path_breadcrumbs do |title, path|
- title = truncate(title, length: 40)
%li
- if path == @path
= link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@ref, path)) do
%strong= title
- else
= link_to title, namespace_project_tree_path(@project.namespace, @project, tree_join(@ref, path))
.tree-controls .tree-controls
= render 'projects/find_file_link' = render 'projects/find_file_link'
.btn-group.prepend-left-10{ role: "group" }< .btn-group{ role: "group" }<
-# only show normal/blame view links for text files -# only show normal/blame view links for text files
- if blob.readable_text? - if blob.readable_text?
- if blame - if blame
...@@ -18,19 +35,3 @@ ...@@ -18,19 +35,3 @@
= link_to 'Permalink', namespace_project_blob_path(@project.namespace, @project, = link_to 'Permalink', namespace_project_blob_path(@project.namespace, @project,
tree_join(@commit.sha, @path)), class: 'btn js-data-file-blob-permalink-url' tree_join(@commit.sha, @path)), class: 'btn js-data-file-blob-permalink-url'
.tree-ref-holder
= render 'shared/ref_switcher', destination: 'blob', path: @path
%ul.breadcrumb.repo-breadcrumb
%li
= link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
= @project.path
- path_breadcrumbs do |title, path|
- title = truncate(title, length: 40)
%li
- if path == @path
= link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@ref, path)) do
%strong= title
- else
= link_to title, namespace_project_tree_path(@project.namespace, @project, tree_join(@ref, path))
- @no_container = true - @no_container = true
- container_class = !fluid_layout && diff_view == :inline ? 'container-limited' : '' - container_class = !fluid_layout && diff_view == :inline ? 'container-limited' : ''
- limited_container_width = fluid_layout || diff_view == :inline ? '' : 'limit-container-width' - limited_container_width = fluid_layout ? '' : 'limit-container-width'
- page_title "#{@commit.title} (#{@commit.short_id})", "Commits" - page_title "#{@commit.title} (#{@commit.short_id})", "Commits"
- page_description @commit.description - page_description @commit.description
= render "projects/commits/head" = render "projects/commits/head"
...@@ -13,7 +13,8 @@ ...@@ -13,7 +13,8 @@
.block-connector .block-connector
= render "projects/diffs/diffs", diffs: @diffs, environment: @environment = render "projects/diffs/diffs", diffs: @diffs, environment: @environment
= render "shared/notes/notes_with_form", :autocomplete => true .limited-width-notes
- if can_collaborate_with_project? = render "shared/notes/notes_with_form", :autocomplete => true
- %w(revert cherry-pick).each do |type| - if can_collaborate_with_project?
= render "projects/commit/change", type: type, commit: @commit, title: @commit.title - %w(revert cherry-pick).each do |type|
= render "projects/commit/change", type: type, commit: @commit, title: @commit.title
...@@ -3,8 +3,8 @@ ...@@ -3,8 +3,8 @@
- commits.chunk { |c| c.committed_date.in_time_zone.to_date }.each do |day, commits| - commits.chunk { |c| c.committed_date.in_time_zone.to_date }.each do |day, commits|
%li.commit-header.js-commit-header{ data: { day: day } } %li.commit-header.js-commit-header{ data: { day: day } }
%span.day= day.strftime('%d %b, %Y') %span.day= l(day, format: '%d %b, %Y')
%span.commits-count= pluralize(commits.count, 'commit') %span.commits-count= n_("%d commit", "%d commits", commits.count) % commits.count
%li.commits-row{ data: { day: day } } %li.commits-row{ data: { day: day } }
%ul.content-list.commit-list %ul.content-list.commit-list
...@@ -12,4 +12,4 @@ ...@@ -12,4 +12,4 @@
- if hidden > 0 - if hidden > 0
%li.alert.alert-warning %li.alert.alert-warning
#{number_with_delimiter(hidden)} additional commits have been omitted to prevent performance issues. = n_('%d additional commit has been omitted to prevent performance issues.', '%d additional commits have been omitted to prevent performance issues.', hidden) % number_with_delimiter(hidden)
- @no_container = true - @no_container = true
- page_title "Commits", @ref - page_title _("Commits"), @ref
= content_for :meta_tags do = content_for :meta_tags do
= auto_discovery_link_tag(:atom, namespace_project_commits_url(@project.namespace, @project, @ref, rss_url_options), title: "#{@project.name}:#{@ref} commits") = auto_discovery_link_tag(:atom, namespace_project_commits_url(@project.namespace, @project, @ref, rss_url_options), title: "#{@project.name}:#{@ref} commits")
...@@ -18,16 +18,16 @@ ...@@ -18,16 +18,16 @@
.block-controls.hidden-xs.hidden-sm .block-controls.hidden-xs.hidden-sm
- if @merge_request.present? - if @merge_request.present?
.control .control
= link_to "View open merge request", namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'btn' = link_to _("View open merge request"), namespace_project_merge_request_path(@project.namespace, @project, @merge_request), class: 'btn'
- elsif create_mr_button?(@repository.root_ref, @ref) - elsif create_mr_button?(@repository.root_ref, @ref)
.control .control
= link_to "Create merge request", create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success' = link_to _("Create merge request"), create_mr_path(@repository.root_ref, @ref), class: 'btn btn-success'
.control .control
= form_tag(namespace_project_commits_path(@project.namespace, @project, @id), method: :get, class: 'commits-search-form') do = form_tag(namespace_project_commits_path(@project.namespace, @project, @id), method: :get, class: 'commits-search-form') do
= search_field_tag :search, params[:search], { placeholder: 'Filter by commit message', id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false } = search_field_tag :search, params[:search], { placeholder: _('Filter by commit message'), id: 'commits-search', class: 'form-control search-text-input input-short', spellcheck: false }
.control .control
= link_to namespace_project_commits_path(@project.namespace, @project, @ref, rss_url_options), title: "Commits feed", class: 'btn' do = link_to namespace_project_commits_path(@project.namespace, @project, @ref, rss_url_options), title: _("Commits feed"), class: 'btn' do
= icon("rss") = icon("rss")
%div{ id: dom_id(@project) } %div{ id: dom_id(@project) }
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
%h4 %h4
Deploy Keys Deploy Keys
%button.btn.js-settings-toggle %button.btn.js-settings-toggle
= expanded ? 'Close' : 'Expand' = expanded ? 'Collapse' : 'Expand'
%p %p
Deploy keys allow read-only or read-write (if enabled) access to your repository. Deploy keys can be used for CI, staging or production servers. You can create a deploy key or add an existing one. Deploy keys allow read-only or read-write (if enabled) access to your repository. Deploy keys can be used for CI, staging or production servers. You can create a deploy key or add an existing one.
.settings-content.no-animate{ class: ('expanded' if expanded) } .settings-content.no-animate{ class: ('expanded' if expanded) }
......
...@@ -3,24 +3,25 @@ ...@@ -3,24 +3,25 @@
.table-mobile-header{ role: 'rowheader' } ID .table-mobile-header{ role: 'rowheader' } ID
%strong.table-mobile-content ##{deployment.iid} %strong.table-mobile-content ##{deployment.iid}
.table-section.section-40{ role: 'gridcell' } .table-section.section-30{ role: 'gridcell' }
.table-mobile-header{ role: 'rowheader' } Commit .table-mobile-header{ role: 'rowheader' } Commit
= render 'projects/deployments/commit', deployment: deployment = render 'projects/deployments/commit', deployment: deployment
.table-section.section-15.build-column{ role: 'gridcell' } .table-section.section-25.build-column{ role: 'gridcell' }
.table-mobile-header{ role: 'rowheader' } Job .table-mobile-header{ role: 'rowheader' } Job
- if deployment.deployable - if deployment.deployable
= link_to [@project.namespace.becomes(Namespace), @project, deployment.deployable], class: 'build-link table-mobile-content' do .table-mobile-content
#{deployment.deployable.name} (##{deployment.deployable.id}) = link_to [@project.namespace.becomes(Namespace), @project, deployment.deployable], class: 'build-link' do
- if deployment.user #{deployment.deployable.name} (##{deployment.deployable.id})
by - if deployment.user
= user_avatar(user: deployment.user, size: 20) by
= user_avatar(user: deployment.user, size: 20)
.table-section.section-15{ role: 'gridcell' } .table-section.section-15{ role: 'gridcell' }
.table-mobile-header{ role: 'rowheader' } Created .table-mobile-header{ role: 'rowheader' } Created
%span.table-mobile-content= time_ago_with_tooltip(deployment.created_at) %span.table-mobile-content= time_ago_with_tooltip(deployment.created_at)
.table-section.section-20.table-button-footer{ role: 'gridcell' } .table-section.section-20.table-button-footer{ role: 'gridcell' }
.btn-group.table-action-button .btn-group.table-action-buttons
= render 'projects/deployments/actions', deployment: deployment = render 'projects/deployments/actions', deployment: deployment
= render 'projects/deployments/rollback', deployment: deployment = render 'projects/deployments/rollback', deployment: deployment
- @content_class = "limit-container-width" unless fluid_layout
= render "projects/settings/head" = render "projects/settings/head"
.project-edit-container .project-edit-container
.row.prepend-top-default .row.prepend-top-default
.col-lg-3.profile-settings-sidebar .col-lg-4.profile-settings-sidebar
%h4.prepend-top-0 %h4.prepend-top-0
Project settings Project settings
.col-lg-9 .col-lg-8
.project-edit-errors .project-edit-errors
= form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "edit-project" }, authenticity_token: true do |f| = form_for [@project.namespace.becomes(Namespace), @project], remote: true, html: { multipart: true, class: "edit-project" }, authenticity_token: true do |f|
%fieldset %fieldset
...@@ -39,66 +41,66 @@ ...@@ -39,66 +41,66 @@
Sharing &amp; Permissions Sharing &amp; Permissions
.form_group.prepend-top-20.sharing-and-permissions .form_group.prepend-top-20.sharing-and-permissions
.row.js-visibility-select .row.js-visibility-select
.col-md-9 .col-md-8
.label-light .label-light
= label_tag :project_visibility, 'Project Visibility', class: 'label-light', for: :project_visibility_level = label_tag :project_visibility, 'Project Visibility', class: 'label-light', for: :project_visibility_level
= link_to icon('question-circle'), help_page_path("public_access/public_access") = link_to icon('question-circle'), help_page_path("public_access/public_access")
%span.help-block %span.help-block
.col-md-3.visibility-select-container .col-md-4.visibility-select-container
= render('projects/visibility_select', model_method: :visibility_level, form: f, selected_level: @project.visibility_level) = render('projects/visibility_select', model_method: :visibility_level, form: f, selected_level: @project.visibility_level)
= f.fields_for :project_feature do |feature_fields| = f.fields_for :project_feature do |feature_fields|
%fieldset.features %fieldset.features
.row .row
.col-md-9.project-feature .col-md-8.project-feature
= feature_fields.label :repository_access_level, "Repository", class: 'label-light' = feature_fields.label :repository_access_level, "Repository", class: 'label-light'
%span.help-block View and edit files in this project %span.help-block View and edit files in this project
.col-md-3.js-repo-access-level .col-md-4.js-repo-access-level
= project_feature_access_select(:repository_access_level) = project_feature_access_select(:repository_access_level)
.row .row
.col-md-9.project-feature.nested .col-md-8.project-feature.nested
= feature_fields.label :merge_requests_access_level, "Merge requests", class: 'label-light' = feature_fields.label :merge_requests_access_level, "Merge requests", class: 'label-light'
%span.help-block Submit changes to be merged upstream %span.help-block Submit changes to be merged upstream
.col-md-3 .col-md-4
= project_feature_access_select(:merge_requests_access_level) = project_feature_access_select(:merge_requests_access_level)
.row .row
.col-md-9.project-feature.nested .col-md-8.project-feature.nested
= feature_fields.label :builds_access_level, "Pipelines", class: 'label-light' = feature_fields.label :builds_access_level, "Pipelines", class: 'label-light'
%span.help-block Build, test, and deploy your changes %span.help-block Build, test, and deploy your changes
.col-md-3 .col-md-4
= project_feature_access_select(:builds_access_level) = project_feature_access_select(:builds_access_level)
.row .row
.col-md-9.project-feature .col-md-8.project-feature
= feature_fields.label :snippets_access_level, "Snippets", class: 'label-light' = feature_fields.label :snippets_access_level, "Snippets", class: 'label-light'
%span.help-block Share code pastes with others out of Git repository %span.help-block Share code pastes with others out of Git repository
.col-md-3 .col-md-4
= project_feature_access_select(:snippets_access_level) = project_feature_access_select(:snippets_access_level)
.row .row
.col-md-9.project-feature .col-md-8.project-feature
= feature_fields.label :issues_access_level, "Issues", class: 'label-light' = feature_fields.label :issues_access_level, "Issues", class: 'label-light'
%span.help-block Lightweight issue tracking system for this project %span.help-block Lightweight issue tracking system for this project
.col-md-3 .col-md-4
= project_feature_access_select(:issues_access_level) = project_feature_access_select(:issues_access_level)
.row .row
.col-md-9.project-feature .col-md-8.project-feature
= feature_fields.label :wiki_access_level, "Wiki", class: 'label-light' = feature_fields.label :wiki_access_level, "Wiki", class: 'label-light'
%span.help-block Pages for project documentation %span.help-block Pages for project documentation
.col-md-3 .col-md-4
= project_feature_access_select(:wiki_access_level) = project_feature_access_select(:wiki_access_level)
.form-group .form-group
= render 'shared/allow_request_access', form: f = render 'shared/allow_request_access', form: f
- if Gitlab.config.lfs.enabled && current_user.admin? - if Gitlab.config.lfs.enabled && current_user.admin?
.row.js-lfs-enabled .row.js-lfs-enabled
.col-md-9 .col-md-8
= f.label :lfs_enabled, 'LFS', class: 'label-light' = f.label :lfs_enabled, 'LFS', class: 'label-light'
%span.help-block %span.help-block
Git Large File Storage Git Large File Storage
= link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs') = link_to icon('question-circle'), help_page_path('workflow/lfs/manage_large_binaries_with_git_lfs')
.col-md-3 .col-md-4
.select-wrapper .select-wrapper
= f.select :lfs_enabled, [%w(Enabled true), %w(Disabled false)], {}, selected: @project.lfs_enabled?, class: 'pull-right form-control project-repo-select select-control', data: { field: 'lfs_enabled' } = f.select :lfs_enabled, [%w(Enabled true), %w(Disabled false)], {}, selected: @project.lfs_enabled?, class: 'pull-right form-control project-repo-select select-control', data: { field: 'lfs_enabled' }
= icon('chevron-down') = icon('chevron-down')
...@@ -138,19 +140,19 @@ ...@@ -138,19 +140,19 @@
.row.prepend-top-default .row.prepend-top-default
%hr %hr
.row.prepend-top-default .row.prepend-top-default
.col-lg-3 .col-lg-4
%h4.prepend-top-0 %h4.prepend-top-0
Housekeeping Housekeeping
%p.append-bottom-0 %p.append-bottom-0
%p %p
Runs a number of housekeeping tasks within the current repository, Runs a number of housekeeping tasks within the current repository,
such as compressing file revisions and removing unreachable objects. such as compressing file revisions and removing unreachable objects.
.col-lg-9 .col-lg-8
= link_to 'Housekeeping', housekeeping_namespace_project_path(@project.namespace, @project), = link_to 'Housekeeping', housekeeping_namespace_project_path(@project.namespace, @project),
method: :post, class: "btn btn-default" method: :post, class: "btn btn-default"
%hr %hr
.row.prepend-top-default .row.prepend-top-default
.col-lg-3 .col-lg-4
%h4.prepend-top-0 %h4.prepend-top-0
Export project Export project
%p.append-bottom-0 %p.append-bottom-0
...@@ -159,7 +161,7 @@ ...@@ -159,7 +161,7 @@
%p %p
Once the exported file is ready, you will receive a notification email with a download link. Once the exported file is ready, you will receive a notification email with a download link.
.col-lg-9 .col-lg-8
- if @project.export_project_path - if @project.export_project_path
= link_to 'Download export', download_export_namespace_project_path(@project.namespace, @project), = link_to 'Download export', download_export_namespace_project_path(@project.namespace, @project),
...@@ -190,7 +192,7 @@ ...@@ -190,7 +192,7 @@
- if can? current_user, :archive_project, @project - if can? current_user, :archive_project, @project
%hr %hr
.row.prepend-top-default .row.prepend-top-default
.col-lg-3 .col-lg-4
%h4.warning-title.prepend-top-0 %h4.warning-title.prepend-top-0
- if @project.archived? - if @project.archived?
Unarchive project Unarchive project
...@@ -201,7 +203,7 @@ ...@@ -201,7 +203,7 @@
Unarchiving the project will mark its repository as active. The project can be committed to. Unarchiving the project will mark its repository as active. The project can be committed to.
- else - else
Archiving the project will mark its repository as read-only. It is hidden from the dashboard and doesn't show up in searches. Archiving the project will mark its repository as read-only. It is hidden from the dashboard and doesn't show up in searches.
.col-lg-9 .col-lg-8
- if @project.archived? - if @project.archived?
%p %p
%strong Once active this project shows up in the search and on the dashboard. %strong Once active this project shows up in the search and on the dashboard.
...@@ -216,10 +218,10 @@ ...@@ -216,10 +218,10 @@
method: :post, class: "btn btn-warning" method: :post, class: "btn btn-warning"
%hr %hr
.row.prepend-top-default .row.prepend-top-default
.col-lg-3 .col-lg-4
%h4.prepend-top-0.warning-title %h4.prepend-top-0.warning-title
Rename repository Rename repository
.col-lg-9 .col-lg-8
= render 'projects/errors' = render 'projects/errors'
= form_for([@project.namespace.becomes(Namespace), @project]) do |f| = form_for([@project.namespace.becomes(Namespace), @project]) do |f|
.form-group.project_name_holder .form-group.project_name_holder
...@@ -244,12 +246,12 @@ ...@@ -244,12 +246,12 @@
- if can?(current_user, :change_namespace, @project) - if can?(current_user, :change_namespace, @project)
%hr %hr
.row.prepend-top-default .row.prepend-top-default
.col-lg-3 .col-lg-4
%h4.prepend-top-0.danger-title %h4.prepend-top-0.danger-title
Transfer project to new group Transfer project to new group
%p.append-bottom-0 %p.append-bottom-0
Please select the group you want to transfer this project to in the dropdown to the right. Please select the group you want to transfer this project to in the dropdown to the right.
.col-lg-9 .col-lg-8
= form_for([@project.namespace.becomes(Namespace), @project], url: transfer_namespace_project_path(@project.namespace, @project), method: :put, remote: true, html: { class: 'js-project-transfer-form' } ) do |f| = form_for([@project.namespace.becomes(Namespace), @project], url: transfer_namespace_project_path(@project.namespace, @project), method: :put, remote: true, html: { class: 'js-project-transfer-form' } ) do |f|
.form-group .form-group
= label_tag :new_namespace_id, nil, class: 'label-light' do = label_tag :new_namespace_id, nil, class: 'label-light' do
...@@ -265,7 +267,7 @@ ...@@ -265,7 +267,7 @@
- if @project.forked? && can?(current_user, :remove_fork_project, @project) - if @project.forked? && can?(current_user, :remove_fork_project, @project)
%hr %hr
.row.prepend-top-default.append-bottom-default .row.prepend-top-default.append-bottom-default
.col-lg-3 .col-lg-4
%h4.prepend-top-0.danger-title %h4.prepend-top-0.danger-title
Remove fork relationship Remove fork relationship
%p.append-bottom-0 %p.append-bottom-0
...@@ -273,7 +275,7 @@ ...@@ -273,7 +275,7 @@
This will remove the fork relationship to source project This will remove the fork relationship to source project
= succeed "." do = succeed "." do
= link_to @project.forked_from_project.name_with_namespace, project_path(@project.forked_from_project) = link_to @project.forked_from_project.name_with_namespace, project_path(@project.forked_from_project)
.col-lg-9 .col-lg-8
= form_for([@project.namespace.becomes(Namespace), @project], url: remove_fork_namespace_project_path(@project.namespace, @project), method: :delete, remote: true, html: { class: 'transfer-project' }) do |f| = form_for([@project.namespace.becomes(Namespace), @project], url: remove_fork_namespace_project_path(@project.namespace, @project), method: :delete, remote: true, html: { class: 'transfer-project' }) do |f|
%p %p
%strong Once removed, the fork relationship cannot be restored and you will no longer be able to send merge requests to the source. %strong Once removed, the fork relationship cannot be restored and you will no longer be able to send merge requests to the source.
...@@ -281,12 +283,12 @@ ...@@ -281,12 +283,12 @@
- if can?(current_user, :remove_project, @project) - if can?(current_user, :remove_project, @project)
%hr %hr
.row.prepend-top-default.append-bottom-default .row.prepend-top-default.append-bottom-default
.col-lg-3 .col-lg-4
%h4.prepend-top-0.danger-title %h4.prepend-top-0.danger-title
Remove project Remove project
%p.append-bottom-0 %p.append-bottom-0
Removing the project will delete its repository and all related resources including issues, merge requests etc. Removing the project will delete its repository and all related resources including issues, merge requests etc.
.col-lg-9 .col-lg-8
= form_tag(namespace_project_path(@project.namespace, @project), method: :delete) do = form_tag(namespace_project_path(@project.namespace, @project), method: :delete) do
%p %p
%strong Removed projects cannot be restored! %strong Removed projects cannot be restored!
......
.row.prepend-top-default .row.prepend-top-default
.col-lg-3 .col-lg-4
%h4.prepend-top-0 %h4.prepend-top-0
= page_title = page_title
%p %p
#{link_to 'Webhooks', help_page_path('user/project/integrations/webhooks')} can be #{link_to 'Webhooks', help_page_path('user/project/integrations/webhooks')} can be
used for binding events when something is happening within the project. used for binding events when something is happening within the project.
.col-lg-9.append-bottom-default .col-lg-8.append-bottom-default
= form_for @hook, as: :hook, url: polymorphic_path([@project.namespace.becomes(Namespace), @project, :hooks]) do |f| = form_for @hook, as: :hook, url: polymorphic_path([@project.namespace.becomes(Namespace), @project, :hooks]) do |f|
= render partial: 'shared/web_hooks/form', locals: { form: f, hook: @hook } = render partial: 'shared/web_hooks/form', locals: { form: f, hook: @hook }
= f.submit 'Add webhook', class: 'btn btn-create' = f.submit 'Add webhook', class: 'btn btn-create'
......
%div{ class: badge.title.gsub(' ', '-') } %div{ class: badge.title.gsub(' ', '-') }
.col-lg-3.profile-settings-sidebar .col-lg-4.profile-settings-sidebar
%h4.prepend-top-0 %h4.prepend-top-0
= badge.title.capitalize = badge.title.capitalize
.col-lg-9 .col-lg-8
.prepend-top-10 .prepend-top-10
.panel.panel-default .panel.panel-default
.panel-heading .panel-heading
......
.row.prepend-top-default .row.prepend-top-default
.col-lg-3.profile-settings-sidebar .col-lg-4.profile-settings-sidebar
%h4.prepend-top-0 %h4.prepend-top-0
Pipelines Pipelines
.col-lg-9 .col-lg-8
= form_for @project, url: namespace_project_pipelines_settings_path(@project.namespace.becomes(Namespace), @project) do |f| = form_for @project, url: namespace_project_pipelines_settings_path(@project.namespace.becomes(Namespace), @project) do |f|
%fieldset.builds-feature %fieldset.builds-feature
- unless @repository.gitlab_ci_yml - unless @repository.gitlab_ci_yml
......
.row.prepend-top-default .row.prepend-top-default
.col-lg-3.settings-sidebar .col-lg-4.settings-sidebar
%h4.prepend-top-0 %h4.prepend-top-0
Project members Project members
- if can?(current_user, :admin_project_member, @project) - if can?(current_user, :admin_project_member, @project)
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
%i Masters %i Masters
or or
%i Owners %i Owners
.col-lg-9 .col-lg-8
.light .light
- if can?(current_user, :admin_project_member, @project) - if can?(current_user, :admin_project_member, @project)
%ul.nav-links.project-member-tabs{ role: 'tablist' } %ul.nav-links.project-member-tabs{ role: 'tablist' }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
%h4 %h4
Protected Branches Protected Branches
%button.btn.js-settings-toggle %button.btn.js-settings-toggle
= expanded ? 'Close' : 'Expand' = expanded ? 'Collapse' : 'Expand'
%p %p
Keep stable branches secure and force developers to use merge requests. Keep stable branches secure and force developers to use merge requests.
.settings-content.no-animate{ class: ('expanded' if expanded) } .settings-content.no-animate{ class: ('expanded' if expanded) }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
%h4 %h4
Protected Tags Protected Tags
%button.btn.js-settings-toggle %button.btn.js-settings-toggle
= expanded ? 'Close' : 'Expand' = expanded ? 'Collapse' : 'Expand'
%p %p
Limit access to creating and updating tags. Limit access to creating and updating tags.
.settings-content.no-animate{ class: ('expanded' if expanded) } .settings-content.no-animate{ class: ('expanded' if expanded) }
......
...@@ -23,3 +23,7 @@ ...@@ -23,3 +23,7 @@
- disabled_title = @service.disabled_title - disabled_title = @service.disabled_title
= link_to 'Cancel', namespace_project_settings_integrations_path(@project.namespace, @project), class: 'btn btn-cancel' = link_to 'Cancel', namespace_project_settings_integrations_path(@project.namespace, @project), class: 'btn btn-cancel'
- if lookup_context.template_exists?('show', "projects/services/#{@service.to_param}", true)
%hr
= render "projects/services/#{@service.to_param}/show"
.row.prepend-top-default.append-bottom-default .row.prepend-top-default.append-bottom-default
.col-lg-3 .col-lg-4
%h4.prepend-top-0 %h4.prepend-top-0
Project services Project services
%p Project services allow you to integrate GitLab with other applications %p Project services allow you to integrate GitLab with other applications
.col-lg-9 .col-lg-8
%table.table %table.table
%colgroup %colgroup
%col %col
......
- content_for :page_specific_javascripts do
= webpack_bundle_tag('prometheus_metrics')
.row.prepend-top-default.append-bottom-default.prometheus-metrics-monitoring.js-prometheus-metrics-monitoring
.col-lg-3
%h4.prepend-top-0
Metrics
%p
Metrics are automatically configured and monitored
based on a library of metrics from popular exporters.
= link_to 'More information', '#'
.col-lg-9
.panel.panel-default.js-panel-monitored-metrics{ data: { "active-metrics" => "#{namespace_project_prometheus_active_metrics_path(@project.namespace, @project, :json)}" } }
.panel-heading
%h3.panel-title
Monitored
%span.badge.js-monitored-count 0
.panel-body
.loading-metrics.text-center.js-loading-metrics
= icon('spinner spin 3x', class: 'metrics-load-spinner')
%p Finding and configuring metrics...
.empty-metrics.text-center.hidden.js-empty-metrics
= custom_icon('icon_empty_metrics')
%p No metrics are being monitored. To start monitoring, deploy to an environment.
= link_to project_environments_path(@project), title: 'View environments', class: 'btn btn-success' do
View environments
%ul.list-unstyled.metrics-list.hidden.js-metrics-list
.panel.panel-default.hidden.js-panel-missing-env-vars
.panel-heading
%h3.panel-title
= icon('caret-right lg fw', class: 'panel-toggle js-panel-toggle', 'aria-label' => 'Toggle panel')
Missing environment variable
%span.badge.js-env-var-count 0
.panel-body.hidden
.flash-container
.flash-notice
.flash-text
To set up automatic monitoring, add the environment variable
%code
$CI_ENVIRONMENT_SLUG
to exporter&rsquo;s queries.
= link_to 'More information', '#'
%ul.list-unstyled.metrics-list.js-missing-var-metrics-list
- @content_class = "limit-container-width" unless fluid_layout
- page_title "Pipelines" - page_title "Pipelines"
= render "projects/settings/head" = render "projects/settings/head"
......
- @content_class = "limit-container-width" unless fluid_layout
- page_title 'Integrations' - page_title 'Integrations'
= render "projects/settings/head" = render "projects/settings/head"
= render 'projects/hooks/index' = render 'projects/hooks/index'
......
- @content_class = "limit-container-width" unless fluid_layout
- page_title "Members" - page_title "Members"
= render "projects/settings/head" = render "projects/settings/head"
......
- @content_class = "limit-container-width limited-inner-width-container" unless fluid_layout
- page_title "#{@snippet.title} (#{@snippet.to_reference})", "Snippets" - page_title "#{@snippet.title} (#{@snippet.to_reference})", "Snippets"
= render 'shared/snippets/header' = render 'shared/snippets/header'
...@@ -9,4 +10,4 @@ ...@@ -9,4 +10,4 @@
.row-content-block.top-block.content-component-block .row-content-block.top-block.content-component-block
= render 'award_emoji/awards_block', awardable: @snippet, inline: true = render 'award_emoji/awards_block', awardable: @snippet, inline: true
#notes= render "shared/notes/notes_with_form", :autocomplete => true #notes.limited-width-notes= render "shared/notes/notes_with_form", :autocomplete => true
- if readme.rich_viewer - if readme.rich_viewer
%article.file-holder.readme-holder %article.file-holder.readme-holder{ class: ("limited-width-container" unless fluid_layout) }
.js-file-title.file-title .js-file-title.file-title
= blob_icon readme.mode, readme.name = blob_icon readme.mode, readme.name
= link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@ref, readme.path)) do = link_to namespace_project_blob_path(@project.namespace, @project, tree_join(@ref, readme.path)) do
......
.tree-controls .tree-ref-container
= render 'projects/find_file_link' .tree-ref-holder
= render 'shared/ref_switcher', destination: 'tree', path: @path
= link_to s_('Commits|History'), namespace_project_commits_path(@project.namespace, @project, @id), class: 'btn btn-grouped'
= render 'projects/buttons/download', project: @project, ref: @ref
.tree-ref-holder %ul.breadcrumb.repo-breadcrumb
= render 'shared/ref_switcher', destination: 'tree', path: @path
%ul.breadcrumb.repo-breadcrumb
%li
= link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
= @project.path
- path_breadcrumbs do |title, path|
%li %li
= link_to truncate(title, length: 40), namespace_project_tree_path(@project.namespace, @project, tree_join(@ref, path)) = link_to namespace_project_tree_path(@project.namespace, @project, @ref) do
= @project.path
- path_breadcrumbs do |title, path|
%li
= link_to truncate(title, length: 40), namespace_project_tree_path(@project.namespace, @project, tree_join(@ref, path))
- if current_user - if current_user
%li %li
- if !on_top_of_branch? - if !on_top_of_branch?
%span.btn.add-to-tree.disabled.has-tooltip{ title: _("You can only add files when you are on a branch"), data: { container: 'body' } } %span.btn.add-to-tree.disabled.has-tooltip{ title: _("You can only add files when you are on a branch"), data: { container: 'body' } }
= icon('plus')
- else
%span.dropdown
%a.dropdown-toggle.btn.add-to-tree{ href: '#', "data-toggle" => "dropdown" }
= icon('plus') = icon('plus')
%ul.dropdown-menu - else
- if can_edit_tree? %span.dropdown
%li %a.dropdown-toggle.btn.add-to-tree{ href: '#', "data-toggle" => "dropdown", "data-target" => ".add-to-tree-dropdown" }
= link_to namespace_project_new_blob_path(@project.namespace, @project, @id) do = icon('plus')
= icon('pencil fw') .add-to-tree-dropdown
#{ _('New file') } %ul.dropdown-menu
%li - if can_edit_tree?
= link_to '#modal-upload-blob', { 'data-target' => '#modal-upload-blob', 'data-toggle' => 'modal' } do %li
= icon('file fw') = link_to namespace_project_new_blob_path(@project.namespace, @project, @id) do
#{ _('Upload file') } = icon('pencil fw')
%li #{ _('New file') }
= link_to '#modal-create-new-dir', { 'data-target' => '#modal-create-new-dir', 'data-toggle' => 'modal' } do %li
= icon('folder fw') = link_to '#modal-upload-blob', { 'data-target' => '#modal-upload-blob', 'data-toggle' => 'modal' } do
#{ _('New directory') } = icon('file fw')
- elsif can?(current_user, :fork_project, @project) #{ _('Upload file') }
%li %li
- continue_params = { to: namespace_project_new_blob_path(@project.namespace, @project, @id), = link_to '#modal-create-new-dir', { 'data-target' => '#modal-create-new-dir', 'data-toggle' => 'modal' } do
notice: edit_in_new_fork_notice, = icon('folder fw')
notice_now: edit_in_new_fork_notice_now } #{ _('New directory') }
- fork_path = namespace_project_forks_path(@project.namespace, @project, namespace_key: current_user.namespace.id, - elsif can?(current_user, :fork_project, @project)
continue: continue_params) %li
= link_to fork_path, method: :post do - continue_params = { to: namespace_project_new_blob_path(@project.namespace, @project, @id),
= icon('pencil fw') notice: edit_in_new_fork_notice,
#{ _('New file') } notice_now: edit_in_new_fork_notice_now }
- fork_path = namespace_project_forks_path(@project.namespace, @project, namespace_key: current_user.namespace.id,
continue: continue_params)
= link_to fork_path, method: :post do
= icon('pencil fw')
#{ _('New file') }
%li
- continue_params = { to: request.fullpath,
notice: edit_in_new_fork_notice + " Try to upload a file again.",
notice_now: edit_in_new_fork_notice_now }
- fork_path = namespace_project_forks_path(@project.namespace, @project, namespace_key: current_user.namespace.id,
continue: continue_params)
= link_to fork_path, method: :post do
= icon('file fw')
#{ _('Upload file') }
%li
- continue_params = { to: request.fullpath,
notice: edit_in_new_fork_notice + " Try to create a new directory again.",
notice_now: edit_in_new_fork_notice_now }
- fork_path = namespace_project_forks_path(@project.namespace, @project, namespace_key: current_user.namespace.id,
continue: continue_params)
= link_to fork_path, method: :post do
= icon('folder fw')
#{ _('New directory') }
%li.divider
%li %li
- continue_params = { to: request.fullpath, = link_to new_namespace_project_branch_path(@project.namespace, @project) do
notice: edit_in_new_fork_notice + " Try to upload a file again.", = icon('code-fork fw')
notice_now: edit_in_new_fork_notice_now } #{ _('New branch') }
- fork_path = namespace_project_forks_path(@project.namespace, @project, namespace_key: current_user.namespace.id,
continue: continue_params)
= link_to fork_path, method: :post do
= icon('file fw')
#{ _('Upload file') }
%li %li
- continue_params = { to: request.fullpath, = link_to new_namespace_project_tag_path(@project.namespace, @project) do
notice: edit_in_new_fork_notice + " Try to create a new directory again.", = icon('tags fw')
notice_now: edit_in_new_fork_notice_now } #{ _('New tag') }
- fork_path = namespace_project_forks_path(@project.namespace, @project, namespace_key: current_user.namespace.id,
continue: continue_params) .tree-controls
= link_to fork_path, method: :post do = render 'projects/find_file_link'
= icon('folder fw')
#{ _('New directory') }
%li.divider = link_to s_('Commits|History'), namespace_project_commits_path(@project.namespace, @project, @id), class: 'btn'
%li
= link_to new_namespace_project_branch_path(@project.namespace, @project) do = render 'projects/buttons/download', project: @project, ref: @ref
= icon('code-fork fw')
#{ _('New branch') }
%li
= link_to new_namespace_project_tag_path(@project.namespace, @project) do
= icon('tags fw')
#{ _('New tag') }
.row.prepend-top-default.append-bottom-default.triggers-container .row.prepend-top-default.append-bottom-default.triggers-container
.col-lg-3 .col-lg-4
= render "projects/triggers/content" = render "projects/triggers/content"
.col-lg-9 .col-lg-8
.panel.panel-default .panel.panel-default
.panel-heading .panel-heading
%h4.panel-title %h4.panel-title
......
.row.prepend-top-default.append-bottom-default .row.prepend-top-default.append-bottom-default
.col-lg-3 .col-lg-4
= render "projects/variables/content" = render "projects/variables/content"
.col-lg-9 .col-lg-8
%h5.prepend-top-0 %h5.prepend-top-0
Add a variable Add a variable
= render "projects/variables/form", btn_text: "Add new variable" = render "projects/variables/form", btn_text: "Add new variable"
......
<svg xmlns="http://www.w3.org/2000/svg" width="64" height="64" viewBox="0 0 64 64">
<g fill="#E5E5E5">
<path d="M32 64C30.8954305 64 30 63.1045695 30 62 30 60.8954305 30.8954305 60 32 60 33.8894444 60 35.7536611 59.8131396 37.574335 59.4454933 38.6570511 59.2268618 39.7120017 59.9273408 39.9306331 61.0100569 40.1492646 62.0927729 39.4487856 63.1477235 38.3660695 63.366355 36.285133 63.7865558 34.1557023 64 32 64zM49.2301062 58.9696428C51.0302775 57.8173242 52.7114504 56.4871355 54.247711 55.0008916 55.0415758 54.232873 55.0625283 52.9667164 54.2945097 52.1728516 53.5264912 51.3789869 52.2603346 51.3580344 51.4664698 52.1260529 50.1212672 53.4274592 48.6493395 54.5920875 47.0736141 55.6007347 46.1433158 56.1962335 45.8719072 57.4331365 46.4674061 58.3634348 47.0629049 59.2937331 48.2998079 59.5651416 49.2301062 58.9696428zM61.0426034 45.4531856C61.9412068 43.5163476 62.6441937 41.4911051 63.1388045 39.4034279 63.393449 38.3286117 62.7285685 37.2508708 61.6537523 36.9962262 60.5789361 36.7415816 59.5011952 37.4064621 59.2465506 38.4812784 58.8141946 40.3061875 58.1997219 42.0764286 57.4141077 43.7697311 56.9492346 44.7717126 57.3846469 45.9608331 58.3866284 46.4257062 59.3886098 46.8905793 60.5777303 46.455167 61.0426034 45.4531856zM63.7270657 27.8034151C63.4476841 25.6718707 62.9558906 23.5863203 62.2616468 21.5714028 61.9018246 20.527084 60.7635435 19.9721898 59.7192246 20.3320119 58.6749058 20.6918341 58.1200116 21.8301152 58.4798337 22.874434 59.0867105 24.6357842 59.5166381 26.45898 59.760988 28.3232492 59.9045362 29.4184513 60.9087418 30.1899192 62.0039439 30.046371 63.099146 29.9028228 63.8706139 28.8986173 63.7270657 27.8034151zM56.4699838 11.3781121C55.0919588 9.74451505 53.5537382 8.25140603 51.8798083 6.92273835 51.0146495 6.23602588 49.7566092 6.38068523 49.0698968 7.24584403 48.3831843 8.11100284 48.5278436 9.36904308 49.3930024 10.0557555 50.8587525 11.2191822 52.2058153 12.5267396 53.4125204 13.9572433 54.1247279 14.8015385 55.3865225 14.9086168 56.2308177 14.1964094 57.0751129 13.484202 57.1821912 12.2224073 56.4699838 11.3781121zM41.481294 1.42849704C39.4470333.798260231 37.3474846.371987025 35.2067823.158824109 34.1076485.0493765922 33.1278998.851675811 33.0184523 1.95080957 32.9090048 3.04994333 33.711304 4.02969203 34.8104377 4.13913955 36.6833634 4.32563829 38.5191483 4.69835932 40.297557 5.24933028 41.3526509 5.57621023 42.4729622 4.98587613 42.7998421 3.93078217 43.1267221 2.8756882 42.536388 1.75537699 41.481294 1.42849704zM23.6558195 1.0993008C21.5852929 1.6571259 19.5822296 2.42161363 17.6728876 3.37914679 16.6855233 3.874309 16.2865147 5.07613416 16.7816769 6.06349841 17.2768392 7.05086266 18.4786643 7.44987125 19.4660286 6.95470905 21.1354949 6.11747332 22.8864813 5.44919307 24.6963667 4.96158787 25.7629079 4.67424869 26.3945759 3.57671185 26.1072367 2.51017072 25.8198975 1.44362959 24.7223606.811961615 23.6558195 1.0993008zM8.36290105 10.4291871C6.92120358 12.00815 5.63985273 13.7275139 4.53998784 15.5610549 3.97179016 16.5082746 4.27904822 17.7367631 5.22626792 18.3049608 6.17348763 18.8731585 7.40197615 18.5659004 7.97017383 17.6186807 8.9327668 16.0139803 10.054503 14.5087932 11.3168098 13.126301 12.0615972 12.3106016 12.0041117 11.0455771 11.1884123 10.3007897 10.372713 9.55600224 9.10768848 9.61348772 8.36290105 10.4291871zM.450120287 26.6230259C.151304663 28.3883054 0 30.1850053 0 32 0 32.2974081.00406268322 32.594367.0121750297 32.8908218.0423897377 33.994978.96197903 34.8655796 2.0661352 34.8353649 3.17029137 34.8051502 4.04089294 33.8855609 4.01067824 32.7814047 4.00356366 32.521412 4 32.2609289 4 32 4 30.4089462 4.13249902 28.8355581 4.39401589 27.2906242 4.57836807 26.2015475 3.84494393 25.1692294 2.75586724 24.9848772 1.66679054 24.800525.634472466 25.5339492.450120287 26.6230259zM2.45830096 44.3202494C3.28286321 46.2952494 4.30407075 48.1806071 5.50459135 49.9494734 6.124886 50.8634254 7.36863868 51.1014818 8.28259072 50.4811871 9.19654276 49.8608925 9.43459912 48.6171398 8.81430448 47.7031878 7.76386025 46.1554464 6.87058107 44.5062706 6.14951581 42.7791677 5.72395784 41.7598668 4.55266835 41.2785432 3.53336751 41.7041011 2.51406668 42.1296591 2.03274299 43.3009486 2.45830096 44.3202494zM13.73374 58.2776222C15.4883094 59.4994144 17.3614388 60.5433005 19.3262717 61.39161 20.3403619 61.8294398 21.5173756 61.3622885 21.9552054 60.3481983 22.3930351 59.3341082 21.9258838 58.1570945 20.9117937 57.7192647 19.1934726 56.9773858 17.5548741 56.0642026 16.0195384 54.9950736 15.1130877 54.3638678 13.8665707 54.5869979 13.2353649 55.4934487 12.6041591 56.3998995 12.8272892 57.6464164 13.73374 58.2776222zM30.6955071 63.9738646C29.5918263 63.9295649 28.7330282 62.9989428 28.7773279 61.895262 28.8216276 60.7915812 29.7522497 59.9327832 30.8559305 59.9770829 31.2344492 59.9922759 31.6140624 59.9999282 31.9946308 59.9999995 33.0992003 60.0002065 33.994463 60.8958047 33.994256 62.0003742 33.9940491 63.1049437 33.0984508 64.0002064 31.9938814 63.9999994 31.5600677 63.9999181 31.1272192 63.9911927 30.6955071 63.9738646zM30.1721098 44.2840559C30.7941711 46.023825 33.2407935 46.0619159 33.9167124 44.3423547L38.9452693 31.5495297 41.1315797 35.2685507C41.4908522 35.8796908 42.1468005 36.2549751 42.8557214 36.2549751L51.1106965 36.2549751C52.215266 36.2549751 53.1106965 35.3595446 53.1106965 34.2549751 53.1106965 33.1504056 52.215266 32.2549751 51.1106965 32.2549751L43.9999712 32.2549751 40.3112064 25.9802055C39.465988 24.5424477 37.3358287 24.7099356 36.7257006 26.2621229L32.1439734 37.9181973 26.2115967 21.3266406C25.5807315 19.562249 23.0875908 19.5563214 22.4483429 21.3176933L18.4775633 32.2587065 13 32.2587065C11.8954305 32.2587065 11 33.154137 11 34.2587065 11 35.363276 11.8954305 36.2587065 13 36.2587065L19.8793532 36.2587065C20.720826 36.2587065 21.4722973 35.732004 21.7593685 34.9410132L24.314328 27.9011249 30.1721098 44.2840559z"/>
</g>
</svg>
- type = local_assigns.fetch(:type, :issues) - type = local_assigns.fetch(:type, :issues)
- page_context_word = type.to_s.humanize(capitalize: false) - page_context_word = type.to_s.humanize(capitalize: false)
- issuables = @issues || @merge_requests - issuables = @issues || @merge_requests
- closed_title = 'Filter by issues that are currently closed.'
%ul.nav-links.issues-state-filters %ul.nav-links.issues-state-filters
%li{ class: active_when(params[:state] == 'opened') }> %li{ class: active_when(params[:state] == 'opened') }>
%button.btn.btn-link{ id: 'state-opened', title: "Filter by #{page_context_word} that are currently opened.", type: 'button', data: { state: 'opened' } } = link_to page_filter_path(state: 'opened', label: true), id: 'state-opened', title: "Filter by #{page_context_word} that are currently opened.", data: { state: 'opened' } do
#{issuables_state_counter_text(type, :opened)} #{issuables_state_counter_text(type, :opened)}
- if type == :merge_requests - if type == :merge_requests
%li{ class: active_when(params[:state] == 'merged') }> %li{ class: active_when(params[:state] == 'merged') }>
%button.btn.btn-link{ id: 'state-merged', title: 'Filter by merge requests that are currently merged.', type: 'button', data: { state: 'merged' } } = link_to page_filter_path(state: 'merged', label: true), id: 'state-merged', title: 'Filter by merge requests that are currently merged.', data: { state: 'merged' } do
#{issuables_state_counter_text(type, :merged)} #{issuables_state_counter_text(type, :merged)}
- closed_title = 'Filter by merge requests that are currently closed and unmerged.' %li{ class: active_when(params[:state] == 'closed') }>
= link_to page_filter_path(state: 'closed', label: true), id: 'state-closed', title: 'Filter by merge requests that are currently closed and unmerged.', data: { state: 'closed' } do
%li{ class: active_when(params[:state] == 'closed') }> #{issuables_state_counter_text(type, :closed)}
%button.btn.btn-link{ id: 'state-closed', title: closed_title, type: 'button', data: { state: 'closed' } } - else
#{issuables_state_counter_text(type, :closed)} %li{ class: active_when(params[:state] == 'closed') }>
= link_to page_filter_path(state: 'closed', label: true), id: 'state-closed', title: 'Filter by issues that are currently closed.', data: { state: 'closed' } do
#{issuables_state_counter_text(type, :closed)}
%li{ class: active_when(params[:state] == 'all') }> %li{ class: active_when(params[:state] == 'all') }>
%button.btn.btn-link{ id: 'state-all', title: "Show all #{page_context_word}.", type: 'button', data: { state: 'all' } } = link_to page_filter_path(state: 'all', label: true), id: 'state-all', title: "Show all #{page_context_word}.", data: { state: 'all' } do
#{issuables_state_counter_text(type, :all)} #{issuables_state_counter_text(type, :all)}
...@@ -6,13 +6,14 @@ ...@@ -6,13 +6,14 @@
- if can_create_note? - if can_create_note?
%ul.notes.notes-form.timeline %ul.notes.notes-form.timeline
%li.timeline-entry %li.timeline-entry
.flash-container.timeline-content .timeline-entry-inner
.flash-container.timeline-content
.timeline-icon.hidden-xs.hidden-sm .timeline-icon.hidden-xs.hidden-sm
%a.author_link{ href: user_path(current_user) } %a.author_link{ href: user_path(current_user) }
= image_tag avatar_icon(current_user), alt: current_user.to_reference, class: 'avatar s40' = image_tag avatar_icon(current_user), alt: current_user.to_reference, class: 'avatar s40'
.timeline-content.timeline-content-form .timeline-content.timeline-content-form
= render "shared/notes/form", view: diff_view, supports_autocomplete: autocomplete = render "shared/notes/form", view: diff_view, supports_autocomplete: autocomplete
- elsif !current_user - elsif !current_user
.disabled-comment.text-center.prepend-top-default .disabled-comment.text-center.prepend-top-default
Please Please
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
.modal-content .modal-content
.modal-header .modal-header
%button.close{ type: "button", "aria-label": "close", data: { dismiss: "modal" } } %button.close{ type: "button", "aria-label": "close", data: { dismiss: "modal" } }
%span{ "aria-hidden": "true" } } × %span{ "aria-hidden": "true" } ×
%h4#custom-notifications-title.modal-title %h4#custom-notifications-title.modal-title
#{ _('Custom notification events') } #{ _('Custom notification events') }
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
- else - else
= render "snippets/actions" = render "snippets/actions"
.snippet-header .snippet-header.limited-header-width
%h2.snippet-title.prepend-top-0.append-bottom-0 %h2.snippet-title.prepend-top-0.append-bottom-0
= markdown_field(@snippet, :title) = markdown_field(@snippet, :title)
......
- @content_class = "limit-container-width limited-inner-width-container" unless fluid_layout
- page_title "#{@snippet.title} (#{@snippet.to_reference})", "Snippets" - page_title "#{@snippet.title} (#{@snippet.to_reference})", "Snippets"
= render 'shared/snippets/header' = render 'shared/snippets/header'
...@@ -9,4 +10,4 @@ ...@@ -9,4 +10,4 @@
.row-content-block.top-block.content-component-block .row-content-block.top-block.content-component-block
= render 'award_emoji/awards_block', awardable: @snippet, inline: true = render 'award_emoji/awards_block', awardable: @snippet, inline: true
#notes= render "shared/notes/notes_with_form", :autocomplete => false #notes.limited-width-notes= render "shared/notes/notes_with_form", :autocomplete => false
---
title: Fix mobile view of files view buttons
merge_request:
author:
---
title: Additional Prometheus metrics support
merge_request: 11712
author:
---
title: Filter archived project in API v3 only if param present
merge_request: 12245
author: Ivan Chernov
---
title: Update QA Dockerfile to lock Chrome browser version
merge_request: 12071
author:
---
title: Standardize timeline note margins across different viewport sizes
merge_request: 12364
author:
---
title: Fix linking to line number on side-by-side diff creating empty discussion box
merge_request:
author:
---
title: Limit commit & snippets comments width
merge_request:
author:
---
title: Don't match tilde and exclamation mark as part of requirements.txt package
name
merge_request:
author:
---
title: Remove unnecessary top padding on group MR index
merge_request:
author:
---
title: Add option to run Gitaly on a remote server
merge_request: 12381
author:
---
title: Fix reversed breadcrumb order for nested groups
merge_request: 12322
author:
---
title: Fix 500 when failing to create private group
merge_request: 12394
author:
---
title: Limit the width of the projects README text
merge_request:
author:
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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