Merge branch 'master' into breadcrumbs-improvements

This commit is contained in:
Phil Hughes 2017-09-06 12:12:19 +01:00
commit 2aa8a75f69
138 changed files with 2121 additions and 1486 deletions

View File

@ -208,7 +208,7 @@ update-tests-metadata:
- '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $KNAPSACK_RSPEC_SUITE_REPORT_PATH $KNAPSACK_SPINACH_SUITE_REPORT_PATH'
- '[[ -z ${TESTS_METADATA_S3_BUCKET} ]] || scripts/sync-reports put $TESTS_METADATA_S3_BUCKET $FLAKY_RSPEC_SUITE_REPORT_PATH'
- rm -f knapsack/${CI_PROJECT_NAME}/*_node_*.json
- rm -f rspec_flaky/${CI_PROJECT_NAME}/all_node_*.json
- rm -f rspec_flaky/${CI_PROJECT_NAME}/*_node_*.json
flaky-examples-check:
<<: *dedicated-runner

View File

@ -1 +1 @@
0.36.0
0.37.0

View File

@ -181,7 +181,7 @@ gem 'connection_pool', '~> 2.0'
gem 'hipchat', '~> 1.5.0'
# JIRA integration
gem 'jira-ruby', '~> 1.1.2'
gem 'jira-ruby', '~> 1.4'
# Flowdock integration
gem 'gitlab-flowdock-git-hook', '~> 1.0.1'
@ -397,7 +397,7 @@ group :ed25519 do
end
# Gitaly GRPC client
gem 'gitaly-proto', '~> 0.31.0', require: 'gitaly'
gem 'gitaly-proto', '~> 0.32.0', require: 'gitaly'
gem 'toml-rb', '~> 0.3.15', require: false

View File

@ -275,7 +275,7 @@ GEM
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gherkin-ruby (0.3.2)
gitaly-proto (0.31.0)
gitaly-proto (0.32.0)
google-protobuf (~> 3.1)
grpc (~> 1.0)
github-linguist (4.7.6)
@ -404,8 +404,9 @@ GEM
cause
json
ipaddress (0.8.3)
jira-ruby (1.1.2)
jira-ruby (1.4.1)
activesupport
multipart-post
oauth (~> 0.5, >= 0.5.0)
jquery-atwho-rails (1.3.2)
jquery-rails (4.1.1)
@ -1020,7 +1021,7 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0)
gitaly-proto (~> 0.31.0)
gitaly-proto (~> 0.32.0)
github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-markup (~> 1.5.1)
@ -1042,7 +1043,7 @@ DEPENDENCIES
html2text
httparty (~> 0.13.3)
influxdb (~> 0.2)
jira-ruby (~> 1.1.2)
jira-ruby (~> 1.4)
jquery-atwho-rails (~> 1.3.2)
jquery-rails (~> 4.1.0)
json-schema (~> 2.6.2)

View File

@ -61,7 +61,7 @@ class DropdownHint extends gl.FilteredSearchDropdown {
.map(tokenKey => ({
icon: `fa-${tokenKey.icon}`,
hint: tokenKey.key,
tag: `<${tokenKey.tag}>`,
tag: `:${tokenKey.tag}`,
type: tokenKey.type,
}));

View File

@ -637,11 +637,15 @@ GitLabDropdown = (function() {
value = this.options.id ? this.options.id(data) : data.id;
fieldName = this.options.fieldName;
if (value) { value = value.toString().replace(/'/g, '\\\''); }
field = this.dropdown.parent().find("input[name='" + fieldName + "'][value='" + value + "']");
if (field.length) {
selected = true;
if (value) {
value = value.toString().replace(/'/g, '\\\'');
field = this.dropdown.parent().find(`input[name='${fieldName}'][value='${value}']`);
if (field.length) {
selected = true;
}
} else {
field = this.dropdown.parent().find(`input[name='${fieldName}']`);
selected = !field.length;
}
}
// Set URL

View File

@ -5,7 +5,6 @@
/* global SubscriptionSelect */
import IssuableBulkUpdateActions from './issuable_bulk_update_actions';
import SidebarHeightManager from './sidebar_height_manager';
const HIDDEN_CLASS = 'hidden';
const DISABLED_CONTENT_CLASS = 'disabled-content';
@ -50,13 +49,6 @@ export default class IssuableBulkUpdateSidebar {
new SubscriptionSelect();
}
getNavHeight() {
const navbarHeight = $('.navbar-gitlab').outerHeight();
const layoutNavHeight = $('.layout-nav').outerHeight();
const subNavScroll = $('.sub-nav-scroll').outerHeight();
return navbarHeight + layoutNavHeight + subNavScroll;
}
setupBulkUpdateActions() {
IssuableBulkUpdateActions.setOriginalDropdownData();
}
@ -84,23 +76,6 @@ export default class IssuableBulkUpdateSidebar {
this.toggleBulkEditButtonDisabled(enable);
this.toggleOtherFiltersDisabled(enable);
this.toggleCheckboxDisplay(enable);
if (enable) {
this.initAffix();
SidebarHeightManager.init();
}
}
initAffix() {
if (!this.$sidebar.hasClass('affix-top')) {
const offsetTop = $('.scrolling-tabs-container').outerHeight() + $('.sub-nav-scroll').outerHeight();
this.$sidebar.affix({
offset: {
top: offsetTop,
},
});
}
}
updateSelectedIssuableIds() {

View File

@ -50,19 +50,10 @@ import initFlyOutNav from './fly_out_nav';
});
});
function applyScrollNavClass() {
const scrollOpacityHeight = 40;
$('.navbar-border').css('opacity', Math.min($(window).scrollTop() / scrollOpacityHeight, 1));
}
$(() => {
if (Cookies.get('new_nav') === 'true') {
const newNavSidebar = new NewNavSidebar();
newNavSidebar.bindEvents();
const newNavSidebar = new NewNavSidebar();
newNavSidebar.bindEvents();
initFlyOutNav();
}
$(window).on('scroll', _.throttle(applyScrollNavClass, 100));
initFlyOutNav();
});
}).call(window);

View File

@ -4,7 +4,7 @@
import statusCodes from '../../lib/utils/http_status';
import MonitoringService from '../services/monitoring_service';
import GraphGroup from './graph_group.vue';
import GraphRow from './graph_row.vue';
import Graph from './graph.vue';
import EmptyState from './empty_state.vue';
import MonitoringStore from '../stores/monitoring_store';
import eventHub from '../event_hub';
@ -32,8 +32,8 @@
},
components: {
Graph,
GraphGroup,
GraphRow,
EmptyState,
},
@ -127,10 +127,10 @@
:key="index"
:name="groupData.group"
>
<graph-row
v-for="(row, index) in groupData.metrics"
<graph
v-for="(graphData, index) in groupData.metrics"
:key="index"
:row-data="row"
:graph-data="graphData"
:update-aspect-ratio="updateAspectRatio"
:deployment-data="store.deploymentData"
/>

View File

@ -19,10 +19,6 @@
type: Object,
required: true,
},
classType: {
type: String,
required: true,
},
updateAspectRatio: {
type: Boolean,
required: true,
@ -207,12 +203,11 @@
},
};
</script>
<template>
<div
:class="classType">
<h5
class="text-center graph-title">
{{graphData.title}}
<div class="prometheus-graph">
<h5 class="text-center graph-title">
{{graphData.title}}
</h5>
<div
class="prometheus-svg-container"
@ -243,7 +238,7 @@
class="graph-data"
:viewBox="innerViewBox"
ref="graphData">
<monitoring-paths
<monitoring-paths
v-for="(path, index) in timeSeries"
:key="index"
:generated-line-path="path.linePath"

View File

@ -14,7 +14,7 @@ export default {
<div class="panel-heading">
<h4>{{name}}</h4>
</div>
<div class="panel-body">
<div class="panel-body prometheus-graph-group">
<slot />
</div>
</div>

View File

@ -1,41 +0,0 @@
<script>
import Graph from './graph.vue';
export default {
props: {
rowData: {
type: Array,
required: true,
},
updateAspectRatio: {
type: Boolean,
required: true,
},
deploymentData: {
type: Array,
required: true,
},
},
components: {
Graph,
},
computed: {
bootstrapClass() {
return this.rowData.length >= 2 ? 'col-md-6' : 'col-md-12';
},
},
};
</script>
<template>
<div class="prometheus-row row">
<graph
v-for="(graphData, index) in rowData"
:graph-data="graphData"
:class-type="bootstrapClass"
:key="index"
:update-aspect-ratio="updateAspectRatio"
:deployment-data="deploymentData"
/>
</div>
</template>

View File

@ -20,22 +20,6 @@ function normalizeMetrics(metrics) {
}));
}
function collate(array, rows = 2) {
const collatedArray = [];
let row = [];
array.forEach((value, index) => {
row.push(value);
if ((index + 1) % rows === 0) {
collatedArray.push(row);
row = [];
}
});
if (row.length > 0) {
collatedArray.push(row);
}
return collatedArray;
}
export default class MonitoringStore {
constructor() {
this.groups = [];
@ -45,7 +29,7 @@ export default class MonitoringStore {
storeMetrics(groups = []) {
this.groups = groups.map(group => ({
...group,
metrics: collate(normalizeMetrics(sortMetrics(group.metrics))),
metrics: normalizeMetrics(sortMetrics(group.metrics)),
}));
}
@ -54,12 +38,6 @@ export default class MonitoringStore {
}
getMetricsCount() {
let metricsCount = 0;
this.groups.forEach((group) => {
group.metrics.forEach((metric) => {
metricsCount = metricsCount += metric.length;
});
});
return metricsCount;
return this.groups.reduce((count, group) => count + group.metrics.length, 0);
}
}

View File

@ -63,7 +63,7 @@ export default class NewNavSidebar {
if (breakpoint === 'sm' || breakpoint === 'md') {
this.toggleCollapsedSidebar(true);
} else if (breakpoint === 'lg') {
const collapse = Cookies.get('sidebar_collapsed') === 'true';
const collapse = this.$sidebar.hasClass('sidebar-icons-only');
this.toggleCollapsedSidebar(collapse);
}
}

View File

@ -2,7 +2,6 @@
import _ from 'underscore';
import Cookies from 'js-cookie';
import SidebarHeightManager from './sidebar_height_manager';
(function() {
this.Sidebar = (function() {
@ -23,7 +22,6 @@ import SidebarHeightManager from './sidebar_height_manager';
};
Sidebar.prototype.addEventListeners = function() {
SidebarHeightManager.init();
const $document = $(document);
this.sidebar.on('click', '.sidebar-collapsed-icon', this, this.sidebarCollapseClicked);

View File

@ -1,37 +0,0 @@
import _ from 'underscore';
import Cookies from 'js-cookie';
export default {
init() {
if (!this.initialized) {
if (Cookies.get('new_nav') === 'true' && $('.js-issuable-sidebar').length) return;
this.$window = $(window);
this.$rightSidebar = $('.js-right-sidebar');
this.$navHeight = $('.navbar-gitlab').outerHeight() +
$('.layout-nav').outerHeight() +
$('.sub-nav-scroll').outerHeight();
const throttledSetSidebarHeight = _.throttle(() => this.setSidebarHeight(), 20);
const debouncedSetSidebarHeight = _.debounce(() => this.setSidebarHeight(), 200);
this.$window.on('scroll', throttledSetSidebarHeight);
this.$window.on('resize', debouncedSetSidebarHeight);
this.initialized = true;
}
},
setSidebarHeight() {
const currentScrollDepth = window.pageYOffset || 0;
const diff = this.$navHeight - currentScrollDepth;
if (diff > 0) {
const newSidebarHeight = window.innerHeight - diff;
this.$rightSidebar.outerHeight(newSidebarHeight);
this.sidebarHeightIsCustom = true;
} else if (this.sidebarHeightIsCustom) {
this.$rightSidebar.outerHeight('100%');
this.sidebarHeightIsCustom = false;
}
},
};

View File

@ -766,6 +766,7 @@
box-shadow: none;
padding: 8px 16px;
text-align: left;
white-space: normal;
width: 100%;
// make sure the text color is not overriden

View File

@ -105,12 +105,11 @@ header {
top: -3px;
font-size: 10px;
}
}
.user-counter {
svg {
position: relative;
top: 2px;
height: 17px;
// hack to get SVG to line up with FA icons
height: 16px;
width: 23px;
fill: currentColor;
}
@ -325,12 +324,12 @@ header {
li {
.badge {
position: inherit;
top: -8px;
font-weight: $gl-font-weight-normal;
margin-left: -11px;
margin-left: -6px;
font-size: 11px;
color: $white-light;
padding: 1px 5px 2px;
padding: 0 5px;
line-height: 12px;
border-radius: 7px;
box-shadow: 0 1px 0 rgba($gl-header-color, .2);

View File

@ -177,13 +177,14 @@ $row-hover: $blue-25;
$row-hover-border: $blue-100;
$progress-color: #c0392b;
$header-height: 50px;
$new-navbar-height: 40px;
$fixed-layout-width: 1280px;
$limited-layout-width: 990px;
$limited-layout-width-sm: 790px;
$container-text-max-width: 540px;
$gl-avatar-size: 40px;
$error-exclamation-point: $red-500;
$border-radius-default: 3px;
$border-radius-default: 4px;
$settings-icon-size: 18px;
$provider-btn-not-active-color: $blue-500;
$link-underline-blue: $blue-500;

View File

@ -3,15 +3,21 @@
@import "bootstrap/variables";
@import "framework/mixins";
.content-wrapper.page-with-new-nav {
margin-top: $new-navbar-height;
}
header.navbar-gitlab-new {
color: $white-light;
background: linear-gradient(to right, $indigo-900, $indigo-800);
border-bottom: 0;
min-height: $new-navbar-height;
.header-content {
display: -webkit-flex;
display: flex;
padding-left: 0;
min-height: $new-navbar-height;
.title-container {
display: -webkit-flex;
@ -39,20 +45,13 @@ header.navbar-gitlab-new {
display: -webkit-flex;
display: flex;
align-items: center;
padding-right: $gl-padding;
padding-left: $gl-padding;
margin-left: -$gl-padding;
@media (min-width: $screen-sm-min) {
padding-right: $gl-padding;
padding-left: $gl-padding;
}
padding: 2px 8px;
margin: 5px 2px 5px -8px;
border-radius: $border-radius-default;
svg {
margin-top: -3px;
@media (min-width: $screen-sm-min) {
margin-right: 10px;
margin-right: 8px;
}
}
@ -61,7 +60,7 @@ header.navbar-gitlab-new {
svg {
width: 55px;
height: 15px;
height: 14px;
margin: 0;
fill: $white-light;
}
@ -69,9 +68,7 @@ header.navbar-gitlab-new {
&:hover,
&:focus {
.logo-text svg {
fill: $tanuki-yellow;
}
background-color: rgba($indigo-200, .2);
}
}
}
@ -91,6 +88,20 @@ header.navbar-gitlab-new {
right: 0;
}
}
&.menu-expanded {
@media (max-width: $screen-xs-max) {
.title-container,
.header-logo, {
display: none;
}
}
}
}
.dropdown-bold-header {
color: $gl-text-color-secondary;
font-size: 12px;
}
.navbar-collapse {
@ -99,14 +110,10 @@ header.navbar-gitlab-new {
box-shadow: 0;
@media (max-width: $screen-xs-max) {
margin-left: -$gl-padding;
margin-left: -8px;
margin-right: -10px;
}
.dropdown-bold-header {
color: initial;
}
.nav {
> li:not(.hidden-xs) a {
@media (max-width: $screen-xs-max) {
@ -120,7 +127,7 @@ header.navbar-gitlab-new {
.container-fluid {
.navbar-toggle {
min-width: 45px;
padding: 6px $gl-padding;
padding: 4px $gl-padding;
margin-right: -7px;
font-size: 14px;
text-align: center;
@ -157,29 +164,88 @@ header.navbar-gitlab-new {
}
> a {
background: none;
will-change: color;
margin: 4px 2px;
padding: 6px 8px;
color: $indigo-200;
height: 32px;
@media (max-width: $screen-xs-max) {
padding: 0;
}
svg {
fill: $indigo-200;
}
&.header-user-dropdown-toggle {
margin-left: 2px;
.header-user-avatar {
border-color: $indigo-200;
margin-right: 0;
}
}
}
.header-new-dropdown-toggle {
margin-right: 0;
}
> a:hover,
> a:focus {
text-decoration: none;
outline: 0;
opacity: 1;
color: $white-light;
@media (min-width: $screen-sm-min) {
background-color: rgba($indigo-200, .2);
}
svg {
fill: currentColor;
}
&.header-user-dropdown-toggle {
.header-user-avatar {
border-color: $indigo-200;
border-color: $white-light;
}
}
}
&:hover,
&:focus {
color: $white-light;
opacity: 1;
.impersonated-user,
.impersonated-user:hover {
margin-right: 1px;
background-color: $white-light;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
> svg {
fill: $white-light;
}
svg {
fill: $indigo-900;
}
}
&.header-user-dropdown-toggle {
.header-user-avatar {
border-color: $white-light;
}
}
.impersonation-btn,
.impersonation-btn:hover {
background-color: $white-light;
margin-left: 0;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
i {
color: $orange-500;
font-size: 20px;
}
}
&.active > a,
&.dropdown.open > a {
color: $indigo-900;
background-color: $white-light;
svg {
fill: currentColor;
}
}
}
@ -189,40 +255,9 @@ header.navbar-gitlab-new {
.navbar-sub-nav {
display: -webkit-flex;
display: flex;
margin-bottom: 0;
margin: 0 0 0 6px;
color: $indigo-200;
> li {
> a:hover,
> a:focus {
box-shadow: inset 0 -3px 0 rgba($indigo-200, .4);
text-decoration: none;
outline: 0;
color: $white-light;
}
&.active > a {
box-shadow: inset 0 -3px 0 $indigo-500;
color: $white-light;
font-weight: $gl-font-weight-bold;
}
> a {
display: block;
padding: 16px 10px;
font-size: 13px;
color: currentColor;
box-shadow: inset 0 0 0 transparent;
will-change: box-shadow;
transition: box-shadow 0.15s;
@media (min-width: $screen-sm-min) {
padding: 15px $gl-padding;
font-size: 14px;
}
}
}
.dropdown-chevron {
position: relative;
top: -1px;
@ -230,16 +265,82 @@ header.navbar-gitlab-new {
}
}
.navbar-gitlab-new {
.navbar-sub-nav,
.navbar-nav {
> li {
> a:hover,
> a:focus {
text-decoration: none;
outline: 0;
color: $white-light;
background-color: rgba($indigo-200, .2);
svg {
fill: currentColor;
}
}
&.active > a,
&.dropdown.open > a {
color: $indigo-900;
background-color: $white-light;
svg {
fill: currentColor;
}
}
> a {
display: flex;
align-items: center;
justify-content: center;
padding: 6px 8px;
margin: 4px 2px;
font-size: 12px;
color: currentColor;
border-radius: $border-radius-default;
height: 32px;
font-weight: $gl-font-weight-bold;
svg {
fill: currentColor;
}
}
&.line-separator {
border-left: 1px solid rgba($indigo-200, .2);
margin: 8px;
}
}
}
}
.admin-icon i {
font-size: 18px;
}
.caret-down {
height: 11px;
width: 11px;
margin-left: 4px;
fill: currentColor;
}
.header-user .dropdown-menu-nav,
.header-new .dropdown-menu-nav {
margin-top: 4px;
}
.search {
margin: 4px 8px 0;
form {
height: 32px;
border: 0;
border-radius: $border-radius-default;
background-color: rgba($indigo-200, .2);
transition: border-color ease-in-out 0.15s, box-shadow ease-in-out 0.15s, background-color ease-in-out 0.15s;
transition: border-color ease-in-out 0.15s, background-color ease-in-out 0.15s;
&:hover {
background-color: rgba($indigo-200, .3);
@ -248,31 +349,50 @@ header.navbar-gitlab-new {
}
&.search-active form {
background-color: rgba($indigo-200, .3);
background-color: $white-light;
box-shadow: none;
.search-input {
color: $gl-text-color;
transition: color ease-in-out 0.15s;
}
.search-input::placeholder {
color: $gl-text-color-tertiary;
}
.search-input-wrap {
.search-icon,
.clear-icon {
color: $gl-text-color-tertiary;
transition: color ease-in-out 0.15s;
}
}
}
.search-input {
color: $white-light;
background: none;
transition: color ease-in-out 0.15s;
}
.search-input::placeholder {
color: rgba($indigo-200, .8);
transition: color ease-in-out 0.15s;
}
.location-badge {
font-size: 12px;
color: $indigo-100;
background-color: rgba($indigo-200, .1);
transition: color 0.15s;
will-change: color;
margin: -4px 4px -4px -4px;
line-height: 25px;
padding: 4px 8px;
border-radius: 2px 0 0 2px;
border-right: 1px solid $indigo-800;
height: 34px;
height: 32px;
transition: border-color ease-in-out 0.15s;
}
.search-input-wrap {
@ -284,8 +404,9 @@ header.navbar-gitlab-new {
&.search-active {
.location-badge {
color: $white-light;
background-color: rgba($indigo-200, .2);
color: $gl-text-color;
background-color: $nav-badge-bg;
border-color: $border-color;
}
.search-input-wrap {
@ -403,3 +524,14 @@ header.navbar-gitlab-new {
}
}
}
.btn-sign-in {
margin-top: 3px;
background-color: $indigo-100;
color: $indigo-900;
font-weight: $gl-font-weight-bold;
&:hover {
background-color: $white-light;
}
}

View File

@ -26,7 +26,7 @@ $new-sidebar-collapsed-width: 50px;
// Override position: absolute
.right-sidebar {
position: fixed;
height: calc(100% - #{$header-height});
height: calc(100% - #{$new-navbar-height});
}
.issues-bulk-update.right-sidebar.right-sidebar-expanded .issuable-sidebar-header {
@ -92,7 +92,7 @@ $new-sidebar-collapsed-width: 50px;
z-index: 400;
width: $new-sidebar-width;
transition: left $sidebar-transition-duration;
top: $header-height;
top: $new-navbar-height;
bottom: 0;
left: 0;
background-color: $gray-normal;
@ -188,7 +188,7 @@ $new-sidebar-collapsed-width: 50px;
}
.with-performance-bar .nav-sidebar {
top: $header-height + $performance-bar-height;
top: $new-navbar-height + $performance-bar-height;
}
.sidebar-sub-level-items {
@ -452,7 +452,7 @@ $new-sidebar-collapsed-width: 50px;
// Make issue boards full-height now that sub-nav is gone
.boards-list {
height: calc(100vh - #{$header-height});
height: calc(100vh - #{$new-navbar-height});
@media (min-width: $screen-sm-min) {
height: 475px; // Needed for PhantomJS
@ -463,7 +463,7 @@ $new-sidebar-collapsed-width: 50px;
}
.with-performance-bar .boards-list {
height: calc(100vh - #{$header-height} - #{$performance-bar-height});
height: calc(100vh - #{$new-navbar-height} - #{$performance-bar-height});
}

View File

@ -440,6 +440,7 @@
&.right-sidebar {
top: 0;
bottom: 0;
height: 100%;
}
.issuable-sidebar-header {

View File

@ -227,6 +227,26 @@
margin-top: 20px;
}
.prometheus-graph-group {
display: flex;
flex-wrap: wrap;
padding: $gl-padding / 2;
}
.prometheus-graph {
flex: 1 0 auto;
min-width: 450px;
padding: $gl-padding / 2;
h5 {
font-size: 16px;
}
@media (max-width: $screen-sm-max) {
min-width: 100%;
}
}
.prometheus-svg-container {
position: relative;
height: 0;
@ -297,9 +317,3 @@
}
}
}
.prometheus-row {
h5 {
font-size: 16px;
}
}

View File

@ -190,6 +190,8 @@ input[type="checkbox"]:hover {
}
.search-holder {
@include new-style-dropdown;
@media (min-width: $screen-sm-min) {
display: -webkit-flex;
display: flex;

View File

@ -302,10 +302,6 @@ module ApplicationHelper
end
end
def show_new_nav?
true
end
def collapsed_sidebar?
cookies["sidebar_collapsed"] == "true"
end

View File

@ -86,7 +86,7 @@ module GroupsHelper
def group_title_link(group, hidable: false, show_avatar: false)
link_to(group_path(group), class: "group-path breadcrumb-item-text js-breadcrumb-item-text #{'hidable' if hidable}") do
output =
if (show_new_nav? && group.try(:avatar_url) || (show_new_nav? && show_avatar)) && !Rails.env.test?
if (group.try(:avatar_url) || show_avatar)) && !Rails.env.test?
image_tag(group_icon(group), class: "avatar-tile", width: 15, height: 15)
else
""

View File

@ -1,8 +1,8 @@
module NavHelper
def page_with_sidebar_class
class_name = page_gutter_class
class_name << 'page-with-new-sidebar' if defined?(@new_sidebar) && @new_sidebar
class_name << 'page-with-icon-sidebar' if collapsed_sidebar? && @new_sidebar
class_name << 'page-with-new-sidebar' if defined?(@left_sidebar) && @left_sidebar
class_name << 'page-with-icon-sidebar' if collapsed_sidebar? && @left_sidebar
class_name
end
@ -30,24 +30,15 @@ module NavHelper
end
end
def nav_header_class
class_names = []
class_names << 'with-horizontal-nav' if defined?(nav) && nav
class_names
end
def layout_nav_class
return [] if show_new_nav?
class_names = []
class_names << 'page-with-layout-nav' if defined?(nav) && nav
class_names << 'page-with-sub-nav' if content_for?(:sub_nav)
class_names
end
def nav_control_class
"nav-control" if current_user
end
def user_dropdown_class
class_names = []
class_names << 'header-user-dropdown-toggle'
class_names << 'impersonated-user' if session[:impersonator_id]
class_names
end
end

View File

@ -4,7 +4,7 @@ module PageLayoutHelper
@page_title.push(*titles.compact) if titles.any?
if show_new_nav? && titles.any? && !defined?(@breadcrumb_title)
if titles.any? && !defined?(@breadcrumb_title)
@breadcrumb_title = @page_title.last
end

View File

@ -62,7 +62,7 @@ module ProjectsHelper
project_link = link_to project_path(project), { class: ("project-item-select-holder" unless show_new_nav?) } do
output =
if show_new_nav? && project.avatar_url && !Rails.env.test?
if project.avatar_url && !Rails.env.test?
project_icon(project, alt: project.name, class: 'avatar-tile', width: 15, height: 15)
else
""

View File

@ -6,6 +6,7 @@
#
module Issuable
extend ActiveSupport::Concern
include Gitlab::SQL::Pattern
include CacheMarkdownField
include Participable
include Mentionable
@ -122,7 +123,9 @@ module Issuable
#
# Returns an ActiveRecord::Relation.
def search(query)
where(arel_table[:title].matches("%#{query}%"))
title = to_fuzzy_arel(:title, query)
where(title)
end
# Searches for records with a matching title or description.
@ -133,10 +136,10 @@ module Issuable
#
# Returns an ActiveRecord::Relation.
def full_search(query)
t = arel_table
pattern = "%#{query}%"
title = to_fuzzy_arel(:title, query)
description = to_fuzzy_arel(:description, query)
where(t[:title].matches(pattern).or(t[:description].matches(pattern)))
where(title&.or(description))
end
def sort(method, excluded_labels: [])

View File

@ -16,6 +16,7 @@ class Group < Namespace
source: :user
has_many :requesters, -> { where.not(requested_at: nil) }, dependent: :destroy, as: :source, class_name: 'GroupMember' # rubocop:disable Cop/ActiveRecordDependent
has_many :members_and_requesters, as: :source, class_name: 'GroupMember'
has_many :milestones
has_many :project_group_links, dependent: :destroy # rubocop:disable Cop/ActiveRecordDependent

View File

@ -126,20 +126,11 @@ class Member < ActiveRecord::Base
find_by(invite_token: invite_token)
end
def add_user(source, user, access_level, current_user: nil, expires_at: nil)
user = retrieve_user(user)
def add_user(source, user, access_level, existing_members: nil, current_user: nil, expires_at: nil)
# `user` can be either a User object, User ID or an email to be invited
member = retrieve_member(source, user, existing_members)
access_level = retrieve_access_level(access_level)
# `user` can be either a User object or an email to be invited
member =
if user.is_a?(User)
source.members.find_by(user_id: user.id) ||
source.requesters.find_by(user_id: user.id) ||
source.members.build(user_id: user.id)
else
source.members.build(invite_email: user)
end
return member unless can_update_member?(current_user, member)
member.attributes = {
@ -165,17 +156,15 @@ class Member < ActiveRecord::Base
def add_users(source, users, access_level, current_user: nil, expires_at: nil)
return [] unless users.present?
# Collect all user ids into separate array
# so we can use single sql query to get user objects
user_ids = users.select { |user| user =~ /\A\d+\Z/ }
users = users - user_ids + User.where(id: user_ids)
emails, users, existing_members = parse_users_list(source, users)
self.transaction do
users.map do |user|
(emails + users).map! do |user|
add_user(
source,
user,
access_level,
existing_members: existing_members,
current_user: current_user,
expires_at: expires_at
)
@ -189,6 +178,31 @@ class Member < ActiveRecord::Base
private
def parse_users_list(source, list)
emails, user_ids, users = [], [], []
existing_members = {}
list.each do |item|
case item
when User
users << item
when Integer
user_ids << item
when /\A\d+\Z/
user_ids << item.to_i
when Devise.email_regexp
emails << item
end
end
if user_ids.present?
users.concat(User.where(id: user_ids))
existing_members = source.members_and_requesters.where(user_id: user_ids).index_by(&:user_id)
end
[emails, users, existing_members]
end
# This method is used to find users that have been entered into the "Add members" field.
# These can be the User objects directly, their IDs, their emails, or new emails to be invited.
def retrieve_user(user)
@ -197,6 +211,20 @@ class Member < ActiveRecord::Base
User.find_by(id: user) || User.find_by(email: user) || user
end
def retrieve_member(source, user, existing_members)
user = retrieve_user(user)
if user.is_a?(User)
if existing_members
existing_members[user.id] || source.members.build(user_id: user.id)
else
source.members_and_requesters.find_or_initialize_by(user_id: user.id)
end
else
source.members.build(invite_email: user)
end
end
def retrieve_access_level(access_level)
access_levels.fetch(access_level) { access_level.to_i }
end

View File

@ -144,6 +144,7 @@ class Project < ActiveRecord::Base
has_many :requesters, -> { where.not(requested_at: nil) },
as: :source, class_name: 'ProjectMember', dependent: :delete_all # rubocop:disable Cop/ActiveRecordDependent
has_many :members_and_requesters, as: :source, class_name: 'ProjectMember'
has_many :deploy_keys_projects
has_many :deploy_keys, through: :deploy_keys_projects

View File

@ -1,4 +1,4 @@
- if show_new_nav? && current_user.can_create_group?
- if current_user.can_create_group?
- content_for :breadcrumbs_extra do
= link_to "New group", new_group_path, class: "btn btn-new"
@ -10,8 +10,8 @@
= nav_link(page: explore_groups_path) do
= link_to explore_groups_path, title: 'Explore public groups' do
Explore public groups
.nav-controls{ class: ("nav-controls-new-nav" if show_new_nav?) }
.nav-controls.nav-controls-new-nav
= render 'shared/groups/search_form'
= render 'shared/groups/dropdown'
- if current_user.can_create_group?
= link_to "New group", new_group_path, class: "btn btn-new #{("visible-xs" if show_new_nav?)}"
= link_to "New group", new_group_path, class: "btn btn-new visible-xs"

View File

@ -1,7 +1,7 @@
= content_for :flash_message do
= render 'shared/project_limit'
- if show_new_nav? && current_user.can_create_project?
- if current_user.can_create_project?
- content_for :breadcrumbs_extra do
= link_to "New project", new_project_path, class: 'btn btn-new'
@ -19,8 +19,8 @@
= link_to explore_root_path, title: 'Explore', data: {placement: 'right'} do
Explore projects
.nav-controls{ class: ("nav-controls-new-nav" if show_new_nav?) }
.nav-controls.nav-controls-new-nav
= render 'shared/projects/search_form'
= render 'shared/projects/dropdown'
- if current_user.can_create_project?
= link_to "New project", new_project_path, class: "btn btn-new #{("visible-xs" if show_new_nav?)}"
= link_to "New project", new_project_path, class: "btn btn-new visible-xs"

View File

@ -1,4 +1,4 @@
- if show_new_nav? && current_user
- if current_user
- content_for :breadcrumbs_extra do
= link_to "New snippet", new_snippet_path, class: "btn btn-new", title: "New snippet"
@ -10,7 +10,3 @@
= nav_link(page: explore_snippets_path) do
= link_to explore_snippets_path, title: 'Explore snippets', data: {placement: 'right'} do
Explore Snippets
- if current_user
.nav-controls.hidden-xs{ class: ("hidden-sm hidden-md hidden-lg" if show_new_nav?) }
= link_to "New snippet", new_snippet_path, class: "btn btn-new", title: "New snippet"

View File

@ -4,15 +4,14 @@
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{current_user.name} issues")
- if show_new_nav?
- content_for :breadcrumbs_extra do
= link_to params.merge(rss_url_options), class: 'btn has-tooltip append-right-10', title: 'Subscribe' do
= icon('rss')
= render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", with_feature_enabled: 'issues', type: :issues
- content_for :breadcrumbs_extra do
= link_to params.merge(rss_url_options), class: 'btn has-tooltip append-right-10', title: 'Subscribe' do
= icon('rss')
= render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", with_feature_enabled: 'issues', type: :issues
.top-area
= render 'shared/issuable/nav', type: :issues
.nav-controls{ class: ("visible-xs" if show_new_nav?) }
.nav-controls.visible-xs
= link_to params.merge(rss_url_options), class: 'btn has-tooltip', title: 'Subscribe' do
= icon('rss')
= render 'shared/new_project_item_select', path: 'issues/new', label: "New issue", with_feature_enabled: 'issues', type: :issues

View File

@ -2,13 +2,12 @@
- page_title "Merge Requests"
- header_title "Merge Requests", merge_requests_dashboard_path(assignee_id: current_user.id)
- if show_new_nav?
- content_for :breadcrumbs_extra do
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", with_feature_enabled: 'merge_requests', type: :merge_requests
- content_for :breadcrumbs_extra do
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", with_feature_enabled: 'merge_requests', type: :merge_requests
.top-area
= render 'shared/issuable/nav', type: :merge_requests
.nav-controls{ class: ("visible-xs" if show_new_nav?) }
.nav-controls.visible-xs
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", with_feature_enabled: 'merge_requests', type: :merge_requests
= render 'shared/issuable/filter', type: :merge_requests

View File

@ -2,14 +2,13 @@
- page_title 'Milestones'
- header_title 'Milestones', dashboard_milestones_path
- if show_new_nav?
- content_for :breadcrumbs_extra do
= render 'shared/new_project_item_select', path: 'milestones/new', label: 'New milestone', include_groups: true, type: :milestones
- content_for :breadcrumbs_extra do
= render 'shared/new_project_item_select', path: 'milestones/new', label: 'New milestone', include_groups: true, type: :milestones
.top-area
= render 'shared/milestones_filter', counts: @milestone_states
.nav-controls{ class: ("visible-xs" if show_new_nav?) }
.nav-controls.visible-xs
= render 'shared/new_project_item_select', path: 'milestones/new', label: 'New milestone', include_groups: true, type: :milestones
.milestones

View File

@ -8,7 +8,7 @@
= webpack_bundle_tag 'common_vue'
= webpack_bundle_tag 'filtered_search'
- if show_new_nav? && group_issues_exists
- if group_issues_exists
- content_for :breadcrumbs_extra do
= link_to params.merge(rss_url_options), class: 'btn btn-default append-right-10' do
= icon('rss')
@ -19,7 +19,7 @@
- if group_issues_exists
.top-area
= render 'shared/issuable/nav', type: :issues
.nav-controls{ class: ("visible-xs" if show_new_nav?) }
.nav-controls.visible-xs
= link_to params.merge(rss_url_options), class: 'btn' do
= icon('rss')
%span.icon-label

View File

@ -1,5 +1,5 @@
- page_title 'Labels'
- if show_new_nav? && can?(current_user, :admin_label, @group)
- if can?(current_user, :admin_label, @group)
- content_for :breadcrumbs_extra do
= link_to "New label", new_group_label_path(@group), class: "btn btn-new"
@ -10,7 +10,7 @@
.nav-text
Labels can be applied to issues and merge requests. Group labels are available for any project within the group.
.nav-controls{ class: ("visible-xs" if show_new_nav?) }
.nav-controls.visible-xs
- if can?(current_user, :admin_label, @group)
= link_to "New label", new_group_label_path(@group), class: "btn btn-new"

View File

@ -4,7 +4,7 @@
= webpack_bundle_tag 'common_vue'
= webpack_bundle_tag 'filtered_search'
- if show_new_nav? && current_user
- if current_user
- content_for :breadcrumbs_extra do
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", type: :merge_requests
@ -14,7 +14,7 @@
.top-area
= render 'shared/issuable/nav', type: :merge_requests
- if current_user
.nav-controls{ class: ("visible-xs" if show_new_nav?) }
.nav-controls.visible-xs
= render 'shared/new_project_item_select', path: 'merge_requests/new', label: "New merge request", type: :merge_requests
= render 'shared/issuable/search_bar', type: :merge_requests

View File

@ -1,5 +1,5 @@
- page_title "Milestones"
- if show_new_nav? && can?(current_user, :admin_milestones, @group)
- if can?(current_user, :admin_milestones, @group)
- content_for :breadcrumbs_extra do
= link_to "New milestone", new_group_milestone_path(@group), class: "btn btn-new"
@ -8,7 +8,7 @@
.top-area
= render 'shared/milestones_filter', counts: @milestone_states
.nav-controls{ class: ("visible-xs" if show_new_nav?) }
.nav-controls.visible-xs
- if can?(current_user, :admin_milestones, @group)
= link_to "New milestone", new_group_milestone_path(@group), class: "btn btn-new"

View File

@ -32,9 +32,9 @@
= stylesheet_link_tag "test", media: "all" if Rails.env.test?
= stylesheet_link_tag 'performance_bar' if performance_bar_enabled?
- if show_new_nav?
= stylesheet_link_tag "new_nav", media: "all"
= stylesheet_link_tag "new_sidebar", media: "all"
// TODO: Combine these 2 stylesheets into application.scss
= stylesheet_link_tag "new_nav", media: "all"
= stylesheet_link_tag "new_sidebar", media: "all"
= Gon::Base.render_data

View File

@ -1,26 +1,14 @@
.page-with-sidebar{ class: page_with_sidebar_class }
- if show_new_nav?
- if defined?(nav) && nav
= render "layouts/nav/#{nav}"
- else
- if defined?(nav) && nav
.layout-nav
.container-fluid
= render "layouts/nav/#{nav}"
- if content_for?(:sub_nav)
= yield :sub_nav
.content-wrapper{ class: layout_nav_class }
- if show_new_nav?
.mobile-overlay
- if defined?(nav) && nav
= render "layouts/nav/sidebar/#{nav}"
.content-wrapper.page-with-new-nav
.mobile-overlay
.alert-wrapper
= render "layouts/broadcast"
- if show_new_nav?
- if content_for?(:new_global_flash)
= yield :new_global_flash
- unless @hide_breadcrumbs
= render "layouts/nav/breadcrumbs"
= render "layouts/flash"
= yield :flash_message
- unless @hide_breadcrumbs
= render "layouts/nav/breadcrumbs"
= render "layouts/flash"
%div{ class: "#{(container_class unless @no_container)} #{@content_class}" }
.content{ id: "content-body" }
= yield

View File

@ -1,9 +1,6 @@
- page_title "Admin Area"
- header_title "Admin Area", admin_root_path
- if show_new_nav?
- nav "new_admin_sidebar"
- @new_sidebar = true
- else
- nav "admin"
- nav "admin"
- @left_sidebar = true
= render template: "layouts/application"

View File

@ -4,10 +4,7 @@
%body{ class: @body_class, data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}", find_file: find_file_path } }
= render "layouts/init_auto_complete" if @gfm_form
= render 'peek/bar'
- if show_new_nav?
= render "layouts/header/new"
- else
= render "layouts/header/default", title: header_title
= render "layouts/header/default"
= render 'layouts/page', sidebar: sidebar, nav: nav
= yield :scripts_body

View File

@ -1,10 +1,7 @@
- page_title @group.name
- page_description @group.description unless page_description
- header_title group_title(@group) unless header_title
- if show_new_nav?
- nav "new_group_sidebar"
- @new_sidebar = true
- else
- nav "group"
- nav "group"
- @left_sidebar = true
= render template: "layouts/application"

View File

@ -1,68 +1,50 @@
%header.navbar.navbar-gitlab{ class: nav_header_class }
.navbar-border
%header.navbar.navbar-gitlab.navbar-gitlab-new
%a.sr-only.gl-accessibility{ href: "#content-body", tabindex: "1" } Skip to content
.container-fluid
.header-content
.dropdown.global-dropdown
%button.global-dropdown-toggle{ type: 'button', 'data-toggle' => 'dropdown' }
%span.sr-only Toggle navigation
= icon('bars')
.dropdown-menu-nav.global-dropdown-menu
- if current_user
= render 'layouts/nav/dashboard'
- else
= render 'layouts/nav/explore'
.title-container
%h1.title
= link_to root_path, title: 'Dashboard', id: 'logo' do
= brand_header_logo
%span.logo-text.hidden-xs
= render 'shared/logo_type.svg'
.header-logo
= link_to root_path, class: 'home', title: 'Dashboard', id: 'logo' do
= brand_header_logo
.title-container.js-title-container
%h1.title{ class: ('initializing' if @has_group_title) }= title
- if current_user
= render "layouts/nav/dashboard"
- else
= render "layouts/nav/explore"
.navbar-collapse.collapse
%ul.nav.navbar-nav
- if current_user
= render 'layouts/header/new_dropdown'
%li.hidden-sm.hidden-xs
= render 'layouts/search' unless current_controller?(:search)
%li.visible-sm-inline-block.visible-xs-inline-block
= link_to search_path, title: 'Search', aria: { label: "Search" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('search')
- if current_user
- if session[:impersonator_id]
%li.impersonation
= link_to admin_impersonation_path, method: :delete, title: "Stop impersonation", aria: { label: 'Stop impersonation' }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
= icon('user-secret fw')
- if current_user.admin?
%li
= link_to admin_root_path, title: 'Admin area', aria: { label: "Admin area" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('wrench fw')
= render 'layouts/header/new_dropdown'
- if Gitlab::Sherlock.enabled?
%li
= link_to sherlock_transactions_path, title: 'Sherlock Transactions',
data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('tachometer fw')
%li
= link_to assigned_issues_dashboard_path, title: 'Issues', aria: { label: "Issues" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
%li.user-counter
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues', aria: { label: "Issues" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= custom_icon('issues')
- issues_count = assigned_issuables_count(:issues)
%span.badge.issues-count{ class: ('hidden' if issues_count.zero?) }
= number_with_delimiter(issues_count)
%li
= link_to assigned_mrs_dashboard_path, title: 'Merge requests', aria: { label: "Merge requests" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
%li.user-counter
= link_to assigned_mrs_dashboard_path, title: 'Merge requests', class: 'dashboard-shortcuts-merge_requests', aria: { label: "Merge requests" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= custom_icon('mr_bold')
- merge_requests_count = assigned_issuables_count(:merge_requests)
%span.badge.merge-requests-count{ class: ('hidden' if merge_requests_count.zero?) }
= number_with_delimiter(merge_requests_count)
%li
%li.user-counter
= link_to dashboard_todos_path, title: 'Todos', aria: { label: "Todos" }, class: 'shortcuts-todos', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('check-circle fw')
= custom_icon('todo_done')
%span.badge.todos-count{ class: ('hidden' if todos_pending_count.zero?) }
= todos_count_format(todos_pending_count)
%li.header-user.dropdown
= link_to current_user, class: "header-user-dropdown-toggle", data: { toggle: "dropdown" } do
= image_tag avatar_icon(current_user, 26), width: 26, height: 26, class: "header-user-avatar"
= icon('caret-down')
= link_to current_user, class: user_dropdown_class, data: { toggle: "dropdown" } do
= image_tag avatar_icon(current_user, 23), width: 23, height: 23, class: "header-user-avatar"
= custom_icon('caret_down')
.dropdown-menu-nav.dropdown-menu-align-right
%ul
%li.current-user
@ -74,18 +56,24 @@
= link_to "Profile", current_user, class: 'profile-link', data: { user: current_user.username }
%li
= link_to "Settings", profile_path
- if current_user
%li
= link_to "Help", help_path
%li.divider
%li
= link_to "Sign out", destroy_user_session_path, method: :delete, class: "sign-out-link"
- if session[:impersonator_id]
%li.impersonation
= link_to admin_impersonation_path, class: 'impersonation-btn', method: :delete, title: "Stop impersonation", aria: { label: 'Stop impersonation' }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
= icon('user-secret')
- else
%li
%div
= link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in btn-success'
= link_to "Sign in / Register", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in'
%button.navbar-toggle{ type: 'button' }
%button.navbar-toggle.hidden-sm.hidden-md.hidden-lg{ type: 'button' }
%span.sr-only Toggle navigation
= icon('ellipsis-v')
= yield :header_content
= icon('ellipsis-v', class: 'js-navbar-toggle-right')
= icon('times', class: 'js-navbar-toggle-left')
= render 'shared/outdated_browser'

View File

@ -1,84 +0,0 @@
%header.navbar.navbar-gitlab.navbar-gitlab-new{ class: nav_header_class }
%a.sr-only.gl-accessibility{ href: "#content-body", tabindex: "1" } Skip to content
.container-fluid
.header-content
.title-container
%h1.title
= link_to root_path, title: 'Dashboard', id: 'logo' do
= brand_header_logo
%span.logo-text.hidden-xs
= render 'shared/logo_type.svg'
- if current_user
= render "layouts/nav/new_dashboard"
- else
= render "layouts/nav/new_explore"
.navbar-collapse.collapse
%ul.nav.navbar-nav
%li.hidden-sm.hidden-xs
= render 'layouts/search' unless current_controller?(:search)
%li.visible-sm-inline-block.visible-xs-inline-block
= link_to search_path, title: 'Search', aria: { label: "Search" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('search')
- if current_user
- if session[:impersonator_id]
%li.impersonation
= link_to admin_impersonation_path, method: :delete, title: "Stop impersonation", aria: { label: 'Stop impersonation' }, data: { toggle: 'tooltip', placement: 'bottom', container: 'body' } do
= icon('user-secret fw')
- if current_user.admin?
%li
= link_to admin_root_path, title: 'Admin area', aria: { label: "Admin area" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('wrench fw')
= render 'layouts/header/new_dropdown'
- if Gitlab::Sherlock.enabled?
%li
= link_to sherlock_transactions_path, title: 'Sherlock Transactions',
data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('tachometer fw')
%li
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues', aria: { label: "Issues" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= custom_icon('issues')
- issues_count = assigned_issuables_count(:issues)
%span.badge.issues-count{ class: ('hidden' if issues_count.zero?) }
= number_with_delimiter(issues_count)
%li
= link_to assigned_mrs_dashboard_path, title: 'Merge requests', class: 'dashboard-shortcuts-merge_requests', aria: { label: "Merge requests" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= custom_icon('mr_bold')
- merge_requests_count = assigned_issuables_count(:merge_requests)
%span.badge.merge-requests-count{ class: ('hidden' if merge_requests_count.zero?) }
= number_with_delimiter(merge_requests_count)
%li
= link_to dashboard_todos_path, title: 'Todos', aria: { label: "Todos" }, class: 'shortcuts-todos', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('check-circle fw')
%span.badge.todos-count{ class: ('hidden' if todos_pending_count.zero?) }
= todos_count_format(todos_pending_count)
%li.header-user.dropdown
= link_to current_user, class: "header-user-dropdown-toggle", data: { toggle: "dropdown" } do
= image_tag avatar_icon(current_user, 26), width: 26, height: 26, class: "header-user-avatar"
= icon('chevron-down')
.dropdown-menu-nav.dropdown-menu-align-right
%ul
%li.current-user
.user-name.bold
= current_user.name
@#{current_user.username}
%li.divider
%li
= link_to "Profile", current_user, class: 'profile-link', data: { user: current_user.username }
%li
= link_to "Settings", profile_path
%li.divider
%li
= link_to "Sign out", destroy_user_session_path, method: :delete, class: "sign-out-link"
- else
%li
%div
= link_to "Sign in", new_session_path(:user, redirect_to_referer: 'yes'), class: 'btn btn-sign-in btn-success'
%button.navbar-toggle.hidden-sm.hidden-md.hidden-lg{ type: 'button' }
%span.sr-only Toggle navigation
= icon('ellipsis-v', class: 'js-navbar-toggle-right')
= icon('times', class: 'js-navbar-toggle-left')
= render 'shared/outdated_browser'

View File

@ -1,11 +1,7 @@
%li.header-new.dropdown
= link_to new_project_path, class: "header-new-dropdown-toggle has-tooltip", title: "New...", ref: 'tooltip', aria: { label: "New..." }, data: { toggle: 'dropdown', placement: 'bottom', container: 'body' } do
- if show_new_nav?
= icon('plus')
= icon('chevron-down')
- else
= icon('plus fw')
= icon('caret-down')
= custom_icon('plus_square')
= custom_icon('caret_down')
.dropdown-menu-nav.dropdown-menu-align-right
%ul
- if @group&.persisted?

View File

@ -1,40 +0,0 @@
= render 'layouts/nav/admin_settings'
.scrolling-tabs-container{ class: nav_control_class }
.fade-left
= icon('angle-left')
.fade-right
= icon('angle-right')
%ul.nav-links.scrolling-tabs
= nav_link(controller: %w(dashboard admin projects users groups builds runners cohorts), html_options: {class: 'home'}) do
= link_to admin_root_path, title: 'Overview', class: 'shortcuts-tree' do
%span
Overview
= nav_link(controller: %w(conversational_development_index system_info background_jobs logs health_check requests_profiles)) do
= link_to admin_conversational_development_index_path, title: 'Monitoring' do
%span
Monitoring
= nav_link(controller: :broadcast_messages) do
= link_to admin_broadcast_messages_path, title: 'Messages' do
%span
Messages
= nav_link(controller: [:hooks, :hook_logs]) do
= link_to admin_hooks_path, title: 'Hooks' do
%span
System Hooks
= nav_link(controller: :applications) do
= link_to admin_applications_path, title: 'Applications' do
%span
Applications
= nav_link(controller: :abuse_reports) do
= link_to admin_abuse_reports_path, title: "Abuse Reports" do
%span
Abuse Reports
%span.badge.count= number_with_delimiter(AbuseReport.count(:all))
- if akismet_enabled?
= nav_link(controller: :spam_logs) do
= link_to admin_spam_logs_path, title: "Spam Logs" do
%span
Spam Logs

View File

@ -1,31 +0,0 @@
.controls
.dropdown.admin-settings-dropdown
%a.dropdown-new.btn.btn-default{ href: '#', 'data-toggle' => 'dropdown' }
= icon('cog')
= icon('caret-down')
%ul.dropdown-menu.dropdown-menu-align-right
= nav_link(controller: :deploy_keys) do
= link_to admin_deploy_keys_path, title: 'Deploy Keys' do
%span
Deploy Keys
= nav_link(controller: :services) do
= link_to admin_application_settings_services_path, title: 'Service Templates' do
%span
Service Templates
= nav_link(controller: :labels) do
= link_to admin_labels_path, title: 'Labels' do
%span
Labels
= nav_link(controller: :appearances) do
= link_to admin_appearances_path, title: 'Appearances' do
%span
Appearance
%li.divider
= nav_link(controller: :application_settings) do
= link_to admin_application_settings_path, title: 'Settings' do
%span
Settings

View File

@ -2,8 +2,8 @@
- hide_top_links = @hide_top_links || false
%nav.breadcrumbs{ role: "navigation", class: [container, @content_class] }
.breadcrumbs-container
- if defined?(@new_sidebar)
.breadcrumbs-container{ class: [container, @content_class] }
- if defined?(@left_sidebar)
= button_tag class: 'toggle-mobile-nav', type: 'button' do
%span.sr-only Open sidebar
= icon ('bars')

View File

@ -1,67 +1,62 @@
%ul
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: {class: "#{project_tab_class} home"}) do
= link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
.shortcut-mappings
.key
= icon('arrow-up', 'aria-label' => 'hidden')
P
%span
Projects
= nav_link(path: 'dashboard#activity') do
= link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do
.shortcut-mappings
.key
= icon('arrow-up', 'aria-label' => 'hidden')
A
%span
Activity
- if koding_enabled?
= nav_link(controller: :koding) do
= link_to koding_path, title: 'Koding' do
%span
Koding
= nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do
%ul.list-unstyled.navbar-sub-nav
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: { id: 'nav-projects-dropdown', class: "home dropdown" }) do
%a{ href: "#", data: { toggle: "dropdown" } }
Projects
= custom_icon('caret_down')
.dropdown-menu.projects-dropdown-menu
= render "layouts/nav/projects_dropdown/show"
= nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { class: "hidden-xs" }) do
= link_to dashboard_groups_path, class: 'dashboard-shortcuts-groups', title: 'Groups' do
.shortcut-mappings
.key
= icon('arrow-up', 'aria-label' => 'hidden')
G
%span
Groups
= nav_link(controller: 'dashboard/milestones') do
Groups
= nav_link(path: 'dashboard#activity', html_options: { class: "visible-lg" }) do
= link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do
Activity
= nav_link(controller: 'dashboard/milestones', html_options: { class: "visible-lg" }) do
= link_to dashboard_milestones_path, class: 'dashboard-shortcuts-milestones', title: 'Milestones' do
.shortcut-mappings
.key
= icon('arrow-up', 'aria-label' => 'hidden')
L
%span
Milestones
= nav_link(path: 'dashboard#issues') do
= link_to assigned_issues_dashboard_path, title: 'Issues', class: 'dashboard-shortcuts-issues' do
.shortcut-mappings
.key
= icon('arrow-up', 'aria-label' => 'hidden')
I
%span.badge.pull-right= number_with_delimiter(assigned_issuables_count(:issues))
%span
Issues
= nav_link(path: 'dashboard#merge_requests') do
= link_to assigned_mrs_dashboard_path, title: 'Merge Requests', class: 'dashboard-shortcuts-merge_requests' do
.shortcut-mappings
.key
= icon('arrow-up', 'aria-label' => 'hidden')
M
%span.badge.pull-right= number_with_delimiter(assigned_issuables_count(:merge_requests))
%span
Merge Requests
= nav_link(controller: 'dashboard/snippets') do
Milestones
= nav_link(controller: 'dashboard/snippets', html_options: { class: "visible-lg" }) do
= link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets', title: 'Snippets' do
.shortcut-mappings
.key
= icon('arrow-up', 'aria-label' => 'hidden')
S
%span
Snippets
%li.divider
%li
= link_to "Help", help_path, title: 'About GitLab CE', class: 'about-gitlab'
Snippets
%li.dropdown.hidden-lg
%a{ href: "#", data: { toggle: "dropdown" } }
More
= custom_icon('caret_down')
.dropdown-menu
%ul
= nav_link(controller: ['dashboard/groups', 'explore/groups'], html_options: { class: "visible-xs" }) do
= link_to dashboard_groups_path, class: 'dashboard-shortcuts-groups', title: 'Groups' do
Groups
= nav_link(path: 'dashboard#activity') do
= link_to activity_dashboard_path, title: 'Activity' do
Activity
= nav_link(controller: 'dashboard/milestones') do
= link_to dashboard_milestones_path, class: 'dashboard-shortcuts-milestones', title: 'Milestones' do
Milestones
= nav_link(controller: 'dashboard/snippets') do
= link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets', title: 'Snippets' do
Snippets
-# Shortcut to Dashboard > Projects
%li.hidden
= link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
Projects
- if current_user.admin? || Gitlab::Sherlock.enabled?
%li.line-separator.hidden-xs
- if current_user.admin?
= nav_link(controller: 'admin/dashboard') do
= link_to admin_root_path, class: 'admin-icon', title: 'Admin area', aria: { label: "Admin area" }, data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('wrench fw')
- if Gitlab::Sherlock.enabled?
%li
= link_to sherlock_transactions_path, class: 'admin-icon', title: 'Sherlock Transactions',
data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('tachometer fw')

View File

@ -1,30 +1,12 @@
%ul
%ul.list-unstyled.navbar-sub-nav
= nav_link(path: ['dashboard#show', 'root#show', 'projects#trending', 'projects#starred', 'projects#index'], html_options: {class: 'home'}) do
= link_to explore_root_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
.shortcut-mappings
.key
= icon('arrow-up', 'aria-label' => 'hidden')
P
%span
Projects
Projects
= nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do
= link_to explore_groups_path, title: 'Groups', class: 'dashboard-shortcuts-groups' do
.shortcut-mappings
.key
= icon('arrow-up', 'aria-label' => 'hidden')
G
%span
Groups
Groups
= nav_link(controller: :snippets) do
= link_to explore_snippets_path, title: 'Snippets', class: 'dashboard-shortcuts-snippets' do
.shortcut-mappings
.key
= icon('arrow-up', 'aria-label' => 'hidden')
S
%span
Snippets
%li.divider
= nav_link(controller: :help) do
= link_to help_path, title: 'Help' do
%span
Help
Snippets
%li
= link_to "Help", help_path, title: 'About GitLab CE'

View File

@ -1,31 +0,0 @@
.scrolling-tabs-container{ class: nav_control_class }
.fade-left
= icon('angle-left')
.fade-right
= icon('angle-right')
%ul.nav-links.scrolling-tabs
= nav_link(path: ['groups#show', 'groups#activity', 'groups#subgroups'], html_options: { class: 'home' }) do
= link_to group_path(@group), title: 'Home' do
%span
Group
= nav_link(path: ['groups#issues', 'labels#index', 'milestones#index']) do
= link_to issues_group_path(@group), title: 'Issues' do
%span
Issues
- issues = IssuesFinder.new(current_user, group_id: @group.id, state: 'opened').execute
%span.badge.count= number_with_delimiter(issues.count)
= nav_link(path: 'groups#merge_requests') do
= link_to merge_requests_group_path(@group), title: 'Merge Requests' do
%span
Merge Requests
- merge_requests = MergeRequestsFinder.new(current_user, group_id: @group.id, state: 'opened', non_archived: true).execute
%span.badge.count= number_with_delimiter(merge_requests.count)
= nav_link(path: 'group_members#index') do
= link_to group_group_members_path(@group), title: 'Members' do
%span
Members
- if current_user && can?(current_user, :admin_group, @group)
= nav_link(path: %w[groups#projects groups#edit ci_cd#show]) do
= link_to edit_group_path(@group), title: 'Settings' do
%span
Settings

View File

@ -1,41 +0,0 @@
%ul.list-unstyled.navbar-sub-nav
= nav_link(path: ['root#index', 'projects#trending', 'projects#starred', 'dashboard/projects#index'], html_options: { id: 'nav-projects-dropdown', class: "home dropdown" }) do
%a{ href: '#', title: 'Projects', data: { toggle: 'dropdown' } }
Projects
= icon("chevron-down", class: "dropdown-chevron")
.dropdown-menu.projects-dropdown-menu
= render "layouts/nav/projects_dropdown/show"
= nav_link(controller: ['dashboard/groups', 'explore/groups']) do
= link_to dashboard_groups_path, class: 'dashboard-shortcuts-groups', title: 'Groups' do
Groups
= nav_link(path: 'dashboard#activity', html_options: { class: "hidden-xs hidden-sm hidden-md" }) do
= link_to activity_dashboard_path, class: 'dashboard-shortcuts-activity', title: 'Activity' do
Activity
%li.dropdown
%a{ href: "#", data: { toggle: "dropdown" } }
More
= icon("chevron-down", class: "dropdown-chevron")
.dropdown-menu
%ul
= nav_link(path: 'dashboard#activity', html_options: { class: "visible-xs visible-sm visible-md" }) do
= link_to activity_dashboard_path, title: 'Activity' do
Activity
= nav_link(controller: 'dashboard/milestones') do
= link_to dashboard_milestones_path, class: 'dashboard-shortcuts-milestones', title: 'Milestones' do
Milestones
= nav_link(controller: 'dashboard/snippets') do
= link_to dashboard_snippets_path, class: 'dashboard-shortcuts-snippets', title: 'Snippets' do
Snippets
%li.divider
%li
= link_to "Help", help_path, title: 'About GitLab CE'
-# Shortcut to Dashboard > Projects
%li.hidden
= link_to dashboard_projects_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
Projects

View File

@ -1,19 +0,0 @@
%ul.list-unstyled.navbar-sub-nav
= nav_link(path: ['dashboard#show', 'root#show', 'projects#trending', 'projects#starred', 'projects#index'], html_options: {class: 'home'}) do
= link_to explore_root_path, title: 'Projects', class: 'dashboard-shortcuts-projects' do
Projects
= nav_link(controller: [:groups, 'groups/milestones', 'groups/group_members']) do
= link_to explore_groups_path, title: 'Groups', class: 'dashboard-shortcuts-groups' do
Groups
%li.dropdown
%a{ href: "#", data: { toggle: "dropdown" } }
More
= icon("chevron-down", class: "dropdown-chevron")
.dropdown-menu
%ul
= nav_link(controller: :snippets) do
= link_to explore_snippets_path, title: 'Snippets', class: 'dashboard-shortcuts-snippets' do
Snippets
%li.divider
%li
= link_to "Help", help_path, title: 'About GitLab CE'

View File

@ -1,57 +0,0 @@
.scrolling-tabs-container
.fade-left
= icon('angle-left')
.fade-right
= icon('angle-right')
%ul.nav-links.scrolling-tabs
= nav_link(path: 'profiles#show', html_options: {class: 'home'}) do
= link_to profile_path, title: 'Profile Settings' do
%span
Profile
= nav_link(controller: [:accounts, :two_factor_auths]) do
= link_to profile_account_path, title: 'Account' do
%span
Account
- if current_application_settings.user_oauth_applications?
= nav_link(controller: 'oauth/applications') do
= link_to applications_profile_path, title: 'Applications' do
%span
Applications
= nav_link(controller: :chat_names) do
= link_to profile_chat_names_path, title: 'Chat' do
%span
Chat
= nav_link(controller: :personal_access_tokens) do
= link_to profile_personal_access_tokens_path, title: 'Access Tokens' do
%span
Access Tokens
= nav_link(controller: :emails) do
= link_to profile_emails_path, title: 'Emails' do
%span
Emails
- unless current_user.ldap_user?
= nav_link(controller: :passwords) do
= link_to edit_profile_password_path, title: 'Password' do
%span
Password
= nav_link(controller: :notifications) do
= link_to profile_notifications_path, title: 'Notifications' do
%span
Notifications
= nav_link(controller: :keys) do
= link_to profile_keys_path, title: 'SSH Keys' do
%span
SSH Keys
= nav_link(controller: :gpg_keys) do
= link_to profile_gpg_keys_path, title: 'GPG Keys' do
%span
GPG Keys
= nav_link(controller: :preferences) do
= link_to profile_preferences_path, title: 'Preferences' do
%span
Preferences
= nav_link(path: 'profiles#audit_log') do
= link_to audit_log_profile_path, title: 'Authentication log' do
%span
Authentication log

View File

@ -1,111 +0,0 @@
- can_edit = can?(current_user, :admin_project, @project)
.scrolling-tabs-container{ class: nav_control_class }
.fade-left
= icon('angle-left')
.fade-right
= icon('angle-right')
%ul.nav-links.scrolling-tabs
= nav_link(path: ['projects#show', 'projects#activity', 'cycle_analytics#show'], html_options: { class: 'home' }) do
= link_to project_path(@project), title: 'Project', class: 'shortcuts-project' do
%span
Project
- if project_nav_tab? :files
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file commit commits compare projects/repositories tags branches releases graphs network)) do
= link_to project_tree_path(@project), title: 'Repository', class: 'shortcuts-tree' do
%span
Repository
- if project_nav_tab? :container_registry
= nav_link(controller: %w[projects/registry/repositories]) do
= link_to project_container_registry_index_path(@project), title: 'Container Registry', class: 'shortcuts-container-registry' do
%span
Registry
- if project_nav_tab? :issues
= nav_link(controller: @project.issues_enabled? ? [:issues, :labels, :milestones, :boards] : :issues) do
= link_to project_issues_path(@project), title: 'Issues', class: 'shortcuts-issues' do
%span
Issues
- if @project.issues_enabled?
%span.badge.count.issue_counter
= number_with_delimiter(@project.open_issues_count)
- if project_nav_tab? :merge_requests
- controllers = [:merge_requests, 'projects/merge_requests/conflicts']
- controllers.push(:merge_requests, :labels, :milestones) unless @project.issues_enabled?
= nav_link(controller: controllers) do
= link_to project_merge_requests_path(@project), title: 'Merge Requests', class: 'shortcuts-merge_requests' do
%span
Merge Requests
%span.badge.count.merge_counter.js-merge-counter
= number_with_delimiter(@project.open_merge_requests_count)
- if project_nav_tab? :pipelines
= nav_link(controller: [:pipelines, :builds, :environments, :artifacts]) do
= link_to project_pipelines_path(@project), title: 'Pipelines', class: 'shortcuts-pipelines' do
%span
Pipelines
- if project_nav_tab? :wiki
= nav_link(controller: :wikis) do
= link_to get_project_wiki_path(@project), title: 'Wiki', class: 'shortcuts-wiki' do
%span
Wiki
- if project_nav_tab? :snippets
= nav_link(controller: :snippets) do
= link_to project_snippets_path(@project), title: 'Snippets', class: 'shortcuts-snippets' do
%span
Snippets
- if project_nav_tab? :project_members
= nav_link(controller: :project_members) do
= link_to project_project_members_path(@project), title: 'Members', class: 'shortcuts-members' do
%span
Members
- if project_nav_tab? :settings
= nav_link(path: %w[projects#edit members#show integrations#show services#edit repository#show ci_cd#show pages#show]) do
= link_to edit_project_path(@project), title: 'Settings', class: 'shortcuts-tree' do
%span
Settings
-# Shortcut to Project > Activity
%li.hidden
= link_to activity_project_path(@project), title: 'Activity', class: 'shortcuts-project-activity' do
%span
Activity
-# Shortcut to Repository > Graph (formerly, Network)
- if project_nav_tab? :network
%li.hidden
= link_to project_network_path(@project, current_ref), title: 'Network', class: 'shortcuts-network' do
Graph
-# Shortcut to Repository > Charts (formerly, top-nav item "Graphs")
- unless @project.empty_repo?
%li.hidden
= link_to charts_project_graph_path(@project, current_ref), title: 'Charts', class: 'shortcuts-repository-charts' do
Charts
-# Shortcut to Issues > New Issue
%li.hidden
= link_to new_project_issue_path(@project), class: 'shortcuts-new-issue' do
Create a new issue
-# Shortcut to Pipelines > Jobs
- if project_nav_tab? :builds
%li.hidden
= link_to project_jobs_path(@project), title: 'Jobs', class: 'shortcuts-builds' do
Jobs
-# Shortcut to commits page
- if project_nav_tab? :commits
%li.hidden
= link_to project_commits_path(@project), title: 'Commits', class: 'shortcuts-commits' do
Commits
-# Shortcut to issue boards
%li.hidden
= link_to 'Issue Boards', project_boards_path(@project), title: 'Issue Boards', class: 'shortcuts-issue-boards'

View File

@ -1,10 +1,7 @@
- page_title "User Settings"
- header_title "User Settings", profile_path unless header_title
- sidebar "dashboard"
- if show_new_nav?
- nav "new_profile_sidebar"
- @new_sidebar = true
- else
- nav "profile"
- nav "profile"
- @left_sidebar = true
= render template: "layouts/application"

View File

@ -1,11 +1,8 @@
- page_title @project.name_with_namespace
- page_description @project.description unless page_description
- header_title project_title(@project) unless header_title
- if show_new_nav?
- nav "new_project_sidebar"
- @new_sidebar = true
- else
- nav "project"
- nav "project"
- @left_sidebar = true
- content_for :project_javascripts do
- project = @target_project || @project

View File

@ -1,8 +1,5 @@
- page_title 'Two-Factor Authentication', 'Account'
- if show_new_nav?
- add_to_breadcrumbs("Account", profile_account_path)
- else
- header_title "Two-Factor Authentication", profile_two_factor_auth_path
- add_to_breadcrumbs("Account", profile_account_path)
- @content_class = "limit-container-width" unless fluid_layout
= render 'profiles/head'

View File

@ -1,7 +1,6 @@
- project = local_assigns.fetch(:project)
- flash_message_container = show_new_nav? ? :new_global_flash : :flash_message
= content_for flash_message_container do
= content_for :flash_message do
= render partial: 'deletion_failed', locals: { project: project }
- if current_user && can?(current_user, :download_code, project)
= render 'shared/no_ssh'

View File

@ -1,5 +1,6 @@
- @no_container = true
- page_title "Environments"
- add_to_breadcrumbs("Pipelines", project_pipelines_path(@project))
= render "projects/pipelines/head"
- content_for :page_specific_javascripts do

View File

@ -13,15 +13,14 @@
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{@project.name} issues")
- if show_new_nav?
- content_for :breadcrumbs_extra do
= render "projects/issues/nav_btns"
- content_for :breadcrumbs_extra do
= render "projects/issues/nav_btns"
- if project_issues(@project).exists?
%div{ class: (container_class) }
.top-area
= render 'shared/issuable/nav', type: :issues
.nav-controls{ class: ("visible-xs" if show_new_nav?) }
.nav-controls.visible-xs
= render "projects/issues/nav_btns"
= render 'shared/issuable/search_bar', type: :issues

View File

@ -39,8 +39,7 @@
%ul
- if can_update_issue
%li= link_to 'Edit', edit_project_issue_path(@project, @issue)
/ TODO: simplify condition back #36860
- if @issue.author && current_user != @issue.author
- unless current_user == @issue.author
%li= link_to 'Report abuse', new_abuse_report_path(user_id: @issue.author.id, ref_url: issue_url(@issue))
- if can_update_issue
%li= link_to 'Close issue', issue_path(@issue, issue: { state_event: :close }, format: 'json'), class: "btn-close js-btn-issue-action #{issue_button_visibility(@issue, true)}", title: 'Close issue'

View File

@ -3,7 +3,7 @@
- hide_class = ''
- can_admin_label = can?(current_user, :admin_label, @project)
- if show_new_nav? && can?(current_user, :admin_label, @project)
- if can?(current_user, :admin_label, @project)
- content_for :breadcrumbs_extra do
= link_to "New label", new_namespace_project_label_path(@project.namespace, @project), class: "btn btn-new"
@ -18,7 +18,7 @@
Star a label to make it a priority label. Order the prioritized labels to change their relative priority, by dragging.
- if can_admin_label
.nav-controls{ class: ("visible-xs" if show_new_nav?) }
.nav-controls.visible-xs
= link_to new_project_label_path(@project), class: "btn btn-new" do
New label

View File

@ -12,9 +12,8 @@
= webpack_bundle_tag 'common_vue'
= webpack_bundle_tag 'filtered_search'
- if show_new_nav?
- content_for :breadcrumbs_extra do
= render "projects/merge_requests/nav_btns", merge_project: merge_project, new_merge_request_path: new_merge_request_path
- content_for :breadcrumbs_extra do
= render "projects/merge_requests/nav_btns", merge_project: merge_project, new_merge_request_path: new_merge_request_path
= render 'projects/last_push'
@ -22,7 +21,7 @@
%div{ class: container_class }
.top-area
= render 'shared/issuable/nav', type: :merge_requests
.nav-controls{ class: ("visible-xs" if show_new_nav?) }
.nav-controls.visible-xs
= render "projects/merge_requests/nav_btns", merge_project: merge_project, new_merge_request_path: new_merge_request_path
= render 'shared/issuable/search_bar', type: :merge_requests

View File

@ -1,7 +1,7 @@
- @no_container = true
- page_title 'Milestones'
- if show_new_nav? && can?(current_user, :admin_milestone, @project)
- if can?(current_user, :admin_milestone, @project)
- content_for :breadcrumbs_extra do
= link_to "New milestone", new_namespace_project_milestone_path(@project.namespace, @project), class: 'btn btn-new', title: 'New milestone'
@ -11,10 +11,10 @@
.top-area
= render 'shared/milestones_filter', counts: milestone_counts(@project.milestones)
.nav-controls{ class: ("nav-controls-new-nav" if show_new_nav?) }
.nav-controls.nav-controls-new-nav
= render 'shared/milestones_sort_dropdown'
- if can?(current_user, :admin_milestone, @project)
= link_to new_project_milestone_path(@project), class: "btn btn-new #{("visible-xs" if show_new_nav?)}", title: 'New milestone' do
= link_to new_project_milestone_path(@project), class: "btn btn-new visible-xs", title: 'New milestone' do
New milestone
.milestones

View File

@ -7,7 +7,7 @@
- @no_container = true
- page_title _("Pipeline Schedules")
- if show_new_nav? && can?(current_user, :create_pipeline_schedule, @project)
- if can?(current_user, :create_pipeline_schedule, @project)
- content_for :breadcrumbs_extra do
= link_to _('New schedule'), new_namespace_project_pipeline_schedule_path(@project.namespace, @project), class: 'btn btn-create'
@ -20,7 +20,7 @@
= render "tabs", schedule_path_proc: schedule_path_proc, all_schedules: @all_schedules, scope: @scope
- if can?(current_user, :create_pipeline_schedule, @project)
.nav-controls{ class: ("visible-xs" if show_new_nav?) }
.nav-controls.visible-xs
= link_to new_project_pipeline_schedule_path(@project), class: 'btn btn-create' do
%span= _('New schedule')

View File

@ -2,8 +2,7 @@
- @breadcrumb_link = namespace_project_pipeline_schedules_path(@project.namespace, @project)
- page_title _("New Pipeline Schedule")
- if show_new_nav?
- add_to_breadcrumbs("Pipelines", project_pipelines_path(@project))
- add_to_breadcrumbs("Pipelines", project_pipelines_path(@project))
%h3.page-title
= _("Schedule a new pipeline")

View File

@ -60,8 +60,21 @@
= f.check_box :public_builds
%strong Public pipelines
.help-block
Allow everyone to access pipelines for public and internal projects
Allow public access to pipelines and job details, including output logs and artifacts
= link_to icon('question-circle'), help_page_path('user/project/pipelines/settings', anchor: 'visibility-of-pipelines'), target: '_blank'
.bs-callout.bs-callout-info
%p If enabled:
%ul
%li
For public projects, anyone can view pipelines and access job details (output logs and artifacts)
%li
For internal projects, any logged in user can view pipelines and access job details (output logs and artifacts)
%li
For private projects, any member (guest or higher) can view pipelines and access job details (output logs and artifacts)
%p
If disabled, the access level will depend on the user's
permissions in the project.
%hr
.form-group
.checkbox

View File

@ -1,8 +1,6 @@
- breadcrumb_title "Integrations"
- page_title @service.title, "Services"
- if show_new_nav?
- add_to_breadcrumbs("Settings", edit_project_path(@project))
- add_to_breadcrumbs("Settings", edit_project_path(@project))
= render "projects/settings/head"
= render 'form'

View File

@ -1,6 +1,6 @@
- page_title "Snippets"
- if show_new_nav? && can?(current_user, :create_project_snippet, @project)
- if can?(current_user, :create_project_snippet, @project)
- content_for :breadcrumbs_extra do
= link_to "New snippet", new_namespace_project_snippet_path(@project.namespace, @project), class: "btn btn-new", title: "New snippet"
@ -9,7 +9,7 @@
- include_private = @project.team.member?(current_user) || current_user.admin?
= render partial: 'snippets/snippets_scope_menu', locals: { subject: @project, include_private: include_private }
.nav-controls{ class: ("visible-xs" if show_new_nav?) }
.nav-controls.visible-xs
- if can?(current_user, :create_project_snippet, @project)
= link_to "New snippet", new_project_snippet_path(@project), class: "btn btn-new", title: "New snippet"

View File

@ -1,6 +1,7 @@
- @no_container = true
- @sort ||= sort_value_recently_updated
- page_title "Tags"
- add_to_breadcrumbs("Repository", project_tree_path(@project))
= render "projects/commits/head"
.flex-list{ class: container_class }

View File

@ -1,4 +1,4 @@
<svg width="28" height="28" class="tanuki-logo" viewBox="0 0 36 36">
<svg width="24" height="24" class="tanuki-logo" viewBox="0 0 36 36">
<path class="tanuki-shape tanuki-left-ear" fill="#e24329" d="M2 14l9.38 9v-9l-4-12.28c-.205-.632-1.176-.632-1.38 0z"/>
<path class="tanuki-shape tanuki-right-ear" fill="#e24329" d="M34 14l-9.38 9v-9l4-12.28c.205-.632 1.176-.632 1.38 0z"/>
<path class="tanuki-shape tanuki-nose" fill="#e24329" d="M18,34.38 3,14 33,14 Z"/>

Before

Width:  |  Height:  |  Size: 834 B

After

Width:  |  Height:  |  Size: 834 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" class="caret-down" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8 10.243l-4.95-4.95a1 1 0 0 0-1.414 1.414l5.657 5.657a.997.997 0 0 0 1.414 0l5.657-5.657a1 1 0 0 0-1.414-1.414L8 10.243z"/></svg>

After

Width:  |  Height:  |  Size: 262 B

View File

@ -1,2 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path d="m5 5.563v4.875c1.024.4 1.75 1.397 1.75 2.563 0 1.519-1.231 2.75-2.75 2.75-1.519 0-2.75-1.231-2.75-2.75 0-1.166.726-2.162 1.75-2.563v-4.875c-1.024-.4-1.75-1.397-1.75-2.563 0-1.519 1.231-2.75 2.75-2.75 1.519 0 2.75 1.231 2.75 2.75 0 1.166-.726 2.162-1.75 2.563m-1 8.687c.69 0 1.25-.56 1.25-1.25 0-.69-.56-1.25-1.25-1.25-.69 0-1.25.56-1.25 1.25 0 .69.56 1.25 1.25 1.25m0-10c.69 0 1.25-.56 1.25-1.25 0-.69-.56-1.25-1.25-1.25-.69 0-1.25.56-1.25 1.25 0 .69.56 1.25 1.25 1.25"/><path d="m10.501 2c1.381.001 2.499 1.125 2.499 2.506v5.931c1.024.4 1.75 1.397 1.75 2.563 0 1.519-1.231 2.75-2.75 2.75-1.519 0-2.75-1.231-2.75-2.75 0-1.166.726-2.162 1.75-2.563v-5.931c0-.279-.225-.506-.499-.506v.926c0 .346-.244.474-.569.271l-2.952-1.844c-.314-.196-.325-.507 0-.71l2.952-1.844c.314-.196.569-.081.569.271v.93m1.499 12.25c.69 0 1.25-.56 1.25-1.25 0-.69-.56-1.25-1.25-1.25-.69 0-1.25.56-1.25 1.25 0 .69.56 1.25 1.25 1.25"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" height="16" width="16" viewBox="0 0 16 16"><path d="m5 5.563v4.875c1.024.4 1.75 1.397 1.75 2.563 0 1.519-1.231 2.75-2.75 2.75-1.519 0-2.75-1.231-2.75-2.75 0-1.166.726-2.162 1.75-2.563v-4.875c-1.024-.4-1.75-1.397-1.75-2.563 0-1.519 1.231-2.75 2.75-2.75 1.519 0 2.75 1.231 2.75 2.75 0 1.166-.726 2.162-1.75 2.563m-1 8.687c.69 0 1.25-.56 1.25-1.25 0-.69-.56-1.25-1.25-1.25-.69 0-1.25.56-1.25 1.25 0 .69.56 1.25 1.25 1.25m0-10c.69 0 1.25-.56 1.25-1.25 0-.69-.56-1.25-1.25-1.25-.69 0-1.25.56-1.25 1.25 0 .69.56 1.25 1.25 1.25"/><path d="m10.501 2c1.381.001 2.499 1.125 2.499 2.506v5.931c1.024.4 1.75 1.397 1.75 2.563 0 1.519-1.231 2.75-2.75 2.75-1.519 0-2.75-1.231-2.75-2.75 0-1.166.726-2.162 1.75-2.563v-5.931c0-.279-.225-.506-.499-.506v.926c0 .346-.244.474-.569.271l-2.952-1.844c-.314-.196-.325-.507 0-.71l2.952-1.844c.314-.196.569-.081.569.271v.93m1.499 12.25c.69 0 1.25-.56 1.25-1.25 0-.69-.56-1.25-1.25-1.25-.69 0-1.25.56-1.25 1.25 0 .69.56 1.25 1.25 1.25"/></svg>

Before

Width:  |  Height:  |  Size: 983 B

After

Width:  |  Height:  |  Size: 1005 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M9 7V4c0-.552-.448-1-1-1s-1 .448-1 1v3H4c-.552 0-1 .448-1 1s.448 1 1 1h3v3c0 .552.448 1 1 1s1-.448 1-1V9h3c.552 0 1-.448 1-1s-.448-1-1-1H9zM3 0h10c1.657 0 3 1.343 3 3v10c0 1.657-1.343 3-3 3H3c-1.657 0-3-1.343-3-3V3c0-1.657 1.343-3 3-3z"/></svg>

After

Width:  |  Height:  |  Size: 357 B

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><path d="M8.243 7.485l4.95-4.95a1 1 0 1 1 1.414 1.415L8.95 9.607a.997.997 0 0 1-1.414 0l-2.83-2.83a1 1 0 0 1 1.415-1.413l2.123 2.12zM12 11a1 1 0 0 1 2 0v2a3 3 0 0 1-3 3H3a3 3 0 0 1-3-3V5a3 3 0 0 1 3-3h2a1 1 0 1 1 0 2H3a1 1 0 0 0-1 1v8a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1v-2z"/></svg>

After

Width:  |  Height:  |  Size: 361 B

View File

@ -9,7 +9,6 @@
class: "hidden-xs hidden-sm btn btn-grouped btn-reopen js-btn-issue-action #{issuable_button_visibility(issuable, false)}", title: "Reopen #{display_issuable_type}"
- elsif can_update && !is_current_user
= render 'shared/issuable/close_reopen_report_toggle', issuable: issuable
- elsif issuable.author
/ TODO: change back to else #36860
- else
= link_to 'Report abuse', new_abuse_report_path(user_id: issuable.author.id, ref_url: issuable_url(issuable)),
class: 'hidden-xs hidden-sm btn btn-grouped btn-close-color', title: 'Report abuse'

View File

@ -37,15 +37,13 @@
%li.divider.droplab-item-ignore
/ TODO: remove condition #36860
- if issuable.author
%li.report-item{ data: { text: 'Report abuse', url: new_abuse_report_path(user_id: issuable.author.id, ref_url: issuable_url(issuable)),
button_class: "#{button_class} btn-close-color", toggle_class: "#{toggle_class} btn-close-color", method: '' } }
%button.btn.btn-transparent
= icon('check', class: 'icon')
.description
%strong.title Report abuse
%p.text
Report
= display_issuable_type.pluralize
that are abusive, inappropriate or spam.
%li.report-item{ data: { text: 'Report abuse', url: new_abuse_report_path(user_id: issuable.author.id, ref_url: issuable_url(issuable)),
button_class: "#{button_class} btn-close-color", toggle_class: "#{toggle_class} btn-close-color", method: '' } }
%button.btn.btn-transparent
= icon('check', class: 'icon')
.description
%strong.title Report abuse
%p.text
Report
= display_issuable_type.pluralize
that are abusive, inappropriate or spam.

View File

@ -3,7 +3,7 @@
= page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag('sidebar')
%aside.right-sidebar.js-right-sidebar.js-issuable-sidebar{ data: { "offset-top" => ("50" unless show_new_nav?), "spy" => ("affix" unless show_new_nav?), signed: { in: current_user.present? } }, class: sidebar_gutter_collapsed_class, 'aria-live' => 'polite' }
%aside.right-sidebar.js-right-sidebar.js-issuable-sidebar{ data: { signed: { in: current_user.present? } }, class: sidebar_gutter_collapsed_class, 'aria-live' => 'polite' }
.issuable-sidebar{ data: { endpoint: "#{issuable_json_path(issuable)}" } }
- can_edit_issuable = can?(current_user, :"admin_#{issuable.to_ability_name}", @project)
.block.issuable-sidebar-header

View File

@ -0,0 +1,5 @@
---
title: Update gpg documentation with gpg2
merge_request: 13851
author: M M Arif
type: other

View File

@ -0,0 +1,5 @@
---
title: Migrate issues authored by deleted user to the Ghost user
merge_request:
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: 'API: Add GPG key management'
merge_request: 13828
author: Robert Schilling
type: added

View File

@ -0,0 +1,5 @@
---
title: Support a multi-word fuzzy seach issues/merge requests on search bar
merge_request: 13780
author: Hiroyuki Sato
type: changed

View File

@ -0,0 +1,5 @@
---
title: Bump jira-ruby gem to 1.4.1 to fix issues with HTTP proxies
merge_request:
author:
type: fixed

View File

@ -0,0 +1,36 @@
class MigrateIssuesToGhostUser < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
class User < ActiveRecord::Base
self.table_name = 'users'
end
class Issue < ActiveRecord::Base
self.table_name = 'issues'
include ::EachBatch
end
def reset_column_in_migration_models
ActiveRecord::Base.clear_cache!
::User.reset_column_information
end
def up
reset_column_in_migration_models
# we use the model method because rewriting it is too complicated and would require copying multiple methods
ghost_id = ::User.ghost.id
Issue.where('NOT EXISTS (?)', User.unscoped.select(1).where('issues.author_id = users.id')).each_batch do |relation|
relation.update_all(author_id: ghost_id)
end
end
def down
end
end

View File

@ -0,0 +1,14 @@
class AddForeignKeyToIssueAuthor < ActiveRecord::Migration
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
def up
add_concurrent_foreign_key(:issues, :users, column: :author_id, on_delete: :nullify)
end
def down
remove_foreign_key(:issues, column: :author_id)
end
end

View File

@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20170831195038) do
ActiveRecord::Schema.define(version: 20170901071411) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -1708,6 +1708,7 @@ ActiveRecord::Schema.define(version: 20170831195038) do
add_foreign_key "issue_assignees", "users", name: "fk_5e0c8d9154", on_delete: :cascade
add_foreign_key "issue_metrics", "issues", on_delete: :cascade
add_foreign_key "issues", "projects", name: "fk_899c8f3231", on_delete: :cascade
add_foreign_key "issues", "users", column: "author_id", name: "fk_05f1e72feb", on_delete: :cascade
add_foreign_key "label_priorities", "labels", on_delete: :cascade
add_foreign_key "label_priorities", "projects", on_delete: :cascade
add_foreign_key "labels", "namespaces", column: "group_id", on_delete: :cascade

View File

@ -61,16 +61,7 @@ following locations:
## Road to GraphQL
Going forward, we will start on moving to
[GraphQL](http://graphql.org/learn/best-practices/) and deprecate the use of
controller-specific endpoints. GraphQL has a number of benefits:
1. We avoid having to maintain two different APIs.
2. Callers of the API can request only what they need.
3. It is versioned by default.
It will co-exist with the current v4 REST API. If we have a v5 API, this should
be a compatibility layer on top of GraphQL.
We have changed our plans to move to GraphQL. After reviewing the GraphQL license, anything related to the Facebook BSD plus patent license will not be allowed at GitLab.
## Basic usage
@ -246,8 +237,8 @@ The following table gives an overview of how the API functions generally behave.
| ------------ | ----------- |
| `GET` | Access one or more resources and return the result as JSON. |
| `POST` | Return `201 Created` if the resource is successfully created and return the newly created resource as JSON. |
| `GET` / `PUT` / `DELETE` | Return `200 OK` if the resource is accessed, modified or deleted successfully. The (modified) result is returned as JSON. |
| `DELETE` | Designed to be idempotent, meaning a request to a resource still returns `200 OK` even it was deleted before or is not available. The reasoning behind this, is that the user is not really interested if the resource existed before or not. |
| `GET` / `PUT` | Return `200 OK` if the resource is accessed or modified successfully. The (modified) result is returned as JSON. |
| `DELETE` | Returns `204 No Content` if the resuource was deleted successfully. |
The following table shows the possible return codes for API requests.

View File

@ -94,7 +94,7 @@ Example response:
## Delete an environment
It returns `200` if the environment was successfully deleted, and `404` if the environment does not exist.
It returns `204` if the environment was successfully deleted, and `404` if the environment does not exist.
```
DELETE /projects/:id/environments/:environment_id

View File

@ -95,8 +95,7 @@ Parameters:
## Delete snippet
Deletes an existing project snippet. This is an idempotent function and deleting a non-existent
snippet still returns a `200 OK` status code.
Deletes an existing project snippet. This returns a `204 No Content` status code if the operation was successfully or `404` if the resource was not found.
```
DELETE /projects/:id/snippets/:snippet_id

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