Commit 4d2315a3 authored by Simon Knox's avatar Simon Knox

Merge branch '2518-persisted-issue-boards-filter-be' of...

Merge branch '2518-persisted-issue-boards-filter-be' of gitlab.com:gitlab-org/gitlab-ee into edit-board
parents 59d29e78 f753e99b
Please view this file on the master branch, on stable branches it's out of date. Please view this file on the master branch, on stable branches it's out of date.
## 10.0.2 (2017-09-27)
- [FIXED] Send valid project path as name for Jira dev panel.
- [FIXED] Fix delta size check to handle commit or nil objects.
## 10.0.1 (2017-09-23)
- No changes.
## 10.0.0 (2017-09-22) ## 10.0.0 (2017-09-22)
- [SECURITY] Check if LDAP users are in external groups on login. !2720 - [SECURITY] Check if LDAP users are in external groups on login. !2720
......
...@@ -2,6 +2,17 @@ ...@@ -2,6 +2,17 @@
documentation](doc/development/changelog.md) for instructions on adding your own documentation](doc/development/changelog.md) for instructions on adding your own
entry. entry.
## 10.0.2 (2017-09-27)
- [FIXED] Notes will not show an empty bubble when the author isn't a member. !14450
- [FIXED] Some checks in `rake gitlab:check` were failling with 'undefined method `run_command`'. !14469
- [FIXED] Make locked setting of Runner to not affect jobs scheduling. !14483
- [FIXED] Re-allow `name` attribute on user-provided anchor HTML.
## 10.0.1 (2017-09-23)
- [FIXED] Fix duplicate key errors in PostDeployMigrateUserExternalMailData migration.
## 10.0.0 (2017-09-22) ## 10.0.0 (2017-09-22)
- [SECURITY] Upgrade brace-expansion NPM package due to security issue. !13665 (Markus Koller) - [SECURITY] Upgrade brace-expansion NPM package due to security issue. !13665 (Markus Koller)
......
9.6.0-pre 10.1.0-pre
...@@ -24,6 +24,9 @@ const categoryLabelMap = { ...@@ -24,6 +24,9 @@ const categoryLabelMap = {
flags: 'Flags', flags: 'Flags',
}; };
const IS_VISIBLE = 'is-visible';
const IS_RENDERED = 'is-rendered';
class AwardsHandler { class AwardsHandler {
constructor(emoji) { constructor(emoji) {
this.emoji = emoji; this.emoji = emoji;
...@@ -51,7 +54,7 @@ class AwardsHandler { ...@@ -51,7 +54,7 @@ class AwardsHandler {
if (!$target.closest('.emoji-menu').length) { if (!$target.closest('.emoji-menu').length) {
if ($('.emoji-menu').is(':visible')) { if ($('.emoji-menu').is(':visible')) {
$('.js-add-award.is-active').removeClass('is-active'); $('.js-add-award.is-active').removeClass('is-active');
$('.emoji-menu').removeClass('is-visible'); this.hideMenuElement($('.emoji-menu'));
} }
} }
}); });
...@@ -88,12 +91,12 @@ class AwardsHandler { ...@@ -88,12 +91,12 @@ class AwardsHandler {
if ($menu.length) { if ($menu.length) {
if ($menu.is('.is-visible')) { if ($menu.is('.is-visible')) {
$addBtn.removeClass('is-active'); $addBtn.removeClass('is-active');
$menu.removeClass('is-visible'); this.hideMenuElement($menu);
$('.js-emoji-menu-search').blur(); $('.js-emoji-menu-search').blur();
} else { } else {
$addBtn.addClass('is-active'); $addBtn.addClass('is-active');
this.positionMenu($menu, $addBtn); this.positionMenu($menu, $addBtn);
$menu.addClass('is-visible'); this.showMenuElement($menu);
$('.js-emoji-menu-search').focus(); $('.js-emoji-menu-search').focus();
} }
} else { } else {
...@@ -103,7 +106,7 @@ class AwardsHandler { ...@@ -103,7 +106,7 @@ class AwardsHandler {
$addBtn.removeClass('is-loading'); $addBtn.removeClass('is-loading');
this.positionMenu($createdMenu, $addBtn); this.positionMenu($createdMenu, $addBtn);
return setTimeout(() => { return setTimeout(() => {
$createdMenu.addClass('is-visible'); this.showMenuElement($createdMenu);
$('.js-emoji-menu-search').focus(); $('.js-emoji-menu-search').focus();
}, 200); }, 200);
}); });
...@@ -241,7 +244,8 @@ class AwardsHandler { ...@@ -241,7 +244,8 @@ class AwardsHandler {
if (isInIssuePage() && !isMainAwardsBlock) { if (isInIssuePage() && !isMainAwardsBlock) {
const id = votesBlock.attr('id').replace('note_', ''); const id = votesBlock.attr('id').replace('note_', '');
$('.emoji-menu').removeClass('is-visible'); this.hideMenuElement($('.emoji-menu'));
$('.js-add-award.is-active').removeClass('is-active'); $('.js-add-award.is-active').removeClass('is-active');
const toggleAwardEvent = new CustomEvent('toggleAward', { const toggleAwardEvent = new CustomEvent('toggleAward', {
detail: { detail: {
...@@ -261,7 +265,8 @@ class AwardsHandler { ...@@ -261,7 +265,8 @@ class AwardsHandler {
return typeof callback === 'function' ? callback() : undefined; return typeof callback === 'function' ? callback() : undefined;
}); });
$('.emoji-menu').removeClass('is-visible'); this.hideMenuElement($('.emoji-menu'));
return $('.js-add-award.is-active').removeClass('is-active'); return $('.js-add-award.is-active').removeClass('is-active');
} }
...@@ -529,6 +534,33 @@ class AwardsHandler { ...@@ -529,6 +534,33 @@ class AwardsHandler {
return $matchingElements.closest('li').clone(); return $matchingElements.closest('li').clone();
} }
/* showMenuElement and hideMenuElement are performance optimizations. We use
* opacity to show/hide the emoji menu, because we can animate it. But opacity
* leaves hidden elements in the render tree, which is unacceptable given the number
* of emoji elements in the emoji menu (5k+). To get the best of both worlds, we separately
* apply IS_RENDERED to add/remove the menu from the render tree and IS_VISIBLE to animate
* the menu being opened and closed. */
showMenuElement($emojiMenu) {
$emojiMenu.addClass(IS_RENDERED);
// enqueues animation as a microtask, so it begins ASAP once IS_RENDERED added
return Promise.resolve()
.then(() => $emojiMenu.addClass(IS_VISIBLE));
}
hideMenuElement($emojiMenu) {
$emojiMenu.on(transitionEndEventString, (e) => {
if (e.currentTarget === e.target) {
$emojiMenu
.removeClass(IS_RENDERED)
.off(transitionEndEventString);
}
});
$emojiMenu.removeClass(IS_VISIBLE);
}
destroy() { destroy() {
this.eventListeners.forEach((entry) => { this.eventListeners.forEach((entry) => {
entry.element.off.call(entry.element, ...entry.args); entry.element.off.call(entry.element, ...entry.args);
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
import '../lib/utils/url_utility'; import '../lib/utils/url_utility';
import { HIDDEN_CLASS } from '../lib/utils/constants'; import { HIDDEN_CLASS } from '../lib/utils/constants';
import csrf from '../lib/utils/csrf';
function toggleLoading($el, $icon, loading) { function toggleLoading($el, $icon, loading) {
if (loading) { if (loading) {
...@@ -36,9 +37,7 @@ export default class BlobFileDropzone { ...@@ -36,9 +37,7 @@ export default class BlobFileDropzone {
maxFiles: 1, maxFiles: 1,
addRemoveLinks: true, addRemoveLinks: true,
previewsContainer: '.dropzone-previews', previewsContainer: '.dropzone-previews',
headers: { headers: csrf.headers,
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content'),
},
init: function () { init: function () {
this.on('addedfile', function () { this.on('addedfile', function () {
toggleLoading(submitButton, submitButtonLoadingIcon, false); toggleLoading(submitButton, submitButtonLoadingIcon, false);
......
...@@ -11,14 +11,22 @@ ...@@ -11,14 +11,22 @@
function ImageFile(file) { function ImageFile(file) {
this.file = file; this.file = file;
this.requestImageInfo($('.two-up.view .frame.deleted img', this.file), (function(_this) { this.requestImageInfo($('.two-up.view .frame.deleted img', this.file), (function(_this) {
// Determine if old and new file has same dimensions, if not show 'two-up' view
return function(deletedWidth, deletedHeight) { return function(deletedWidth, deletedHeight) {
return _this.requestImageInfo($('.two-up.view .frame.added img', _this.file), function(width, height) { return _this.requestImageInfo($('.two-up.view .frame.added img', _this.file), function(width, height) {
if (width === deletedWidth && height === deletedHeight) { _this.initViewModes();
return _this.initViewModes();
} else { // Load two-up view after images are loaded
return _this.initView('two-up'); // so that we can display the correct width and height information
} const images = $('.two-up.view img', _this.file);
let loadedCount = 0;
images.on('load', () => {
loadedCount += 1;
if (loadedCount === images.length) {
_this.initView('two-up');
}
});
}); });
}; };
})(this)); })(this));
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
/* global Dropzone */ /* global Dropzone */
import _ from 'underscore'; import _ from 'underscore';
import './preview_markdown'; import './preview_markdown';
import csrf from './lib/utils/csrf';
window.DropzoneInput = (function() { window.DropzoneInput = (function() {
function DropzoneInput(form) { function DropzoneInput(form) {
...@@ -50,9 +51,7 @@ window.DropzoneInput = (function() { ...@@ -50,9 +51,7 @@ window.DropzoneInput = (function() {
paramName: 'file', paramName: 'file',
maxFilesize: maxFileSize, maxFilesize: maxFileSize,
uploadMultiple: false, uploadMultiple: false,
headers: { headers: csrf.headers,
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
previewContainer: false, previewContainer: false,
processing: function() { processing: function() {
return $('.div-dropzone-alert').alert('close'); return $('.div-dropzone-alert').alert('close');
...@@ -260,9 +259,7 @@ window.DropzoneInput = (function() { ...@@ -260,9 +259,7 @@ window.DropzoneInput = (function() {
dataType: 'json', dataType: 'json',
processData: false, processData: false,
contentType: false, contentType: false,
headers: { headers: csrf.headers,
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content')
},
beforeSend: function() { beforeSend: function() {
showSpinner(); showSpinner();
return closeAlertMessage(); return closeAlertMessage();
......
/*
This module provides easy access to the CSRF token and caches
it for re-use. It also exposes some values commonly used in relation
to the CSRF token (header key and headers object).
If you need to refresh the csrfToken for some reason, just call `init` and
then use the accessors as you would normally.
If you need to compose a headers object, use the spread operator:
```
headers: {
...csrf.headers,
someOtherHeader: '12345',
}
```
*/
const csrf = {
init() {
const tokenEl = document.querySelector('meta[name=csrf-token]');
if (tokenEl !== null) {
this.csrfToken = tokenEl.getAttribute('content');
} else {
this.csrfToken = null;
}
},
get token() {
return this.csrfToken;
},
get headerKey() {
return 'X-CSRF-Token';
},
get headers() {
if (this.csrfToken !== null) {
return {
[this.headerKey]: this.token,
};
}
return {};
},
};
csrf.init();
// use our cached token for any $.rails-generated AJAX requests
if ($.rails) {
$.rails.csrfToken = () => csrf.token;
}
export default csrf;
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
/* global Flash, Autosave */ /* global Flash, Autosave */
import { mapActions, mapGetters } from 'vuex'; import { mapActions, mapGetters } from 'vuex';
import _ from 'underscore'; import _ from 'underscore';
import autosize from 'vendor/autosize';
import '../../autosave'; import '../../autosave';
import TaskList from '../../task_list'; import TaskList from '../../task_list';
import * as constants from '../constants'; import * as constants from '../constants';
...@@ -96,6 +97,8 @@ ...@@ -96,6 +97,8 @@
methods: { methods: {
...mapActions([ ...mapActions([
'saveNote', 'saveNote',
'stopPolling',
'restartPolling',
'removePlaceholderNotes', 'removePlaceholderNotes',
]), ]),
setIsSubmitButtonDisabled(note, isSubmitting) { setIsSubmitButtonDisabled(note, isSubmitting) {
...@@ -124,10 +127,14 @@ ...@@ -124,10 +127,14 @@
} }
this.isSubmitting = true; this.isSubmitting = true;
this.note = ''; // Empty textarea while being requested. Repopulate in catch this.note = ''; // Empty textarea while being requested. Repopulate in catch
this.resizeTextarea();
this.stopPolling();
this.saveNote(noteData) this.saveNote(noteData)
.then((res) => { .then((res) => {
this.isSubmitting = false; this.isSubmitting = false;
this.restartPolling();
if (res.errors) { if (res.errors) {
if (res.errors.commands_only) { if (res.errors.commands_only) {
this.discard(); this.discard();
...@@ -174,6 +181,8 @@ ...@@ -174,6 +181,8 @@
if (shouldClear) { if (shouldClear) {
this.note = ''; this.note = '';
this.resizeTextarea();
this.$refs.markdownField.previewMarkdown = false;
} }
// reset autostave // reset autostave
...@@ -205,6 +214,11 @@ ...@@ -205,6 +214,11 @@
selector: '.notes', selector: '.notes',
}); });
}, },
resizeTextarea() {
this.$nextTick(() => {
autosize.update(this.$refs.textarea);
});
},
}, },
mounted() { mounted() {
// jQuery is needed here because it is a custom event being dispatched with jQuery. // jQuery is needed here because it is a custom event being dispatched with jQuery.
...@@ -247,7 +261,8 @@ ...@@ -247,7 +261,8 @@
:markdown-docs-path="markdownDocsPath" :markdown-docs-path="markdownDocsPath"
:quick-actions-docs-path="quickActionsDocsPath" :quick-actions-docs-path="quickActionsDocsPath"
:add-spacing-classes="false" :add-spacing-classes="false"
:is-confidential-issue="isConfidentialIssue"> :is-confidential-issue="isConfidentialIssue"
ref="markdownField">
<textarea <textarea
id="note-body" id="note-body"
name="note[note]" name="note[note]"
......
...@@ -187,6 +187,14 @@ export const poll = ({ commit, state, getters }) => { ...@@ -187,6 +187,14 @@ export const poll = ({ commit, state, getters }) => {
}); });
}; };
export const stopPolling = () => {
eTagPoll.stop();
};
export const restartPolling = () => {
eTagPoll.restart();
};
export const fetchData = ({ commit, state, getters }) => { export const fetchData = ({ commit, state, getters }) => {
const requestData = { endpoint: state.notesData.notesPath, lastFetchedAt: state.lastFetchedAt }; const requestData = { endpoint: state.notesData.notesPath, lastFetchedAt: state.lastFetchedAt };
......
...@@ -5,15 +5,19 @@ import * as constants from '../constants'; ...@@ -5,15 +5,19 @@ import * as constants from '../constants';
export default { export default {
[types.ADD_NEW_NOTE](state, note) { [types.ADD_NEW_NOTE](state, note) {
const { discussion_id, type } = note; const { discussion_id, type } = note;
const noteData = { const [exists] = state.notes.filter(n => n.id === note.discussion_id);
expanded: true,
id: discussion_id, if (!exists) {
individual_note: !(type === constants.DISCUSSION_NOTE), const noteData = {
notes: [note], expanded: true,
reply_id: discussion_id, id: discussion_id,
}; individual_note: !(type === constants.DISCUSSION_NOTE),
notes: [note],
state.notes.push(noteData); reply_id: discussion_id,
};
state.notes.push(noteData);
}
}, },
[types.ADD_NEW_REPLY_TO_DISCUSSION](state, note) { [types.ADD_NEW_REPLY_TO_DISCUSSION](state, note) {
......
...@@ -69,8 +69,7 @@ ...@@ -69,8 +69,7 @@
@click="onClickAction(action.path)" @click="onClickAction(action.path)"
:class="{ disabled: isActionDisabled(action) }" :class="{ disabled: isActionDisabled(action) }"
:disabled="isActionDisabled(action)"> :disabled="isActionDisabled(action)">
<span v-html="playIconSvg"></span> {{action.name}}
<span>{{action.name}}</span>
</button> </button>
</li> </li>
</ul> </ul>
......
...@@ -39,11 +39,7 @@ ...@@ -39,11 +39,7 @@
rel="nofollow" rel="nofollow"
download download
:href="artifact.path"> :href="artifact.path">
<i Download {{artifact.name}} artifacts
class="fa fa-download"
aria-hidden="true">
</i>
<span>Download {{artifact.name}} artifacts</span>
</a> </a>
</li> </li>
</ul> </ul>
......
<script> <script>
import { s__ } from '../../locale';
const PAGINATION_UI_BUTTON_LIMIT = 4; const PAGINATION_UI_BUTTON_LIMIT = 4;
const UI_LIMIT = 6; const UI_LIMIT = 6;
const SPREAD = '...'; const SPREAD = '...';
const PREV = 'Prev'; const PREV = s__('Pagination|Prev');
const NEXT = 'Next'; const NEXT = s__('Pagination|Next');
const FIRST = '« First'; const FIRST = s__('Pagination|« First');
const LAST = 'Last »'; const LAST = s__('Pagination|Last »');
export default { export default {
props: { props: {
......
import Vue from 'vue'; import Vue from 'vue';
import VueResource from 'vue-resource'; import VueResource from 'vue-resource';
import csrf from '../lib/utils/csrf';
Vue.use(VueResource); Vue.use(VueResource);
...@@ -18,9 +19,7 @@ Vue.http.interceptors.push((request, next) => { ...@@ -18,9 +19,7 @@ Vue.http.interceptors.push((request, next) => {
// New Vue Resource version uses Headers, we are expecting a plain object to render pagination // New Vue Resource version uses Headers, we are expecting a plain object to render pagination
// and polling. // and polling.
Vue.http.interceptors.push((request, next) => { Vue.http.interceptors.push((request, next) => {
if ($.rails) { request.headers.set(csrf.headerKey, csrf.token);
request.headers.set('X-CSRF-Token', $.rails.csrfToken());
}
next((response) => { next((response) => {
// Headers object has a `forEach` property that iterates through all values. // Headers object has a `forEach` property that iterates through all values.
......
...@@ -30,10 +30,12 @@ ...@@ -30,10 +30,12 @@
@import "framework/mobile"; @import "framework/mobile";
@import "framework/modal"; @import "framework/modal";
@import "framework/nav"; @import "framework/nav";
@import "framework/new-nav";
@import "framework/pagination"; @import "framework/pagination";
@import "framework/panels"; @import "framework/panels";
@import "framework/selects"; @import "framework/selects";
@import "framework/sidebar"; @import "framework/sidebar";
@import "framework/new-sidebar";
@import "framework/tables"; @import "framework/tables";
@import "framework/notes"; @import "framework/notes";
@import "framework/timeline"; @import "framework/timeline";
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
} }
.emoji-menu { .emoji-menu {
display: none;
position: absolute; position: absolute;
top: 0; top: 0;
margin-top: 3px; margin-top: 3px;
...@@ -27,6 +28,10 @@ ...@@ -27,6 +28,10 @@
transition: .3s cubic-bezier(.67, .06, .19, 1.44); transition: .3s cubic-bezier(.67, .06, .19, 1.44);
transition-property: transform, opacity; transition-property: transform, opacity;
&.is-rendered {
display: block;
}
&.is-aligned-right { &.is-aligned-right {
transform-origin: 100% -45px; transform-origin: 100% -45px;
} }
......
...@@ -254,6 +254,10 @@ body { ...@@ -254,6 +254,10 @@ body {
.search-icon { .search-icon {
color: $theme-gray-200; color: $theme-gray-200;
} }
.search-input {
color: $gl-text-color;
}
} }
.location-badge { .location-badge {
......
...@@ -144,3 +144,39 @@ ...@@ -144,3 +144,39 @@
@mixin green-status-color { @mixin green-status-color {
@include status-color($green-50, $green-500, $green-700); @include status-color($green-50, $green-500, $green-700);
} }
@mixin fade($gradient-direction, $gradient-color) {
visibility: hidden;
opacity: 0;
z-index: 2;
position: absolute;
bottom: 12px;
width: 43px;
height: 30px;
transition-duration: .3s;
-webkit-transform: translateZ(0);
background: linear-gradient(to $gradient-direction, $gradient-color 45%, rgba($gradient-color, 0.4));
&.scrolling {
visibility: visible;
opacity: 1;
transition-duration: .3s;
}
.fa {
position: relative;
top: 5px;
font-size: 18px;
}
}
@mixin scrolling-links() {
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
display: flex;
&::-webkit-scrollbar {
display: none;
}
}
@mixin fade($gradient-direction, $gradient-color) {
visibility: hidden;
opacity: 0;
z-index: 2;
position: absolute;
bottom: 12px;
width: 43px;
height: 30px;
transition-duration: .3s;
-webkit-transform: translateZ(0);
background: linear-gradient(to $gradient-direction, $gradient-color 45%, rgba($gradient-color, 0.4));
&.scrolling {
visibility: visible;
opacity: 1;
transition-duration: .3s;
}
.fa {
position: relative;
top: 5px;
font-size: 18px;
}
}
@mixin scrolling-links() {
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
display: flex;
&::-webkit-scrollbar {
display: none;
}
}
.nav-links { .nav-links {
display: flex; display: flex;
......
...@@ -295,75 +295,6 @@ header.navbar-gitlab-new { ...@@ -295,75 +295,6 @@ header.navbar-gitlab-new {
margin-top: 4px; margin-top: 4px;
} }
.search {
margin: 4px 8px 0;
form {
height: 32px;
border: 0;
border-radius: $border-radius-default;
transition: border-color ease-in-out 0.15s, background-color ease-in-out 0.15s;
&:hover {
box-shadow: none;
}
}
&.search-active form {
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 {
transition: color ease-in-out 0.15s;
}
.location-badge {
font-size: 12px;
margin: -4px 4px -4px -4px;
line-height: 25px;
padding: 4px 8px;
border-radius: 2px 0 0 2px;
height: 32px;
transition: border-color ease-in-out 0.15s;
}
&.search-active {
.location-badge {
background-color: $nav-badge-bg;
border-color: $border-color;
}
.search-input-wrap {
.clear-icon {
color: $white-light;
}
}
}
}
.breadcrumbs { .breadcrumbs {
display: flex; display: flex;
min-height: 48px; min-height: 48px;
......
...@@ -6,6 +6,7 @@ $gutter_width: 290px; ...@@ -6,6 +6,7 @@ $gutter_width: 290px;
$gutter_inner_width: 250px; $gutter_inner_width: 250px;
$sidebar-transition-duration: .15s; $sidebar-transition-duration: .15s;
$sidebar-breakpoint: 1024px; $sidebar-breakpoint: 1024px;
$default-transition-duration: .15s;
/* /*
* Color schema * Color schema
......
...@@ -28,9 +28,7 @@ input[type="checkbox"]:hover { ...@@ -28,9 +28,7 @@ input[type="checkbox"]:hover {
} }
.search { .search {
margin-right: 10px; margin: 4px 8px 0;
margin-left: 10px;
margin-top: ($header-height - 35) / 2;
form { form {
@extend .form-control; @extend .form-control;
...@@ -38,15 +36,23 @@ input[type="checkbox"]:hover { ...@@ -38,15 +36,23 @@ input[type="checkbox"]:hover {
padding: 4px; padding: 4px;
width: $search-input-width; width: $search-input-width;
line-height: 24px; line-height: 24px;
height: 32px;
border: 0;
border-radius: $border-radius-default;
transition: border-color ease-in-out $default-transition-duration, background-color ease-in-out $default-transition-duration;
&:hover { &:hover {
border-color: lighten($dropdown-input-focus-border, 20%); box-shadow: none;
box-shadow: 0 0 4px lighten($search-input-focus-shadow-color, 20%);
} }
} }
.location-text { .location-badge {
font-style: normal; font-size: 12px;
margin: -4px 4px -4px -4px;
line-height: 25px;
padding: 4px 8px;
border-radius: $border-radius-default 0 0 $border-radius-default;
transition: border-color ease-in-out $default-transition-duration;
} }
.search-input { .search-input {
...@@ -56,41 +62,26 @@ input[type="checkbox"]:hover { ...@@ -56,41 +62,26 @@ input[type="checkbox"]:hover {
margin-left: 5px; margin-left: 5px;
line-height: 25px; line-height: 25px;
width: 98%; width: 98%;
color: $white-light;
background: none;
transition: color ease-in-out $default-transition-duration;
} }
.location-badge { .search-input::placeholder {
line-height: 25px; transition: color ease-in-out $default-transition-duration;
padding: 0 5px;
border-radius: $border-radius-default;
font-size: 14px;
font-style: normal;
color: $note-disabled-comment-color;
display: inline-block;
background-color: $gray-normal;
vertical-align: top;
cursor: default;
} }
.search-input-container { .search-input-container {
display: -webkit-flex;
display: flex; display: flex;
position: relative; position: relative;
} }
.search-input-wrap { .search-input-wrap {
// Fallback if flexbox is not supported
display: inline-block;
}
.search-input-wrap {
width: 100%;
.search-icon, .search-icon,
.clear-icon { .clear-icon {
position: absolute; position: absolute;
right: 5px; right: 5px;
top: 0; top: 0;
color: $location-icon-color;
&::before { &::before {
font-family: FontAwesome; font-family: FontAwesome;
...@@ -101,7 +92,7 @@ input[type="checkbox"]:hover { ...@@ -101,7 +92,7 @@ input[type="checkbox"]:hover {
.search-icon { .search-icon {
@extend .fa-search; @extend .fa-search;
transition: color 0.15s; transition: color $default-transition-duration;
-webkit-user-select: none; -webkit-user-select: none;
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none; -ms-user-select: none;
...@@ -148,21 +139,32 @@ input[type="checkbox"]:hover { ...@@ -148,21 +139,32 @@ input[type="checkbox"]:hover {
form { form {
@extend .form-control:focus; @extend .form-control:focus;
border-color: $dropdown-input-focus-border; border-color: $dropdown-input-focus-border;
box-shadow: 0 0 4px $search-input-focus-shadow-color; box-shadow: none;
}
.search-input-wrap {
.search-icon,
.clear-icon {
color: $gl-text-color-tertiary;
transition: color ease-in-out $default-transition-duration;
}
}
.location-badge { .search-input {
transition: all 0.15s; color: $gl-text-color;
background-color: $location-badge-active-bg; transition: color ease-in-out $default-transition-duration;
color: $white-light; }
}
.search-input-wrap { .search-input::placeholder {
i { color: $gl-text-color-tertiary;
color: $layout-link-gray;
} }
} }
.location-badge {
transition: all $default-transition-duration;
background-color: $nav-badge-bg;
border-color: $border-color;
}
.dropdown-menu { .dropdown-menu {
transition-duration: 100ms, 75ms; transition-duration: 100ms, 75ms;
transition-delay: 75ms, 100ms; transition-delay: 75ms, 100ms;
......
...@@ -12,6 +12,7 @@ class Admin::ApplicationController < ApplicationController ...@@ -12,6 +12,7 @@ class Admin::ApplicationController < ApplicationController
def display_geo_information def display_geo_information
return unless Gitlab::Geo.secondary? return unless Gitlab::Geo.secondary?
return unless Gitlab::Geo.primary_node_configured?
primary_node = view_context.link_to('primary node', Gitlab::Geo.primary_node.url) primary_node = view_context.link_to('primary node', Gitlab::Geo.primary_node.url)
flash.now[:notice] = "You are on a secondary (read-only) Geo node. If you want to make any changes, you must visit the #{primary_node}.".html_safe flash.now[:notice] = "You are on a secondary (read-only) Geo node. If you want to make any changes, you must visit the #{primary_node}.".html_safe
......
...@@ -117,19 +117,34 @@ module IssuableCollections ...@@ -117,19 +117,34 @@ module IssuableCollections
key = 'issuable_sort' key = 'issuable_sort'
cookies[key] = params[:sort] if params[:sort].present? cookies[key] = params[:sort] if params[:sort].present?
cookies[key] = update_cookie_value(cookies[key])
# id_desc and id_asc are old values for these two.
cookies[key] = sort_value_recently_created if cookies[key] == 'id_desc'
cookies[key] = sort_value_oldest_created if cookies[key] == 'id_asc'
params[:sort] = cookies[key] params[:sort] = cookies[key]
end end
def default_sort_order def default_sort_order
case params[:state] case params[:state]
when 'opened', 'all' then sort_value_recently_created when 'opened', 'all' then sort_value_created_date
when 'merged', 'closed' then sort_value_recently_updated when 'merged', 'closed' then sort_value_recently_updated
else sort_value_recently_created else sort_value_created_date
end
end
# Update old values to the actual ones.
def update_cookie_value(value)
case value
when 'id_asc' then sort_value_oldest_created
when 'id_desc' then sort_value_recently_created
when 'created_asc' then sort_value_created_date
when 'created_desc' then sort_value_created_date
when 'due_date_asc' then sort_value_due_date
when 'due_date_desc' then sort_value_due_date
when 'milestone_due_asc' then sort_value_milestone
when 'milestone_due_desc' then sort_value_milestone
when 'downvotes_asc' then sort_value_popularity
when 'downvotes_desc' then sort_value_popularity
when 'weight_asc' then sort_value_weight
when 'weight_desc' then sort_value_weight
else value
end end
end end
end end
...@@ -3,8 +3,13 @@ class HelpController < ApplicationController ...@@ -3,8 +3,13 @@ class HelpController < ApplicationController
layout 'help' layout 'help'
# Taken from Jekyll
# https://github.com/jekyll/jekyll/blob/3.5-stable/lib/jekyll/document.rb#L13
YAML_FRONT_MATTER_REGEXP = %r!\A(---\s*\n.*?\n?)^((---|\.\.\.)\s*$\n?)!m
def index def index
@help_index = File.read(Rails.root.join('doc', 'README.md')) # Remove YAML frontmatter so that it doesn't look weird
@help_index = File.read(Rails.root.join('doc', 'README.md')).sub(YAML_FRONT_MATTER_REGEXP, '')
# Prefix Markdown links with `help/` unless they are external links # Prefix Markdown links with `help/` unless they are external links
# See http://rubular.com/r/X3baHTbPO2 # See http://rubular.com/r/X3baHTbPO2
...@@ -22,7 +27,8 @@ class HelpController < ApplicationController ...@@ -22,7 +27,8 @@ class HelpController < ApplicationController
path = File.join(Rails.root, 'doc', "#{@path}.md") path = File.join(Rails.root, 'doc', "#{@path}.md")
if File.exist?(path) if File.exist?(path)
@markdown = File.read(path) # Remove YAML frontmatter so that it doesn't look weird
@markdown = File.read(path).gsub(YAML_FRONT_MATTER_REGEXP, '')
render 'show.html.haml' render 'show.html.haml'
else else
......
...@@ -35,7 +35,10 @@ class Projects::TreeController < Projects::ApplicationController ...@@ -35,7 +35,10 @@ class Projects::TreeController < Projects::ApplicationController
end end
format.json do format.json do
render json: TreeSerializer.new(project: @project, repository: @repository, ref: @ref).represent(@tree) # n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/38261
Gitlab::GitalyClient.allow_n_plus_1_calls do
render json: TreeSerializer.new(project: @project, repository: @repository, ref: @ref).represent(@tree)
end
end end
end end
end end
......
...@@ -25,9 +25,31 @@ class IssuableFinder ...@@ -25,9 +25,31 @@ class IssuableFinder
NONE = '0'.freeze NONE = '0'.freeze
SCALAR_PARAMS = %i(scope state group_id project_id milestone_title assignee_id search label_name sort assignee_username author_id author_username authorized_only due_date iids non_archived weight my_reaction_emoji).freeze SCALAR_PARAMS = %i[
assignee_id
assignee_username
author_id
author_username
authorized_only
due_date
group_id
iids
label_name
milestone_title
non_archived
project_id
scope
search
sort
state
].freeze
ARRAY_PARAMS = { label_name: [], iids: [], assignee_username: [] }.freeze ARRAY_PARAMS = { label_name: [], iids: [], assignee_username: [] }.freeze
VALID_PARAMS = (SCALAR_PARAMS + [ARRAY_PARAMS]).freeze
EE_SCALAR_PARAMS = %i[
weight
].freeze
VALID_PARAMS = (SCALAR_PARAMS + [ARRAY_PARAMS] + EE_SCALAR_PARAMS).freeze
attr_accessor :current_user, :params attr_accessor :current_user, :params
......
...@@ -176,13 +176,15 @@ module CommitsHelper ...@@ -176,13 +176,15 @@ module CommitsHelper
end end
end end
def view_file_button(commit_sha, diff_new_path, project) def view_file_button(commit_sha, diff_new_path, project, replaced: false)
title = replaced ? _('View replaced file @ ') : _('View file @ ')
link_to( link_to(
project_blob_path(project, project_blob_path(project,
tree_join(commit_sha, diff_new_path)), tree_join(commit_sha, diff_new_path)),
class: 'btn view-file js-view-file' class: 'btn view-file js-view-file'
) do ) do
raw('View file @ ') + content_tag(:span, Commit.truncate_sha(commit_sha), raw(title) + content_tag(:span, Commit.truncate_sha(commit_sha),
class: 'commit-sha') class: 'commit-sha')
end end
end end
......
...@@ -131,7 +131,7 @@ module GroupsHelper ...@@ -131,7 +131,7 @@ module GroupsHelper
end end
def default_help def default_help
s_("GroupSettings|This setting will be applied to all subgroups unless overridden by a group owner.") s_("GroupSettings|This setting will be applied to all subgroups unless overridden by a group owner. Groups that already have access to the project will continue to have access unless removed manually.")
end end
def ancestor_locked_but_you_can_override(group) def ancestor_locked_but_you_can_override(group)
......
module MirrorHelper module MirrorHelper
def branch_diverged_tooltip_message def branch_diverged_tooltip_message
message = "The branch could not be updated automatically because it has diverged from its upstream counterpart." message = s_('Branches|The branch could not be updated automatically because it has diverged from its upstream counterpart.')
message << "<br>To discard the local changes and overwrite the branch with the upstream version, delete it here and choose 'Update Now' above." if can?(current_user, :push_code, @project)
if can?(current_user, :push_code, @project)
message << '<br>'
message << s_("Branches|To discard the local changes and overwrite the branch with the upstream version, delete it here and choose 'Update Now' above.")
end
message message
end end
......
This diff is collapsed.
...@@ -142,16 +142,18 @@ module Issuable ...@@ -142,16 +142,18 @@ module Issuable
end end
def sort(method, excluded_labels: []) def sort(method, excluded_labels: [])
sorted = case method.to_s sorted =
when 'milestone_due_asc' then order_milestone_due_asc case method.to_s
when 'milestone_due_desc' then order_milestone_due_desc when 'downvotes_desc' then order_downvotes_desc
when 'downvotes_desc' then order_downvotes_desc when 'label_priority' then order_labels_priority(excluded_labels: excluded_labels)
when 'upvotes_desc' then order_upvotes_desc when 'milestone' then order_milestone_due_asc
when 'label_priority' then order_labels_priority(excluded_labels: excluded_labels) when 'milestone_due_asc' then order_milestone_due_asc
when 'priority' then order_due_date_and_labels_priority(excluded_labels: excluded_labels) when 'milestone_due_desc' then order_milestone_due_desc
else when 'popularity' then order_upvotes_desc
order_by(method) when 'priority' then order_due_date_and_labels_priority(excluded_labels: excluded_labels)
end when 'upvotes_desc' then order_upvotes_desc
else order_by(method)
end
# Break ties with the ID column for pagination # Break ties with the ID column for pagination
sorted.order(id: :desc) sorted.order(id: :desc)
...@@ -224,7 +226,7 @@ module Issuable ...@@ -224,7 +226,7 @@ module Issuable
def grouping_columns(sort) def grouping_columns(sort)
grouping_columns = [arel_table[:id]] grouping_columns = [arel_table[:id]]
if %w(milestone_due_desc milestone_due_asc).include?(sort) if %w(milestone_due_desc milestone_due_asc milestone).include?(sort)
milestone_table = Milestone.arel_table milestone_table = Milestone.arel_table
grouping_columns << milestone_table[:id] grouping_columns << milestone_table[:id]
grouping_columns << milestone_table[:due_date] grouping_columns << milestone_table[:due_date]
......
...@@ -19,14 +19,15 @@ module Sortable ...@@ -19,14 +19,15 @@ module Sortable
module ClassMethods module ClassMethods
def order_by(method) def order_by(method)
case method.to_s case method.to_s
when 'name_asc' then order_name_asc when 'created_asc' then order_created_asc
when 'name_desc' then order_name_desc when 'created_date' then order_created_desc
when 'updated_asc' then order_updated_asc
when 'updated_desc' then order_updated_desc
when 'created_asc' then order_created_asc
when 'created_desc' then order_created_desc when 'created_desc' then order_created_desc
when 'id_desc' then order_id_desc when 'id_asc' then order_id_asc
when 'id_asc' then order_id_asc when 'id_desc' then order_id_desc
when 'name_asc' then order_name_asc
when 'name_desc' then order_name_desc
when 'updated_asc' then order_updated_asc
when 'updated_desc' then order_updated_desc
else else
all all
end end
......
...@@ -128,10 +128,12 @@ class Issue < ActiveRecord::Base ...@@ -128,10 +128,12 @@ class Issue < ActiveRecord::Base
def self.sort(method, excluded_labels: []) def self.sort(method, excluded_labels: [])
case method.to_s case method.to_s
when 'due_date_asc' then order_due_date_asc when 'due_date' then order_due_date_asc
when 'due_date_asc' then order_due_date_asc
when 'due_date_desc' then order_due_date_desc when 'due_date_desc' then order_due_date_desc
when 'weight_desc' then order_weight_desc when 'weight' then order_weight_asc
when 'weight_asc' then order_weight_asc when 'weight_asc' then order_weight_asc
when 'weight_desc' then order_weight_desc
else else
super super
end end
......
...@@ -82,30 +82,30 @@ class License < ActiveRecord::Base ...@@ -82,30 +82,30 @@ class License < ActiveRecord::Base
ULTIMATE_PLAN = 'ultimate'.freeze ULTIMATE_PLAN = 'ultimate'.freeze
EARLY_ADOPTER_PLAN = 'early_adopter'.freeze EARLY_ADOPTER_PLAN = 'early_adopter'.freeze
EES_FEATURES = [ EES_FEATURES = %i[
{ AUDIT_EVENTS_FEATURE => 1 }, audit_events
{ BURNDOWN_CHARTS_FEATURE => 1 }, burndown_charts
{ CONTRIBUTION_ANALYTICS_FEATURE => 1 }, contribution_analytics
{ ELASTIC_SEARCH_FEATURE => 1 }, elastic_search
{ EXPORT_ISSUES_FEATURE => 1 }, export_issues
{ FAST_FORWARD_MERGE_FEATURE => 1 }, fast_forward_merge
{ GROUP_WEBHOOKS_FEATURE => 1 }, group_webhooks
{ ISSUABLE_DEFAULT_TEMPLATES_FEATURE => 1 }, issuable_default_templates
{ ISSUE_BOARD_FOCUS_MODE_FEATURE => 1 }, issue_board_focus_mode
{ SCOPED_ISSUE_BOARD_FEATURE => 1 }, scoped_issue_board
{ ISSUE_WEIGHTS_FEATURE => 1 }, issue_weights
{ JENKINS_INTEGRATION_FEATURE => 1 }, jenkins_integration
{ LDAP_EXTRAS_FEATURE => 1 }, ldap_extras
{ MERGE_REQUEST_APPROVERS_FEATURE => 1 }, merge_request_approvers
{ MERGE_REQUEST_REBASE_FEATURE => 1 }, merge_request_rebase
{ MERGE_REQUEST_SQUASH_FEATURE => 1 }, merge_request_squash
{ MULTIPLE_ISSUE_ASSIGNEES_FEATURE => 1 }, multiple_issue_assignees
{ MULTIPLE_ISSUE_BOARDS_FEATURE => 1 }, multiple_issue_boards
{ PUSH_RULES_FEATURE => 1 }, push_rules
{ PROTECTED_REFS_FOR_USERS_FEATURE => 1 }, protected_refs_for_users
{ RELATED_ISSUES_FEATURE => 1 }, related_issues
{ REPOSITORY_MIRRORS_FEATURE => 1 }, repository_mirrors
{ REPOSITORY_SIZE_LIMIT_FEATURE => 1 } repository_size_limit
].freeze ].freeze
EEP_FEATURES = EES_FEATURES + %i[ EEP_FEATURES = EES_FEATURES + %i[
...@@ -304,7 +304,7 @@ class License < ActiveRecord::Base ...@@ -304,7 +304,7 @@ class License < ActiveRecord::Base
end end
def features_from_add_ons def features_from_add_ons
add_ons.map { |name, count| FEATURES_FOR_ADD_ONS[name] if count > 0 }.compact add_ons.map { |name, count| FEATURES_FOR_ADD_ONS[name] if count.to_i > 0 }.compact
end end
def features def features
......
...@@ -10,6 +10,7 @@ class Repository ...@@ -10,6 +10,7 @@ class Repository
RESERVED_REFS_NAMES = %W[ RESERVED_REFS_NAMES = %W[
heads heads
tags tags
replace
#{REF_ENVIRONMENTS} #{REF_ENVIRONMENTS}
#{REF_KEEP_AROUND} #{REF_KEEP_AROUND}
#{REF_ENVIRONMENTS} #{REF_ENVIRONMENTS}
......
...@@ -39,9 +39,11 @@ module Geo ...@@ -39,9 +39,11 @@ module Geo
Array([message, details].compact.join("\n")) Array([message, details].compact.join("\n"))
end end
rescue Gitlab::Geo::GeoNodeNotFoundError
['This GitLab instance does not appear to be configured properly as a Geo node. Make sure the URLs are using the correct fully-qualified domain names.']
rescue OpenSSL::Cipher::CipherError rescue OpenSSL::Cipher::CipherError
['Error decrypting the Geo secret from the database. Check that the primary uses the correct db_key_base.'] ['Error decrypting the Geo secret from the database. Check that the primary uses the correct db_key_base.']
rescue HTTParty::Error, Timeout::Error, SocketError, Errno::ECONNRESET, Errno::ECONNREFUSED => e rescue HTTParty::Error, Timeout::Error, SocketError, SystemCallError, OpenSSL::SSL::SSLError => e
[e.message] [e.message]
end end
......
- @no_container = true - @no_container = true
- page_title 'Audit Log' - page_title 'Audit Log'
= render 'admin/monitoring/head'
%div{ class: container_class } %div{ class: container_class }
.todos-filters .todos-filters
......
- @no_container = true - @no_container = true
- page_title "Background Jobs" - page_title "Background Jobs"
= render 'admin/monitoring/head'
%div{ class: container_class } %div{ class: container_class }
%h3.page-title Background Jobs %h3.page-title Background Jobs
......
- breadcrumb_title "Cohorts" - breadcrumb_title "Cohorts"
- @no_container = true - @no_container = true
= render "admin/dashboard/head"
%div{ class: container_class } %div{ class: container_class }
- if @cohorts - if @cohorts
......
- @no_container = true - @no_container = true
- page_title 'ConvDev Index' - page_title 'ConvDev Index'
= render 'admin/monitoring/head'
.container .container
- if show_callout?('convdev_intro_callout_dismissed') - if show_callout?('convdev_intro_callout_dismissed')
= render 'callout' = render 'callout'
......
= content_for :sub_nav do
.scrolling-tabs-container.sub-nav-scroll
= render 'shared/nav_scroll'
.nav-links.sub-nav.scrolling-tabs
%ul{ class: (container_class) }
= nav_link(controller: :dashboard, html_options: {class: 'home'}) do
= link_to admin_root_path, title: 'Overview' do
%span
Overview
= nav_link(controller: [:admin, :projects]) do
= link_to admin_projects_path, title: 'Projects' do
%span
Projects
= nav_link(controller: :users) do
= link_to admin_users_path, title: 'Users' do
%span
Users
= nav_link(controller: :groups) do
= link_to admin_groups_path, title: 'Groups' do
%span
Groups
= nav_link path: 'builds#index' do
= link_to admin_jobs_path, title: 'Jobs' do
%span
Jobs
= nav_link path: ['runners#index', 'runners#show'] do
= link_to admin_runners_path, title: 'Runners' do
%span
Runners
= nav_link path: 'cohorts#index' do
= link_to admin_cohorts_path, title: 'Cohorts' do
%span
Cohorts
= nav_link(controller: :conversational_development_index) do
= link_to admin_conversational_development_index_path, title: 'ConvDev Index' do
%span
ConvDev Index
- @no_container = true - @no_container = true
- breadcrumb_title "Dashboard" - breadcrumb_title "Dashboard"
= render "admin/dashboard/head"
%div{ class: container_class } %div{ class: container_class }
- if @license - if @license
......
- @no_container = true - @no_container = true
- page_title "Groups" - page_title "Groups"
= render "admin/dashboard/head"
%div{ class: container_class } %div{ class: container_class }
.top-area .top-area
......
- @no_container = true - @no_container = true
- page_title _('Health Check') - page_title _('Health Check')
- no_errors = @errors.blank? && @failing_storage_statuses.blank? - no_errors = @errors.blank? && @failing_storage_statuses.blank?
= render 'admin/monitoring/head'
%div{ class: container_class } %div{ class: container_class }
%h3.page-title= page_title %h3.page-title= page_title
......
- breadcrumb_title "Jobs" - breadcrumb_title "Jobs"
- @no_container = true - @no_container = true
= render "admin/dashboard/head"
%div{ class: container_class } %div{ class: container_class }
......
- @no_container = true - @no_container = true
- page_title "Logs" - page_title "Logs"
= render 'admin/monitoring/head'
%div{ class: container_class } %div{ class: container_class }
%ul.nav-links.log-tabs %ul.nav-links.log-tabs
......
= content_for :sub_nav do
.scrolling-tabs-container.sub-nav-scroll
= render 'shared/nav_scroll'
.nav-links.sub-nav.scrolling-tabs
%ul{ class: (container_class) }
= nav_link(controller: :system_info) do
= link_to admin_system_info_path, title: 'System Info' do
%span
System Info
= nav_link(controller: :background_jobs) do
= link_to admin_background_jobs_path, title: 'Background Jobs' do
%span
Background Jobs
= nav_link(controller: :logs) do
= link_to admin_logs_path, title: 'Logs' do
%span
Logs
= nav_link(controller: :health_check) do
= link_to admin_health_check_path, title: 'Health Check' do
%span
Health Check
= nav_link(controller: :requests_profiles) do
= link_to admin_requests_profiles_path, title: 'Requests Profiles' do
%span
Requests Profiles
= render 'admin/monitoring/ee/nav'
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
- page_title "Projects" - page_title "Projects"
- params[:visibility_level] ||= [] - params[:visibility_level] ||= []
= render "admin/dashboard/head"
%div{ class: container_class } %div{ class: container_class }
.top-area .top-area
......
- @no_container = true - @no_container = true
- page_title 'Requests Profiles' - page_title 'Requests Profiles'
= render 'admin/monitoring/head'
%div{ class: container_class } %div{ class: container_class }
%h3.page-title %h3.page-title
......
- breadcrumb_title "Runners" - breadcrumb_title "Runners"
- @no_container = true - @no_container = true
= render "admin/dashboard/head"
%div{ class: container_class } %div{ class: container_class }
.bs-callout .bs-callout
......
- @no_container = true - @no_container = true
- page_title "System Info" - page_title "System Info"
= render 'admin/monitoring/head'
%div{ class: container_class } %div{ class: container_class }
.prepend-top-default .prepend-top-default
......
- @no_container = true - @no_container = true
- page_title "Users" - page_title "Users"
= render "admin/dashboard/head"
%div{ class: container_class } %div{ class: container_class }
.prepend-top-default .prepend-top-default
......
= content_for :sub_nav do
.scrolling-tabs-container.sub-nav-scroll
= render 'shared/nav_scroll'
.nav-links.sub-nav.scrolling-tabs
%ul{ class: container_class }
= nav_link(path: ['groups#show', 'groups#subgroups'], html_options: { class: 'home' }) do
= link_to group_path(@group), title: 'Group Home' do
%span
Home
= nav_link(path: 'groups#activity') do
= link_to activity_group_path(@group), title: 'Activity' do
%span
Activity
.hidden-xs
= render "projects/last_push"
= content_for :sub_nav do
.scrolling-tabs-container.sub-nav-scroll
= render 'shared/nav_scroll'
.nav-links.sub-nav.scrolling-tabs
%ul{ class: container_class }
= nav_link(path: 'groups#issues', html_options: { class: 'home' }) do
= link_to issues_group_path(@group), title: 'List' do
%span
List
- if @group.feature_available?(:group_issue_boards)
= nav_link(path: 'groups#boards') do
= link_to group_boards_path(@group), title: 'Boards' do
%span
Boards
= nav_link(path: 'labels#index') do
= link_to group_labels_path(@group), title: 'Labels' do
%span
Labels
= nav_link(path: 'milestones#index') do
= link_to group_milestones_path(@group), title: 'Milestones' do
%span
Milestones
= content_for :sub_nav do
.scrolling-tabs-container.sub-nav-scroll
= render 'shared/nav_scroll'
.nav-links.sub-nav.scrolling-tabs
%ul{ class: container_class }
= nav_link(path: 'groups#edit') do
= link_to edit_group_path(@group), title: 'General' do
%span
General
= nav_link(path: 'groups#projects') do
= link_to projects_group_path(@group), title: 'Projects' do
%span
Projects
= nav_link(controller: :ci_cd) do
= link_to group_settings_ci_cd_path(@group), title: 'Pipelines' do
%span
Pipelines
= render 'groups/ee/settings_nav'
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
= auto_discovery_link_tag(:atom, group_url(@group, rss_url_options), title: "#{@group.name} activity") = auto_discovery_link_tag(:atom, group_url(@group, rss_url_options), title: "#{@group.name} activity")
- page_title "Activity" - page_title "Activity"
= render 'groups/head'
%section.activities %section.activities
= render 'activities' = render 'activities'
- page_title "Audit Events" - page_title "Audit Events"
= render "groups/settings_head"
%h3.page-title Group Audit Events %h3.page-title Group Audit Events
%p.light Events in #{@group.name} %p.light Events in #{@group.name}
......
- page_title "Billing" - page_title "Billing"
= render "groups/settings_head"
- if @top_most_group - if @top_most_group
- top_most_group_plan = subscription_plan_info(@plans_data, @top_most_group.actual_plan) - top_most_group_plan = subscription_plan_info(@plans_data, @top_most_group.actual_plan)
......
- breadcrumb_title "General Settings" - breadcrumb_title "General Settings"
= render "groups/settings_head"
.panel.panel-default.prepend-top-default .panel.panel-default.prepend-top-default
.panel-heading .panel-heading
Group settings Group settings
......
= render "groups/settings_head"
- if @group.feature_available?(:group_webhooks) - if @group.feature_available?(:group_webhooks)
.row.prepend-top-default .row.prepend-top-default
.col-lg-3 .col-lg-3
......
- page_title "Issues" - page_title "Issues"
- group_issues_exists = group_issues(@group).exists? - group_issues_exists = group_issues(@group).exists?
= render "head_issues"
= content_for :meta_tags do = content_for :meta_tags do
= auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{@group.name} issues") = auto_discovery_link_tag(:atom, params.merge(rss_url_options), title: "#{@group.name} issues")
......
- page_title 'Labels' - page_title 'Labels'
= render "groups/head_issues"
.top-area.adjust .top-area.adjust
.nav-text .nav-text
Labels can be applied to issues and merge requests. Group labels are available for any project within the group. Labels can be applied to issues and merge requests. Group labels are available for any project within the group.
......
- page_title "Milestones" - page_title "Milestones"
= render "groups/head_issues"
.top-area .top-area
= render 'shared/milestones_filter', counts: @milestone_states = render 'shared/milestones_filter', counts: @milestone_states
......
- page_title "Pipelines quota" - page_title "Pipelines quota"
= render "groups/settings_head"
%h3.page-title %h3.page-title
Group pipelines quota Group pipelines quota
......
- breadcrumb_title "Projects" - breadcrumb_title "Projects"
= render "groups/settings_head"
.panel.panel-default.prepend-top-default .panel.panel-default.prepend-top-default
.panel-heading .panel-heading
......
- breadcrumb_title "CI / CD Settings" - breadcrumb_title "CI / CD Settings"
- page_title "CI / CD" - page_title "CI / CD"
= render "groups/settings_head"
= render 'ci/variables/index' = render 'ci/variables/index'
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
= content_for :meta_tags do = content_for :meta_tags do
= auto_discovery_link_tag(:atom, group_url(@group, rss_url_options), title: "#{@group.name} activity") = auto_discovery_link_tag(:atom, group_url(@group, rss_url_options), title: "#{@group.name} activity")
= render 'groups/head'
= render 'groups/home_panel' = render 'groups/home_panel'
.groups-header{ class: container_class } .groups-header{ class: container_class }
......
- breadcrumb_title "Details" - breadcrumb_title "Details"
- @no_container = true - @no_container = true
= render 'head'
= render 'groups/home_panel' = render 'groups/home_panel'
.groups-header{ class: container_class } .groups-header{ class: container_class }
......
...@@ -32,10 +32,6 @@ ...@@ -32,10 +32,6 @@
= stylesheet_link_tag "test", media: "all" if Rails.env.test? = stylesheet_link_tag "test", media: "all" if Rails.env.test?
= stylesheet_link_tag 'performance_bar' if performance_bar_enabled? = stylesheet_link_tag 'performance_bar' if performance_bar_enabled?
// 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 = Gon::Base.render_data
- if content_for?(:library_javascripts) - if content_for?(:library_javascripts)
......
...@@ -60,7 +60,7 @@ ...@@ -60,7 +60,7 @@
= link_to sherlock_transactions_path, class: 'admin-icon', title: 'Sherlock Transactions', = link_to sherlock_transactions_path, class: 'admin-icon', title: 'Sherlock Transactions',
data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('tachometer fw') = icon('tachometer fw')
- if Gitlab::Geo.secondary? - if Gitlab::Geo.secondary? && Gitlab::Geo.primary_node_configured?
%li %li
= link_to Gitlab::Geo.primary_node.url, title: 'Go to primary node', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do = link_to Gitlab::Geo.primary_node.url, title: 'Go to primary node', data: {toggle: 'tooltip', placement: 'bottom', container: 'body'} do
= icon('globe fw') = icon('globe fw')
= content_for :sub_nav do
.scrolling-tabs-container.sub-nav-scroll
= render 'shared/nav_scroll'
.nav-links.sub-nav.scrolling-tabs
%ul{ class: container_class }
= nav_link(path: 'projects#show') do
= link_to project_path(@project), title: _('Project home'), class: 'shortcuts-project' do
%span= _('Home')
= nav_link(path: 'projects#activity') do
= link_to activity_project_path(@project), title: _('Activity'), class: 'shortcuts-project-activity' do
%span= _('Activity')
- if can?(current_user, :read_cycle_analytics, @project)
= nav_link(path: 'cycle_analytics#show') do
= link_to project_cycle_analytics_path(@project), title: _('Cycle Analytics'), class: 'shortcuts-project-cycle-analytics' do
%span= _('Cycle Analytics')
...@@ -2,8 +2,6 @@ ...@@ -2,8 +2,6 @@
- page_title _("Activity") - page_title _("Activity")
= render "projects/head"
= render 'projects/last_push' = render 'projects/last_push'
= render 'projects/activity' = render 'projects/activity'
- breadcrumb_title _('Artifacts') - breadcrumb_title _('Artifacts')
- page_title @path.presence, 'Artifacts', "#{@build.name} (##{@build.id})", 'Jobs' - page_title @path.presence, 'Artifacts', "#{@build.name} (##{@build.id})", 'Jobs'
= render "projects/pipelines/head"
= render "projects/jobs/header", show_controls: false = render "projects/jobs/header", show_controls: false
......
- page_title @path, 'Artifacts', "#{@build.name} (##{@build.id})", 'Jobs' - page_title @path, 'Artifacts', "#{@build.name} (##{@build.id})", 'Jobs'
= render "projects/pipelines/head"
= render "projects/jobs/header", show_controls: false = render "projects/jobs/header", show_controls: false
......
- page_title "Audit Events" - page_title "Audit Events"
= render "projects/settings/head"
- if show_project_feature_promotion?(:audit_events) - if show_project_feature_promotion?(:audit_events)
= render 'shared/promotions/promote_audit_events' = render 'shared/promotions/promote_audit_events'
......
- @no_container = true - @no_container = true
- project_duration = age_map_duration(@blame_groups, @project) - project_duration = age_map_duration(@blame_groups, @project)
- page_title "Blame", @blob.path, @ref - page_title "Blame", @blob.path, @ref
= render "projects/commits/head"
%div{ class: container_class } %div{ class: container_class }
#blob-content-holder.tree-holder #blob-content-holder.tree-holder
......
...@@ -4,7 +4,6 @@ ...@@ -4,7 +4,6 @@
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= page_specific_javascript_tag('lib/ace.js') = page_specific_javascript_tag('lib/ace.js')
= page_specific_javascript_bundle_tag('blob') = page_specific_javascript_bundle_tag('blob')
= render "projects/commits/head"
%div{ class: container_class } %div{ class: container_class }
- if @conflict - if @conflict
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
- @no_container = true - @no_container = true
- page_title @blob.path, @ref - page_title @blob.path, @ref
= render "projects/commits/head"
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= webpack_bundle_tag 'blob' = webpack_bundle_tag 'blob'
......
...@@ -13,26 +13,29 @@ ...@@ -13,26 +13,29 @@
- if branch.name == @repository.root_ref - if branch.name == @repository.root_ref
%span.label.label-primary default %span.label.label-primary default
- elsif @repository.merged_to_root_ref? branch.name - elsif @repository.merged_to_root_ref? branch.name
%span.label.label-info.has-tooltip{ title: "Merged into #{@repository.root_ref}" } %span.label.label-info.has-tooltip{ title: s_('Branches|Merged into %{default_branch}') % { default_branch: @repository.root_ref } }
merged = s_('Branches|merged')
- if protected_branch?(@project, branch) - if protected_branch?(@project, branch)
%span.label.label-success %span.label.label-success
protected = s_('Branches|protected')
- if @project.mirror_ever_updated_successfully? && @repository.diverged_from_upstream?(branch.name) - if @project.mirror_ever_updated_successfully? && @repository.diverged_from_upstream?(branch.name)
%span.label.label-danger.has-tooltip{ data: { html: "true", title: branch_diverged_tooltip_message } } %span.label.label-danger.has-tooltip{ data: { html: "true", title: branch_diverged_tooltip_message } }
= icon('exclamation-triangle') = icon('exclamation-triangle')
diverged from upstream = s_('Branches|diverged from upstream')
.controls.hidden-xs< .controls.hidden-xs<
- if merge_project && create_mr_button?(@repository.root_ref, branch.name) - if merge_project && create_mr_button?(@repository.root_ref, branch.name)
= link_to create_mr_path(@repository.root_ref, branch.name), class: 'btn btn-default' do = link_to create_mr_path(@repository.root_ref, branch.name), class: 'btn btn-default' do
Merge request = _('Merge request')
- if branch.name != @repository.root_ref - if branch.name != @repository.root_ref
= link_to project_compare_index_path(@project, from: @repository.root_ref, to: branch.name), class: "btn btn-default #{'prepend-left-10' unless merge_project}", method: :post, title: "Compare" do = link_to project_compare_index_path(@project, from: @repository.root_ref, to: branch.name),
Compare class: "btn btn-default #{'prepend-left-10' unless merge_project}",
method: :post,
title: s_('Branches|Compare') do
= s_('Branches|Compare')
= render 'projects/buttons/download', project: @project, ref: branch.name, pipeline: @refs_pipelines[branch.name] = render 'projects/buttons/download', project: @project, ref: branch.name, pipeline: @refs_pipelines[branch.name]
...@@ -40,12 +43,12 @@ ...@@ -40,12 +43,12 @@
- if branch.name == @project.repository.root_ref - if branch.name == @project.repository.root_ref
%button{ class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip disabled", %button{ class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip disabled",
disabled: true, disabled: true,
title: "The default branch cannot be deleted" } title: s_('Branches|The default branch cannot be deleted') }
= icon("trash-o") = icon("trash-o")
- elsif protected_branch?(@project, branch) - elsif protected_branch?(@project, branch)
- if can?(current_user, :delete_protected_branch, @project) - if can?(current_user, :delete_protected_branch, @project)
%button{ class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip", %button{ class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip",
title: "Delete protected branch", title: s_('Branches|Delete protected branch'),
data: { toggle: "modal", data: { toggle: "modal",
target: "#modal-delete-branch", target: "#modal-delete-branch",
delete_path: project_branch_path(@project, branch.name), delete_path: project_branch_path(@project, branch.name),
...@@ -55,20 +58,22 @@ ...@@ -55,20 +58,22 @@
- else - else
%button{ class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip disabled", %button{ class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip disabled",
disabled: true, disabled: true,
title: "Only a project master or owner can delete a protected branch" } title: s_('Branches|Only a project master or owner can delete a protected branch') }
= icon("trash-o") = icon("trash-o")
- else - else
= link_to project_branch_path(@project, branch.name), = link_to project_branch_path(@project, branch.name),
class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip", class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip",
title: "Delete branch", title: s_('Branches|Delete branch'),
method: :delete, method: :delete,
data: { confirm: "Deleting the '#{branch.name}' branch cannot be undone. Are you sure?" }, data: { confirm: s_("Branches|Deleting the '%{branch_name}' branch cannot be undone. Are you sure?") % { branch_name: branch.name } },
remote: true, remote: true,
"aria-label" => "Delete branch" do 'aria-label' => s_('Branches|Delete branch') do
= icon("trash-o") = icon("trash-o")
- if branch.name != @repository.root_ref - if branch.name != @repository.root_ref
.divergence-graph{ title: "#{number_commits_behind} commits behind #{@repository.root_ref}, #{number_commits_ahead} commits ahead" } .divergence-graph{ title: s_('%{number_commits_behind} commits behind %{default_branch}, %{number_commits_ahead} commits ahead') % { number_commits_behind: number_commits_behind,
default_branch: @repository.root_ref,
number_commits_ahead: number_commits_ahead } }
.graph-side .graph-side
.bar.bar-behind{ style: "width: #{number_commits_behind * bar_graph_width_factor}%" } .bar.bar-behind{ style: "width: #{number_commits_behind * bar_graph_width_factor}%" }
%span.count.count-behind= number_commits_behind %span.count.count-behind= number_commits_behind
...@@ -82,4 +87,4 @@ ...@@ -82,4 +87,4 @@
= render 'projects/branches/commit', commit: commit, project: @project = render 'projects/branches/commit', commit: commit, project: @project
- else - else
%p %p
Cant find HEAD commit for this branch = s_('Branches|Cant find HEAD commit for this branch')
...@@ -4,36 +4,38 @@ ...@@ -4,36 +4,38 @@
.modal-header .modal-header
%button.close{ data: { dismiss: 'modal' } } × %button.close{ data: { dismiss: 'modal' } } ×
%h3.page-title %h3.page-title
Delete protected branch - title_branch_name = capture do
= surround "'", "'?" do
%span.js-branch-name.ref-name>[branch name] %span.js-branch-name.ref-name>[branch name]
= s_("Branches|Delete protected branch '%{branch_name}'?").html_safe % { branch_name: title_branch_name }
.modal-body .modal-body
%p %p
You’re about to permanently delete the protected branch - branch_name = capture do
= succeed '.' do %strong.js-branch-name.ref-name>[branch name]
%strong.js-branch-name.ref-name [branch name] = s_('Branches|You’re about to permanently delete the protected branch %{branch_name}.').html_safe % { branch_name: branch_name }
%p.js-not-merged %p.js-not-merged
- default_branch = capture do - default_branch = capture do
%span.ref-name= @repository.root_ref %span.ref-name= @repository.root_ref
= s_("Branches|This branch hasn’t been merged into %{default_branch}.").html_safe % { default_branch: default_branch } = s_('Branches|This branch hasn’t been merged into %{default_branch}.').html_safe % { default_branch: default_branch }
= s_("Branches|To avoid data loss, consider merging this branch before deleting it.") = s_('Branches|To avoid data loss, consider merging this branch before deleting it.')
%p %p
Once you confirm and press - delete_protected_branch = capture do
= succeed ',' do %strong
%strong Delete protected branch = s_('Branches|Delete protected branch')
it cannot be undone or recovered. = s_('Branches|Once you confirm and press %{delete_protected_branch}, it cannot be undone or recovered.').html_safe % { delete_protected_branch: delete_protected_branch }
%p %p
%strong To confirm, type - branch_name_confirmation = capture do
%kbd.js-branch-name [branch name] %kbd.js-branch-name [branch name]
%strong
= s_('Branches|To confirm, type %{branch_name_confirmation}:').html_safe % { branch_name_confirmation: branch_name_confirmation }
.form-group .form-group
= text_field_tag 'delete_branch_input', '', class: 'form-control js-delete-branch-input' = text_field_tag 'delete_branch_input', '', class: 'form-control js-delete-branch-input'
.modal-footer .modal-footer
%button.btn{ data: { dismiss: 'modal' } } Cancel %button.btn{ data: { dismiss: 'modal' } } Cancel
= link_to 'Delete protected branch', '', = link_to s_('Branches|Delete protected branch'), '',
class: "btn btn-danger js-delete-branch", class: "btn btn-danger js-delete-branch",
title: 'Delete branch', title: s_('Branches|Delete branch'),
method: :delete, method: :delete,
"aria-label" => "Delete" 'aria-label' => s_('Branches|Delete branch')
- @no_container = true - @no_container = true
- page_title "Branches" - page_title _('Branches')
- add_to_breadcrumbs("Repository", project_tree_path(@project)) - add_to_breadcrumbs(_('Repository'), project_tree_path(@project))
= render "projects/commits/head"
%div{ class: container_class } %div{ class: container_class }
.top-area.adjust .top-area.adjust
- if can?(current_user, :admin_project, @project) - if can?(current_user, :admin_project, @project)
.nav-text .nav-text
Protected branches can be managed in - project_settings_link = link_to s_('Branches|project settings'), project_protected_branches_path(@project)
= link_to 'project settings', project_protected_branches_path(@project) = s_('Branches|Protected branches can be managed in %{project_settings_link}').html_safe % { project_settings_link: project_settings_link }
.nav-controls .nav-controls
= form_tag(filter_branches_path, method: :get) do = form_tag(filter_branches_path, method: :get) do
= search_field_tag :search, params[:search], { placeholder: 'Filter by branch name', id: 'branch-search', class: 'form-control search-text-input input-short', spellcheck: false } = search_field_tag :search, params[:search], { placeholder: s_('Branches|Filter by branch name'), id: 'branch-search', class: 'form-control search-text-input input-short', spellcheck: false }
.dropdown.inline> .dropdown.inline>
%button.dropdown-menu-toggle{ type: 'button', 'data-toggle' => 'dropdown' } %button.dropdown-menu-toggle{ type: 'button', 'data-toggle' => 'dropdown' }
...@@ -21,23 +20,31 @@ ...@@ -21,23 +20,31 @@
= icon('chevron-down') = icon('chevron-down')
%ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-selectable %ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-selectable
%li.dropdown-header %li.dropdown-header
Sort by = s_('Branches|Sort by')
- branches_sort_options_hash.each do |value, title| - branches_sort_options_hash.each do |value, title|
%li %li
= link_to title, filter_branches_path(sort: value), class: ("is-active" if @sort == value) = link_to title, filter_branches_path(sort: value), class: ("is-active" if @sort == value)
- if can? current_user, :push_code, @project - if can? current_user, :push_code, @project
= link_to project_merged_branches_path(@project), class: 'btn btn-inverted btn-remove has-tooltip', title: "Delete all branches that are merged into '#{@project.repository.root_ref}'", method: :delete, data: { confirm: "Deleting the merged branches cannot be undone. Are you sure?", container: 'body' } do = link_to project_merged_branches_path(@project),
Delete merged branches class: 'btn btn-inverted btn-remove has-tooltip',
title: s_("Branches|Delete all branches that are merged into '%{default_branch}'") % { default_branch: @project.repository.root_ref },
method: :delete,
data: { confirm: s_('Branches|Deleting the merged branches cannot be undone. Are you sure?'),
container: 'body' } do
= s_('Branches|Delete merged branches')
= link_to new_project_branch_path(@project), class: 'btn btn-create' do = link_to new_project_branch_path(@project), class: 'btn btn-create' do
New branch = s_('Branches|New branch')
= render 'projects/commits/mirror_status' = render 'projects/commits/mirror_status'
- if @branches.any? - if @branches.any?
%ul.content-list.all-branches %ul.content-list.all-branches
- @branches.each do |branch| - @branches.each do |branch|
= render "projects/branches/branch", branch: branch = render "projects/branches/branch", branch: branch
= paginate @branches, theme: 'gitlab' = paginate @branches, theme: 'gitlab'
- else - else
.nothing-here-block No branches to show .nothing-here-block
= s_('Branches|No branches to show')
= render 'projects/branches/delete_protected_modal' = render 'projects/branches/delete_protected_modal'
...@@ -11,19 +11,15 @@ ...@@ -11,19 +11,15 @@
#{ _('Source code') } #{ _('Source code') }
%li %li
= link_to archive_project_repository_path(project, ref: ref, format: 'zip'), rel: 'nofollow', download: '' do = link_to archive_project_repository_path(project, ref: ref, format: 'zip'), rel: 'nofollow', download: '' do
%i.fa.fa-download
%span= _('Download zip') %span= _('Download zip')
%li %li
= link_to archive_project_repository_path(project, ref: ref, format: 'tar.gz'), rel: 'nofollow', download: '' do = link_to archive_project_repository_path(project, ref: ref, format: 'tar.gz'), rel: 'nofollow', download: '' do
%i.fa.fa-download
%span= _('Download tar.gz') %span= _('Download tar.gz')
%li %li
= link_to archive_project_repository_path(project, ref: ref, format: 'tar.bz2'), rel: 'nofollow', download: '' do = link_to archive_project_repository_path(project, ref: ref, format: 'tar.bz2'), rel: 'nofollow', download: '' do
%i.fa.fa-download
%span= _('Download tar.bz2') %span= _('Download tar.bz2')
%li %li
= link_to archive_project_repository_path(project, ref: ref, format: 'tar'), rel: 'nofollow', download: '' do = link_to archive_project_repository_path(project, ref: ref, format: 'tar'), rel: 'nofollow', download: '' do
%i.fa.fa-download
%span= _('Download tar') %span= _('Download tar')
- if pipeline && pipeline.latest_builds_with_artifacts.any? - if pipeline && pipeline.latest_builds_with_artifacts.any?
...@@ -36,6 +32,5 @@ ...@@ -36,6 +32,5 @@
- pipeline.latest_builds_with_artifacts.each do |job| - pipeline.latest_builds_with_artifacts.each do |job|
%li %li
= link_to latest_succeeded_project_artifacts_path(project, "#{ref}/download", job: job.name), rel: 'nofollow', download: '' do = link_to latest_succeeded_project_artifacts_path(project, "#{ref}/download", job: job.name), rel: 'nofollow', download: '' do
%i.fa.fa-download
%span %span
#{s_('DownloadArtifacts|Download')} '#{job.name}' #{s_('DownloadArtifacts|Download')} '#{job.name}'
...@@ -11,19 +11,16 @@ ...@@ -11,19 +11,16 @@
- if can_create_issue - if can_create_issue
%li %li
= link_to new_project_issue_path(@project) do = link_to new_project_issue_path(@project) do
= icon('exclamation-circle fw')
#{ _('New issue') } #{ _('New issue') }
- if merge_project - if merge_project
%li %li
= link_to project_new_merge_request_path(merge_project) do = link_to project_new_merge_request_path(merge_project) do
= icon('tasks fw')
#{ _('New merge request') } #{ _('New merge request') }
- if can_create_snippet - if can_create_snippet
%li %li
= link_to new_project_snippet_path(@project) do = link_to new_project_snippet_path(@project) do
= icon('file-text-o fw')
#{ _('New snippet') } #{ _('New snippet') }
- if can_create_issue || merge_project || can_create_snippet - if can_create_issue || merge_project || can_create_snippet
...@@ -32,20 +29,16 @@ ...@@ -32,20 +29,16 @@
- if can?(current_user, :push_code, @project) - if can?(current_user, :push_code, @project)
%li %li
= link_to project_new_blob_path(@project, @project.default_branch || 'master') do = link_to project_new_blob_path(@project, @project.default_branch || 'master') do
= icon('file fw')
#{ _('New file') } #{ _('New file') }
%li %li
= link_to new_project_branch_path(@project) do = link_to new_project_branch_path(@project) do
= icon('code-fork fw')
#{ _('New branch') } #{ _('New branch') }
%li %li
= link_to new_project_tag_path(@project) do = link_to new_project_tag_path(@project) do
= icon('tags fw')
#{ _('New tag') } #{ _('New tag') }
- elsif current_user && current_user.already_forked?(@project) - elsif current_user && current_user.already_forked?(@project)
%li %li
= link_to project_new_blob_path(@project, @project.default_branch || 'master') do = link_to project_new_blob_path(@project, @project.default_branch || 'master') do
= icon('file fw')
#{ _('New file') } #{ _('New file') }
- elsif can?(current_user, :fork_project, @project) - elsif can?(current_user, :fork_project, @project)
%li %li
...@@ -55,5 +48,4 @@ ...@@ -55,5 +48,4 @@
- fork_path = project_forks_path(@project, namespace_key: current_user.namespace.id, - fork_path = project_forks_path(@project, namespace_key: current_user.namespace.id,
continue: continue_params) continue: continue_params)
= link_to fork_path, method: :post do = link_to fork_path, method: :post do
= icon('file fw')
#{ _('New file') } #{ _('New file') }
...@@ -6,7 +6,6 @@ ...@@ -6,7 +6,6 @@
- @content_class = limited_container_width - @content_class = limited_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"
.container-fluid{ class: [limited_container_width, container_class] } .container-fluid{ class: [limited_container_width, container_class] }
= render "commit_box" = render "commit_box"
......
= content_for :sub_nav do
.scrolling-tabs-container.sub-nav-scroll
= render 'shared/nav_scroll'
.nav-links.sub-nav.scrolling-tabs
%ul{ class: (container_class) }
= nav_link(controller: %w(tree blob blame edit_tree new_tree find_file)) do
= link_to project_tree_path(@project) do
#{ _('Files') }
= nav_link(controller: [:commit, :commits]) do
= link_to project_commits_path(@project, current_ref) do
#{ _('Commits') }
= nav_link(html_options: {class: branches_tab_class}) do
= link_to project_branches_path(@project) do
#{ _('Branches') }
= nav_link(controller: [:tags, :releases]) do
= link_to project_tags_path(@project) do
#{ _('Tags') }
= nav_link(path: 'graphs#show') do
= link_to project_graph_path(@project, current_ref) do
#{ _('Contributors') }
= nav_link(controller: %w(network)) do
= link_to project_network_path(@project, current_ref) do
#{ s_('ProjectNetworkGraph|Graph') }
= nav_link(controller: :compare) do
= link_to project_compare_index_path(@project, from: @repository.root_ref, to: current_ref) do
#{ _('Compare') }
= nav_link(path: 'graphs#charts') do
= link_to charts_project_graph_path(@project, current_ref) do
#{ _('Charts') }
- if @project.feature_available?(:file_locks)
= nav_link(controller: [:path_locks]) do
= link_to project_path_locks_path(@project) do
Locked Files
...@@ -5,9 +5,6 @@ ...@@ -5,9 +5,6 @@
= content_for :meta_tags do = content_for :meta_tags do
= auto_discovery_link_tag(:atom, project_commits_url(@project, @ref, rss_url_options), title: "#{@project.name}:#{@ref} commits") = auto_discovery_link_tag(:atom, project_commits_url(@project, @ref, rss_url_options), title: "#{@project.name}:#{@ref} commits")
= content_for :sub_nav do
= render "head"
.js-project-commits-show{ 'data-commits-limit' => @limit } .js-project-commits-show{ 'data-commits-limit' => @limit }
%div{ class: container_class } %div{ class: container_class }
.tree-holder .tree-holder
......
- @no_container = true - @no_container = true
- breadcrumb_title "Compare Revisions" - breadcrumb_title "Compare Revisions"
- page_title "Compare" - page_title "Compare"
= render "projects/commits/head"
%div{ class: container_class } %div{ class: container_class }
.sub-header-block .sub-header-block
......
- @no_container = true - @no_container = true
- add_to_breadcrumbs "Compare Revisions", project_compare_index_path(@project) - add_to_breadcrumbs "Compare Revisions", project_compare_index_path(@project)
- page_title "#{params[:from]}...#{params[:to]}" - page_title "#{params[:from]}...#{params[:to]}"
= render "projects/commits/head"
%div{ class: container_class } %div{ class: container_class }
.sub-header-block.no-bottom-space .sub-header-block.no-bottom-space
......
...@@ -4,8 +4,6 @@ ...@@ -4,8 +4,6 @@
= page_specific_javascript_bundle_tag('common_vue') = page_specific_javascript_bundle_tag('common_vue')
= page_specific_javascript_bundle_tag('cycle_analytics') = page_specific_javascript_bundle_tag('cycle_analytics')
= render "projects/head"
#cycle-analytics{ class: container_class, "v-cloak" => "true", data: { request_path: project_cycle_analytics_path(@project) } } #cycle-analytics{ class: container_class, "v-cloak" => "true", data: { request_path: project_cycle_analytics_path(@project) } }
- if @cycle_analytics_no_data - if @cycle_analytics_no_data
.landing.content-block{ "v-if" => "!isOverviewDialogDismissed" } .landing.content-block{ "v-if" => "!isOverviewDialogDismissed" }
......
- environment = local_assigns.fetch(:environment, nil) - environment = local_assigns.fetch(:environment, nil)
- file_hash = hexdigest(diff_file.file_path) - file_hash = hexdigest(diff_file.file_path)
- image_diff = diff_file.rich_viewer && diff_file.rich_viewer.partial_name == 'image'
- image_replaced = diff_file.old_content_sha && diff_file.old_content_sha != diff_file.content_sha
.diff-file.file-holder{ id: file_hash, data: diff_file_html_data(project, diff_file.file_path, diff_file.content_sha) } .diff-file.file-holder{ id: file_hash, data: diff_file_html_data(project, diff_file.file_path, diff_file.content_sha) }
.js-file-title.file-title-flex-parent .js-file-title.file-title-flex-parent
.file-header-content .file-header-content
...@@ -17,6 +20,9 @@ ...@@ -17,6 +20,9 @@
= edit_blob_link(@merge_request.source_project, @merge_request.source_branch, diff_file.new_path, = edit_blob_link(@merge_request.source_project, @merge_request.source_branch, diff_file.new_path,
blob: blob, link_opts: link_opts) blob: blob, link_opts: link_opts)
- if image_diff && image_replaced
= view_file_button(diff_file.old_content_sha, diff_file.old_path, project, replaced: true)
= view_file_button(diff_file.content_sha, diff_file.file_path, project) = view_file_button(diff_file.content_sha, diff_file.file_path, project)
= view_on_environment_button(diff_file.content_sha, diff_file.file_path, environment) if environment = view_on_environment_button(diff_file.content_sha, diff_file.file_path, environment) if environment
......
...@@ -15,8 +15,7 @@ ...@@ -15,8 +15,7 @@
.two-up.view .two-up.view
%span.wrap %span.wrap
.frame.deleted .frame.deleted
%a{ href: project_blob_path(@project, tree_join(diff_file.old_content_sha, diff_file.old_path)) } = image_tag(old_blob_raw_path, alt: diff_file.old_path)
= image_tag(old_blob_raw_path, alt: diff_file.old_path)
%p.image-info.hide %p.image-info.hide
%span.meta-filesize= number_to_human_size(old_blob.size) %span.meta-filesize= number_to_human_size(old_blob.size)
| |
...@@ -27,8 +26,7 @@ ...@@ -27,8 +26,7 @@
%span.meta-height %span.meta-height
%span.wrap %span.wrap
.frame.added .frame.added
%a{ href: project_blob_path(@project, tree_join(diff_file.content_sha, diff_file.new_path)) } = image_tag(blob_raw_path, alt: diff_file.new_path)
= image_tag(blob_raw_path, alt: diff_file.new_path)
%p.image-info.hide %p.image-info.hide
%span.meta-filesize= number_to_human_size(blob.size) %span.meta-filesize= number_to_human_size(blob.size)
| |
......
...@@ -7,8 +7,6 @@ ...@@ -7,8 +7,6 @@
= webpack_bundle_tag('common_vue') = webpack_bundle_tag('common_vue')
= webpack_bundle_tag('service_desk') = webpack_bundle_tag('service_desk')
= render "projects/settings/head"
.project-edit-container .project-edit-container
%section.settings.general-settings %section.settings.general-settings
.settings-header .settings-header
......
...@@ -3,7 +3,6 @@ ...@@ -3,7 +3,6 @@
= render partial: 'flash_messages', locals: { project: @project } = render partial: 'flash_messages', locals: { project: @project }
= render "projects/head"
= render "home_panel" = render "home_panel"
.row-content-block.second-block.center .row-content-block.second-block.center
......
- @no_container = true - @no_container = true
- page_title "Edit", @environment.name, "Environments" - page_title "Edit", @environment.name, "Environments"
= render "projects/pipelines/head"
%div{ class: container_class } %div{ class: container_class }
%h3.page-title %h3.page-title
......
- @no_container = true - @no_container = true
- page_title "Environments" - page_title "Environments"
= render "projects/pipelines/head"
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_vue') = page_specific_javascript_bundle_tag('common_vue')
......
- @no_container = true - @no_container = true
- page_title "Environments" - page_title "Environments"
- add_to_breadcrumbs("Pipelines", project_pipelines_path(@project)) - add_to_breadcrumbs("Pipelines", project_pipelines_path(@project))
= render "projects/pipelines/head"
- content_for :page_specific_javascripts do - content_for :page_specific_javascripts do
= page_specific_javascript_bundle_tag('common_vue') = page_specific_javascript_bundle_tag('common_vue')
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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