Commit 039b0c0d authored by Douwe Maan's avatar Douwe Maan

Merge branch 'master' into 'security-fj-bumping-sanitize-gem'

# Conflicts:
#   Gemfile.rails5.lock
parents b4c10804 3c725a2a
...@@ -71,7 +71,3 @@ rules: ...@@ -71,7 +71,3 @@ rules:
body: 1 body: 1
## Destructuring: https://eslint.org/docs/rules/prefer-destructuring ## Destructuring: https://eslint.org/docs/rules/prefer-destructuring
prefer-destructuring: off prefer-destructuring: off
## no-restricted-globals: https://eslint.org/docs/rules/no-restricted-globals
no-restricted-globals: off
## no-multi-assign: https://eslint.org/docs/rules/no-multi-assign
no-multi-assign: off
...@@ -307,7 +307,7 @@ GEM ...@@ -307,7 +307,7 @@ GEM
rouge (~> 3.1) rouge (~> 3.1)
sanitize (~> 4.6.4) sanitize (~> 4.6.4)
stringex (~> 2.6) stringex (~> 2.6)
gitlab-gollum-rugged_adapter (0.4.4) gitlab-gollum-rugged_adapter (0.4.4.1)
mime-types (>= 1.15) mime-types (>= 1.15)
rugged (~> 0.25) rugged (~> 0.25)
gitlab-grit (2.8.2) gitlab-grit (2.8.2)
......
...@@ -70,7 +70,7 @@ export default class BlobViewer { ...@@ -70,7 +70,7 @@ export default class BlobViewer {
const initialViewer = this.$fileHolder[0].querySelector('.blob-viewer:not(.hidden)'); const initialViewer = this.$fileHolder[0].querySelector('.blob-viewer:not(.hidden)');
let initialViewerName = initialViewer.getAttribute('data-type'); let initialViewerName = initialViewer.getAttribute('data-type');
if (this.switcher && location.hash.indexOf('#L') === 0) { if (this.switcher && window.location.hash.indexOf('#L') === 0) {
initialViewerName = 'simple'; initialViewerName = 'simple';
} }
......
/* eslint-disable comma-dangle, space-before-function-paren, one-var */ /* eslint-disable comma-dangle, space-before-function-paren, one-var */
import $ from 'jquery';
import Sortable from 'sortablejs'; import Sortable from 'sortablejs';
import Vue from 'vue'; import Vue from 'vue';
import AccessorUtilities from '../../lib/utils/accessor'; import AccessorUtilities from '../../lib/utils/accessor';
...@@ -57,40 +56,6 @@ gl.issueBoards.Board = Vue.extend({ ...@@ -57,40 +56,6 @@ gl.issueBoards.Board = Vue.extend({
}); });
}, },
deep: true, deep: true,
},
detailIssue: {
handler () {
if (!Object.keys(this.detailIssue.issue).length) return;
const issue = this.list.findIssue(this.detailIssue.issue.id);
if (issue) {
const offsetLeft = this.$el.offsetLeft;
const boardsList = document.querySelectorAll('.boards-list')[0];
const left = boardsList.scrollLeft - offsetLeft;
let right = (offsetLeft + this.$el.offsetWidth);
if (window.innerWidth > 768 && boardsList.classList.contains('is-compact')) {
// -290 here because width of boardsList is animating so therefore
// getting the width here is incorrect
// 290 is the width of the sidebar
right -= (boardsList.offsetWidth - 290);
} else {
right -= boardsList.offsetWidth;
}
if (right - boardsList.scrollLeft > 0) {
$(boardsList).animate({
scrollLeft: right
}, this.sortableOptions.animation);
} else if (left > 0) {
$(boardsList).animate({
scrollLeft: offsetLeft
}, this.sortableOptions.animation);
}
}
},
deep: true
} }
}, },
mounted () { mounted () {
......
...@@ -17,7 +17,7 @@ gl.issueBoards.BoardDelete = Vue.extend({ ...@@ -17,7 +17,7 @@ gl.issueBoards.BoardDelete = Vue.extend({
deleteBoard () { deleteBoard () {
$(this.$el).tooltip('hide'); $(this.$el).tooltip('hide');
if (confirm('Are you sure you want to delete this list?')) { if (window.confirm('Are you sure you want to delete this list?')) {
this.list.destroy(); this.list.destroy();
} }
} }
......
...@@ -145,6 +145,6 @@ gl.issueBoards.BoardsStore = { ...@@ -145,6 +145,6 @@ gl.issueBoards.BoardsStore = {
return filteredList[0]; return filteredList[0];
}, },
updateFiltersUrl () { updateFiltersUrl () {
history.pushState(null, null, `?${this.filter.path}`); window.history.pushState(null, null, `?${this.filter.path}`);
} }
}; };
...@@ -45,7 +45,7 @@ export default class CommitsList { ...@@ -45,7 +45,7 @@ export default class CommitsList {
this.content.fadeTo('fast', 1.0); this.content.fadeTo('fast', 1.0);
// Change url so if user reload a page - search results are saved // Change url so if user reload a page - search results are saved
history.replaceState({ window.history.replaceState({
page: commitsUrl, page: commitsUrl,
}, document.title, commitsUrl); }, document.title, commitsUrl);
}) })
......
...@@ -98,7 +98,7 @@ export default { ...@@ -98,7 +98,7 @@ export default {
}, },
disableKey(deployKey, callback) { disableKey(deployKey, callback) {
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
if (confirm(s__('DeployKeys|You are going to remove this deploy key. Are you sure?'))) { if (window.confirm(s__('DeployKeys|You are going to remove this deploy key. Are you sure?'))) {
this.service this.service
.disableKey(deployKey.id) .disableKey(deployKey.id)
.then(this.fetchKeys) .then(this.fetchKeys)
......
...@@ -40,7 +40,7 @@ ...@@ -40,7 +40,7 @@
methods: { methods: {
onClick() { onClick() {
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
if (confirm('Are you sure you want to stop this environment?')) { if (window.confirm('Are you sure you want to stop this environment?')) {
this.isLoading = true; this.isLoading = true;
$(this.$el).tooltip('dispose'); $(this.$el).tooltip('dispose');
......
...@@ -34,6 +34,10 @@ export default { ...@@ -34,6 +34,10 @@ export default {
type: String, type: String,
required: true, required: true,
}, },
actionBtnIcon: {
type: String,
required: true,
},
itemActionComponent: { itemActionComponent: {
type: String, type: String,
required: true, required: true,
...@@ -53,26 +57,21 @@ export default { ...@@ -53,26 +57,21 @@ export default {
required: true, required: true,
}, },
}, },
data() {
return {
showActionButton: false,
};
},
computed: { computed: {
titleText() { titleText() {
return sprintf(__('%{title} changes'), { return sprintf(__('%{title} changes'), {
title: this.title, title: this.title,
}); });
}, },
filesLength() {
return this.fileList.length;
},
}, },
methods: { methods: {
...mapActions(['stageAllChanges', 'unstageAllChanges']), ...mapActions(['stageAllChanges', 'unstageAllChanges']),
actionBtnClicked() { actionBtnClicked() {
this[this.action](); this[this.action]();
}, },
setShowActionButton(show) {
this.showActionButton = show;
},
}, },
}; };
</script> </script>
...@@ -83,8 +82,6 @@ export default { ...@@ -83,8 +82,6 @@ export default {
> >
<header <header
class="multi-file-commit-panel-header" class="multi-file-commit-panel-header"
@mouseenter="setShowActionButton(true)"
@mouseleave="setShowActionButton(false)"
> >
<div <div
class="multi-file-commit-panel-header-title" class="multi-file-commit-panel-header-title"
...@@ -95,24 +92,40 @@ export default { ...@@ -95,24 +92,40 @@ export default {
:size="18" :size="18"
/> />
{{ titleText }} {{ titleText }}
<span <div class="d-flex ml-auto">
v-show="!showActionButton" <button
class="ide-commit-file-count" v-tooltip
> v-show="filesLength"
{{ fileList.length }} :class="{
</span> 'd-flex': filesLength
<button }"
v-show="showActionButton" :title="actionBtnText"
type="button" type="button"
class="btn btn-blank btn-link ide-staged-action-btn" class="btn btn-default ide-staged-action-btn p-0 order-1 align-items-center"
@click="actionBtnClicked" data-placement="bottom"
> data-container="body"
{{ actionBtnText }} data-boundary="viewport"
</button> @click="actionBtnClicked"
>
<icon
:name="actionBtnIcon"
:size="12"
class="ml-auto mr-auto"
/>
</button>
<span
:class="{
'rounded-right': !filesLength
}"
class="ide-commit-file-count order-0 rounded-left text-center"
>
{{ filesLength }}
</span>
</div>
</div> </div>
</header> </header>
<ul <ul
v-if="fileList.length" v-if="filesLength"
class="multi-file-commit-list list-unstyled append-bottom-0" class="multi-file-commit-list list-unstyled append-bottom-0"
> >
<li <li
......
<script> <script>
import { mapActions } from 'vuex'; import { mapActions } from 'vuex';
import tooltip from '~/vue_shared/directives/tooltip';
import Icon from '~/vue_shared/components/icon.vue'; import Icon from '~/vue_shared/components/icon.vue';
import StageButton from './stage_button.vue'; import StageButton from './stage_button.vue';
import UnstageButton from './unstage_button.vue'; import UnstageButton from './unstage_button.vue';
...@@ -11,6 +12,9 @@ export default { ...@@ -11,6 +12,9 @@ export default {
StageButton, StageButton,
UnstageButton, UnstageButton,
}, },
directives: {
tooltip,
},
props: { props: {
file: { file: {
type: Object, type: Object,
...@@ -50,6 +54,9 @@ export default { ...@@ -50,6 +54,9 @@ export default {
isActive() { isActive() {
return this.activeFileKey === this.fullKey; return this.activeFileKey === this.fullKey;
}, },
tooltipTitle() {
return this.file.path === this.file.name ? '' : this.file.path;
},
}, },
methods: { methods: {
...mapActions([ ...mapActions([
...@@ -81,29 +88,30 @@ export default { ...@@ -81,29 +88,30 @@ export default {
</script> </script>
<template> <template>
<div <div class="multi-file-commit-list-item position-relative">
:class="{
'is-active': isActive
}"
class="multi-file-commit-list-item"
>
<button <button
v-tooltip
:title="tooltipTitle"
:class="{
'is-active': isActive
}"
type="button" type="button"
class="multi-file-commit-list-path" class="multi-file-commit-list-path w-100 border-0 ml-0 mr-0"
@dblclick="fileAction" @dblclick="fileAction"
@click="openFileInEditor" @click="openFileInEditor"
> >
<span class="multi-file-commit-list-file-path"> <span class="multi-file-commit-list-file-path d-flex align-items-center">
<icon <icon
:name="iconName" :name="iconName"
:size="16" :size="16"
:css-classes="iconClass" :css-classes="iconClass"
/>{{ file.path }} />{{ file.name }}
</span> </span>
</button> </button>
<component <component
:is="actionComponent" :is="actionComponent"
:path="file.path" :path="file.path"
class="d-flex position-absolute"
/> />
</div> </div>
</template> </template>
...@@ -25,15 +25,17 @@ export default { ...@@ -25,15 +25,17 @@ export default {
<template> <template>
<div <div
v-once v-once
class="multi-file-discard-btn" class="multi-file-discard-btn dropdown"
> >
<button <button
v-tooltip v-tooltip
:aria-label="__('Stage changes')" :aria-label="__('Stage changes')"
:title="__('Stage changes')" :title="__('Stage changes')"
type="button" type="button"
class="btn btn-blank append-right-5" class="btn btn-blank append-right-5 d-flex align-items-center"
data-container="body" data-container="body"
data-boundary="viewport"
data-placement="bottom"
@click.stop="stageChange(path)" @click.stop="stageChange(path)"
> >
<icon <icon
...@@ -43,17 +45,31 @@ export default { ...@@ -43,17 +45,31 @@ export default {
</button> </button>
<button <button
v-tooltip v-tooltip
:aria-label="__('Discard changes')" :title="__('More actions')"
:title="__('Discard changes')"
type="button" type="button"
class="btn btn-blank" class="btn btn-blank d-flex align-items-center"
data-container="body" data-container="body"
@click.stop="discardFileChanges(path)" data-boundary="viewport"
data-placement="bottom"
data-toggle="dropdown"
data-display="static"
> >
<icon <icon
:size="12" :size="12"
name="remove" name="more"
/> />
</button> </button>
<div class="dropdown-menu dropdown-menu-right">
<ul>
<li>
<button
type="button"
@click.stop="discardFileChanges(path)"
>
{{ __('Discard changes') }}
</button>
</li>
</ul>
</div>
</div> </div>
</template> </template>
...@@ -32,8 +32,10 @@ export default { ...@@ -32,8 +32,10 @@ export default {
:aria-label="__('Unstage changes')" :aria-label="__('Unstage changes')"
:title="__('Unstage changes')" :title="__('Unstage changes')"
type="button" type="button"
class="btn btn-blank" class="btn btn-blank d-flex align-items-center"
data-container="body" data-container="body"
data-boundary="viewport"
data-placement="bottom"
@click="unstageChange(path)" @click="unstageChange(path)"
> >
<icon <icon
......
...@@ -93,23 +93,25 @@ export default { ...@@ -93,23 +93,25 @@ export default {
:title="__('Unstaged')" :title="__('Unstaged')"
:key-prefix="$options.stageKeys.unstaged" :key-prefix="$options.stageKeys.unstaged"
:file-list="changedFiles" :file-list="changedFiles"
:action-btn-text="__('Stage all')" :action-btn-text="__('Stage all changes')"
:active-file-key="activeFileKey" :active-file-key="activeFileKey"
class="is-first"
icon-name="unstaged"
action="stageAllChanges" action="stageAllChanges"
action-btn-icon="mobile-issue-close"
item-action-component="stage-button" item-action-component="stage-button"
class="is-first"
icon-name="unstaged"
/> />
<commit-files-list <commit-files-list
:title="__('Staged')" :title="__('Staged')"
:key-prefix="$options.stageKeys.staged" :key-prefix="$options.stageKeys.staged"
:file-list="stagedFiles" :file-list="stagedFiles"
:action-btn-text="__('Unstage all')" :action-btn-text="__('Unstage all changes')"
:staged-list="true" :staged-list="true"
:active-file-key="activeFileKey" :active-file-key="activeFileKey"
icon-name="staged"
action="unstageAllChanges" action="unstageAllChanges"
action-btn-icon="history"
item-action-component="unstage-button" item-action-component="unstage-button"
icon-name="staged"
/> />
</template> </template>
<empty-state <empty-state
......
import { computeDiff } from './diff'; import { computeDiff } from './diff';
// eslint-disable-next-line no-restricted-globals
self.addEventListener('message', (e) => { self.addEventListener('message', (e) => {
const data = e.data; const data = e.data;
// eslint-disable-next-line no-restricted-globals
self.postMessage({ self.postMessage({
path: data.path, path: data.path,
changes: computeDiff(data.originalContent, data.newContent), changes: computeDiff(data.originalContent, data.newContent),
......
...@@ -12,5 +12,6 @@ export const defaultEditorOptions = { ...@@ -12,5 +12,6 @@ export const defaultEditorOptions = {
export default [ export default [
{ {
readOnly: model => !!model.file.file_lock, readOnly: model => !!model.file.file_lock,
quickSuggestions: model => !(model.language === 'markdown'),
}, },
]; ];
import { viewerInformationForPath } from '~/vue_shared/components/content_viewer/lib/viewer_utils'; import { viewerInformationForPath } from '~/vue_shared/components/content_viewer/lib/viewer_utils';
import { decorateData, sortTree } from '../utils'; import { decorateData, sortTree } from '../utils';
// eslint-disable-next-line no-restricted-globals
self.addEventListener('message', e => { self.addEventListener('message', e => {
const { data, projectId, branchId, tempFile = false, content = '', base64 = false } = e.data; const { data, projectId, branchId, tempFile = false, content = '', base64 = false } = e.data;
...@@ -89,6 +90,7 @@ self.addEventListener('message', e => { ...@@ -89,6 +90,7 @@ self.addEventListener('message', e => {
return acc; return acc;
}, {}); }, {});
// eslint-disable-next-line no-restricted-globals
self.postMessage({ self.postMessage({
entries, entries,
treeList: sortTree(treeList), treeList: sortTree(treeList),
......
...@@ -226,7 +226,7 @@ ...@@ -226,7 +226,7 @@
.then(res => res.data) .then(res => res.data)
.then(data => this.checkForSpam(data)) .then(data => this.checkForSpam(data))
.then((data) => { .then((data) => {
if (location.pathname !== data.web_url) { if (window.location.pathname !== data.web_url) {
visitUrl(data.web_url); visitUrl(data.web_url);
} }
......
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
}, },
deleteIssuable() { deleteIssuable() {
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
if (confirm('Issue will be removed! Are you sure?')) { if (window.confirm('Issue will be removed! Are you sure?')) {
this.deleteLoading = true; this.deleteLoading = true;
eventHub.$emit('delete.issuable'); eventHub.$emit('delete.issuable');
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
export default { export default {
computed: { computed: {
currentPath() { currentPath() {
return location.pathname; return window.location.pathname;
}, },
}, },
}; };
......
...@@ -44,8 +44,8 @@ export default class LazyLoader { ...@@ -44,8 +44,8 @@ export default class LazyLoader {
requestAnimationFrame(() => this.checkElementsInView()); requestAnimationFrame(() => this.checkElementsInView());
} }
checkElementsInView() { checkElementsInView() {
const scrollTop = pageYOffset; const scrollTop = window.pageYOffset;
const visHeight = scrollTop + innerHeight + SCROLL_THRESHOLD; const visHeight = scrollTop + window.innerHeight + SCROLL_THRESHOLD;
// Loading Images which are in the current viewport or close to them // Loading Images which are in the current viewport or close to them
this.lazyImages = this.lazyImages.filter((selectedImage) => { this.lazyImages = this.lazyImages.filter((selectedImage) => {
......
...@@ -93,7 +93,7 @@ export default class LinkedTabs { ...@@ -93,7 +93,7 @@ export default class LinkedTabs {
const newState = `${copySource}${this.currentLocation.search}${this.currentLocation.hash}`; const newState = `${copySource}${this.currentLocation.search}${this.currentLocation.hash}`;
history.replaceState({ window.history.replaceState({
url: newState, url: newState,
}, document.title, newState); }, document.title, newState);
return newState; return newState;
......
...@@ -197,7 +197,10 @@ export const insertText = (target, text) => { ...@@ -197,7 +197,10 @@ export const insertText = (target, text) => {
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
target.value = newText; target.value = newText;
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign
target.selectionStart = target.selectionEnd = selectionStart + insertedText.length; target.selectionStart = selectionStart + insertedText.length;
// eslint-disable-next-line no-param-reassign
target.selectionEnd = selectionStart + insertedText.length;
// Trigger autosave // Trigger autosave
target.dispatchEvent(new Event('input')); target.dispatchEvent(new Event('input'));
......
...@@ -12,7 +12,7 @@ export function formatRelevantDigits(number) { ...@@ -12,7 +12,7 @@ export function formatRelevantDigits(number) {
let digitsLeft = ''; let digitsLeft = '';
let relevantDigits = 0; let relevantDigits = 0;
let formattedNumber = ''; let formattedNumber = '';
if (!isNaN(Number(number))) { if (!Number.isNaN(Number(number))) {
digitsLeft = number.toString().split('.')[0]; digitsLeft = number.toString().split('.')[0];
switch (digitsLeft.length) { switch (digitsLeft.length) {
case 1: case 1:
......
...@@ -35,7 +35,7 @@ const LineHighlighter = function(options = {}) { ...@@ -35,7 +35,7 @@ const LineHighlighter = function(options = {}) {
options.highlightLineClass = options.highlightLineClass || 'hll'; options.highlightLineClass = options.highlightLineClass || 'hll';
options.fileHolderSelector = options.fileHolderSelector || '.file-holder'; options.fileHolderSelector = options.fileHolderSelector || '.file-holder';
options.scrollFileHolder = options.scrollFileHolder || false; options.scrollFileHolder = options.scrollFileHolder || false;
options.hash = options.hash || location.hash; options.hash = options.hash || window.location.hash;
this.options = options; this.options = options;
this._hash = options.hash; this._hash = options.hash;
...@@ -145,6 +145,8 @@ LineHighlighter.prototype.highlightRange = function(range) { ...@@ -145,6 +145,8 @@ LineHighlighter.prototype.highlightRange = function(range) {
var i, lineNumber, ref, ref1, results; var i, lineNumber, ref, ref1, results;
if (range[1]) { if (range[1]) {
results = []; results = [];
// eslint-disable-next-line no-multi-assign
for (lineNumber = i = ref = range[0], ref1 = range[1]; ref <= ref1 ? i <= ref1 : i >= ref1; lineNumber = ref <= ref1 ? (i += 1) : (i -= 1)) { for (lineNumber = i = ref = range[0], ref1 = range[1]; ref <= ref1 ? i <= ref1 : i >= ref1; lineNumber = ref <= ref1 ? (i += 1) : (i -= 1)) {
results.push(this.highlightLine(lineNumber)); results.push(this.highlightLine(lineNumber));
} }
...@@ -170,7 +172,7 @@ LineHighlighter.prototype.setHash = function(firstLineNumber, lastLineNumber) { ...@@ -170,7 +172,7 @@ LineHighlighter.prototype.setHash = function(firstLineNumber, lastLineNumber) {
// //
// This method is stubbed in tests. // This method is stubbed in tests.
LineHighlighter.prototype.__setLocationHash__ = function(value) { LineHighlighter.prototype.__setLocationHash__ = function(value) {
return history.pushState({ return window.history.pushState({
url: value url: value
// We're using pushState instead of assigning location.hash directly to // We're using pushState instead of assigning location.hash directly to
// prevent the page from scrolling on the hashchange event // prevent the page from scrolling on the hashchange event
......
...@@ -18,13 +18,13 @@ export default class Milestone { ...@@ -18,13 +18,13 @@ export default class Milestone {
return $('a[data-toggle="tab"]').on('show.bs.tab', (e) => { return $('a[data-toggle="tab"]').on('show.bs.tab', (e) => {
const $target = $(e.target); const $target = $(e.target);
location.hash = $target.attr('href'); window.location.hash = $target.attr('href');
this.loadTab($target); this.loadTab($target);
}); });
} }
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
loadInitialTab() { loadInitialTab() {
const $target = $(`.js-milestone-tabs a[href="${location.hash}"]`); const $target = $(`.js-milestone-tabs a[href="${window.location.hash}"]`);
if ($target.length) { if ($target.length) {
$target.tab('show'); $target.tab('show');
......
...@@ -16,10 +16,10 @@ export default class MilestoneSelect { ...@@ -16,10 +16,10 @@ export default class MilestoneSelect {
typeof currentProject === 'string' ? JSON.parse(currentProject) : currentProject; typeof currentProject === 'string' ? JSON.parse(currentProject) : currentProject;
} }
this.init(els, options); MilestoneSelect.init(els, options);
} }
init(els, options) { static init(els, options) {
let $els = $(els); let $els = $(els);
if (!els) { if (!els) {
...@@ -224,7 +224,6 @@ export default class MilestoneSelect { ...@@ -224,7 +224,6 @@ export default class MilestoneSelect {
$selectBox.hide(); $selectBox.hide();
$value.css('display', ''); $value.css('display', '');
if (data.milestone != null) { if (data.milestone != null) {
data.milestone.full_path = this.currentProject.full_path;
data.milestone.remaining = timeFor(data.milestone.due_date); data.milestone.remaining = timeFor(data.milestone.due_date);
data.milestone.name = data.milestone.title; data.milestone.name = data.milestone.title;
$value.html(milestoneLinkTemplate(data.milestone)); $value.html(milestoneLinkTemplate(data.milestone));
......
...@@ -139,7 +139,7 @@ export default { ...@@ -139,7 +139,7 @@ export default {
this.updateAspectRatio = true; this.updateAspectRatio = true;
}, },
toggleAspectRatio() { toggleAspectRatio() {
this.updatedAspectRatios = this.updatedAspectRatios += 1; this.updatedAspectRatios += 1;
if (this.store.getMetricsCount() === this.updatedAspectRatios) { if (this.store.getMetricsCount() === this.updatedAspectRatios) {
this.updateAspectRatio = !this.updateAspectRatio; this.updateAspectRatio = !this.updateAspectRatio;
this.updatedAspectRatios = 0; this.updatedAspectRatios = 0;
......
...@@ -154,7 +154,7 @@ export default { ...@@ -154,7 +154,7 @@ export default {
point.x = e.clientX; point.x = e.clientX;
point.y = e.clientY; point.y = e.clientY;
point = point.matrixTransform(this.$refs.graphData.getScreenCTM().inverse()); point = point.matrixTransform(this.$refs.graphData.getScreenCTM().inverse());
point.x = point.x += 7; point.x += 7;
const firstTimeSeries = this.timeSeries[0]; const firstTimeSeries = this.timeSeries[0];
const timeValueOverlay = firstTimeSeries.timeSeriesScaleX.invert(point.x); const timeValueOverlay = firstTimeSeries.timeSeriesScaleX.invert(point.x);
const overlayIndex = bisectDate(firstTimeSeries.values, timeValueOverlay, 1); const overlayIndex = bisectDate(firstTimeSeries.values, timeValueOverlay, 1);
......
...@@ -97,7 +97,7 @@ export default { ...@@ -97,7 +97,7 @@ export default {
? this.deploymentFlagData.seriesIndex ? this.deploymentFlagData.seriesIndex
: indexFromCoordinates; : indexFromCoordinates;
const value = series.values[index] && series.values[index].value; const value = series.values[index] && series.values[index].value;
if (isNaN(value)) { if (Number.isNaN(value)) {
return '-'; return '-';
} }
return `${formatRelevantDigits(value)}${this.unitOfDisplay}`; return `${formatRelevantDigits(value)}${this.unitOfDisplay}`;
......
...@@ -73,7 +73,7 @@ function queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom ...@@ -73,7 +73,7 @@ function queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom
timeSeriesScaleX.ticks(d3.timeMinute, 60); timeSeriesScaleX.ticks(d3.timeMinute, 60);
timeSeriesScaleY.domain(yDom); timeSeriesScaleY.domain(yDom);
const defined = d => !isNaN(d.value) && d.value != null; const defined = d => !Number.isNaN(d.value) && d.value != null;
const lineFunction = d3 const lineFunction = d3
.line() .line()
......
...@@ -112,6 +112,8 @@ export default (function() { ...@@ -112,6 +112,8 @@ export default (function() {
fill: "#444" fill: "#444"
}); });
ref = this.days; ref = this.days;
// eslint-disable-next-line no-multi-assign
for (mm = j = 0, len = ref.length; j < len; mm = (j += 1)) { for (mm = j = 0, len = ref.length; j < len; mm = (j += 1)) {
day = ref[mm]; day = ref[mm];
if (cuday !== day[0] || cumonth !== day[1]) { if (cuday !== day[0] || cumonth !== day[1]) {
...@@ -285,6 +287,8 @@ export default (function() { ...@@ -285,6 +287,8 @@ export default (function() {
r = this.r; r = this.r;
ref = commit.parents; ref = commit.parents;
results = []; results = [];
// eslint-disable-next-line no-multi-assign
for (i = j = 0, len = ref.length; j < len; i = (j += 1)) { for (i = j = 0, len = ref.length; j < len; i = (j += 1)) {
parent = ref[i]; parent = ref[i];
parentCommit = this.preparedCommits[parent[0]]; parentCommit = this.preparedCommits[parent[0]];
......
...@@ -315,7 +315,7 @@ export default class Notes { ...@@ -315,7 +315,7 @@ export default class Notes {
if (discussionNoteForm.length) { if (discussionNoteForm.length) {
if ($textarea.val() !== '') { if ($textarea.val() !== '') {
if ( if (
!confirm('Are you sure you want to cancel creating this comment?') !window.confirm('Are you sure you want to cancel creating this comment?')
) { ) {
return; return;
} }
...@@ -329,7 +329,7 @@ export default class Notes { ...@@ -329,7 +329,7 @@ export default class Notes {
newText = $textarea.val(); newText = $textarea.val();
if (originalText !== newText) { if (originalText !== newText) {
if ( if (
!confirm('Are you sure you want to cancel editing this comment?') !window.confirm('Are you sure you want to cancel editing this comment?')
) { ) {
return; return;
} }
......
...@@ -152,7 +152,7 @@ export default { ...@@ -152,7 +152,7 @@ export default {
const msg = 'Are you sure you want to cancel creating this comment?'; const msg = 'Are you sure you want to cancel creating this comment?';
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
if (!confirm(msg)) { if (!window.confirm(msg)) {
return; return;
} }
} }
......
...@@ -77,7 +77,7 @@ export default { ...@@ -77,7 +77,7 @@ export default {
}, },
deleteHandler() { deleteHandler() {
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
if (confirm('Are you sure you want to delete this comment?')) { if (window.confirm('Are you sure you want to delete this comment?')) {
this.isDeleting = true; this.isDeleting = true;
this.deleteNote(this.note) this.deleteNote(this.note)
...@@ -129,7 +129,7 @@ export default { ...@@ -129,7 +129,7 @@ export default {
formCancelHandler(shouldConfirm, isDirty) { formCancelHandler(shouldConfirm, isDirty) {
if (shouldConfirm && isDirty) { if (shouldConfirm && isDirty) {
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
if (!confirm('Are you sure you want to cancel editing this comment?')) if (!window.confirm('Are you sure you want to cancel editing this comment?'))
return; return;
} }
this.$refs.noteBody.resetAutoSave(); this.$refs.noteBody.resetAutoSave();
......
...@@ -36,7 +36,9 @@ export default (function() { ...@@ -36,7 +36,9 @@ export default (function() {
var author_graph, author_header; var author_graph, author_header;
author_header = _this.create_author_header(d); author_header = _this.create_author_header(d);
$(".contributors-list").append(author_header); $(".contributors-list").append(author_header);
_this.authors[d.author_name] = author_graph = new ContributorsAuthorGraph(d.dates);
author_graph = new ContributorsAuthorGraph(d.dates);
_this.authors[d.author_name] = author_graph;
return author_graph.draw(); return author_graph.draw();
}; };
})(this)); })(this));
......
...@@ -111,10 +111,15 @@ export default { ...@@ -111,10 +111,15 @@ export default {
parse_log_entry: function(log_entry, field, date_range) { parse_log_entry: function(log_entry, field, date_range) {
var parsed_entry; var parsed_entry;
parsed_entry = {}; parsed_entry = {};
parsed_entry.author_name = log_entry.author_name; parsed_entry.author_name = log_entry.author_name;
parsed_entry.author_email = log_entry.author_email; parsed_entry.author_email = log_entry.author_email;
parsed_entry.dates = {}; parsed_entry.dates = {};
parsed_entry.commits = parsed_entry.additions = parsed_entry.deletions = 0;
parsed_entry.commits = 0;
parsed_entry.additions = 0;
parsed_entry.deletions = 0;
_.each(_.omit(log_entry, 'author_name', 'author_email'), (function(_this) { _.each(_.omit(log_entry, 'author_name', 'author_email'), (function(_this) {
return function(value, key) { return function(value, key) {
if (_this.in_range(value.date, date_range)) { if (_this.in_range(value.date, date_range)) {
......
...@@ -187,7 +187,7 @@ export default class UserTabs { ...@@ -187,7 +187,7 @@ export default class UserTabs {
let newState = source; let newState = source;
newState = newState.replace(/\/+$/, ''); newState = newState.replace(/\/+$/, '');
newState += this.windowLocation.search + this.windowLocation.hash; newState += this.windowLocation.search + this.windowLocation.hash;
history.replaceState( window.history.replaceState(
{ {
url: newState, url: newState,
}, },
......
...@@ -91,6 +91,7 @@ export default { ...@@ -91,6 +91,7 @@ export default {
class="js-ci-action btn btn-blank class="js-ci-action btn btn-blank
btn-transparent ci-action-icon-container ci-action-icon-wrapper" btn-transparent ci-action-icon-container ci-action-icon-wrapper"
data-container="body" data-container="body"
data-boundary="viewport"
@click="onClickAction" @click="onClickAction"
> >
<icon :name="actionIcon"/> <icon :name="actionIcon"/>
......
...@@ -87,6 +87,7 @@ export default { ...@@ -87,6 +87,7 @@ export default {
data-toggle="dropdown" data-toggle="dropdown"
data-container="body" data-container="body"
data-boundary="viewport" data-boundary="viewport"
data-display="static"
class="dropdown-menu-toggle build-content" class="dropdown-menu-toggle build-content"
> >
......
...@@ -165,6 +165,7 @@ export default { ...@@ -165,6 +165,7 @@ export default {
class="mini-pipeline-graph-dropdown-toggle js-builds-dropdown-button" class="mini-pipeline-graph-dropdown-toggle js-builds-dropdown-button"
data-placement="top" data-placement="top"
data-toggle="dropdown" data-toggle="dropdown"
data-display="static"
type="button" type="button"
aria-haspopup="true" aria-haspopup="true"
aria-expanded="false" aria-expanded="false"
......
...@@ -139,6 +139,8 @@ import _ from 'underscore'; ...@@ -139,6 +139,8 @@ import _ from 'underscore';
var array, binary, i, k, len, v; var array, binary, i, k, len, v;
binary = atob(dataURL.split(',')[1]); binary = atob(dataURL.split(',')[1]);
array = []; array = [];
// eslint-disable-next-line no-multi-assign
for (k = i = 0, len = binary.length; i < len; k = (i += 1)) { for (k = i = 0, len = binary.length; i < len; k = (i += 1)) {
v = binary[k]; v = binary[k];
array.push(binary.charCodeAt(k)); array.push(binary.charCodeAt(k));
......
...@@ -91,6 +91,8 @@ export default class ProjectFindFile { ...@@ -91,6 +91,8 @@ export default class ProjectFindFile {
var blobItemUrl, filePath, html, i, j, len, matches, results; var blobItemUrl, filePath, html, i, j, len, matches, results;
this.element.find(".tree-table > tbody").empty(); this.element.find(".tree-table > tbody").empty();
results = []; results = [];
// eslint-disable-next-line no-multi-assign
for (i = j = 0, len = filePaths.length; j < len; i = (j += 1)) { for (i = j = 0, len = filePaths.length; j < len; i = (j += 1)) {
filePath = filePaths[i]; filePath = filePaths[i];
if (i === 20) { if (i === 20) {
...@@ -150,7 +152,7 @@ export default class ProjectFindFile { ...@@ -150,7 +152,7 @@ export default class ProjectFindFile {
} }
goToTree() { goToTree() {
return location.href = this.options.treeUrl; return window.location.href = this.options.treeUrl;
} }
goToBlob() { goToBlob() {
......
...@@ -2,7 +2,7 @@ import { visitUrl } from './lib/utils/url_utility'; ...@@ -2,7 +2,7 @@ import { visitUrl } from './lib/utils/url_utility';
export default function projectImport() { export default function projectImport() {
setTimeout(() => { setTimeout(() => {
visitUrl(location.href); visitUrl(window.location.href);
}, 5000); }, 5000);
} }
...@@ -107,7 +107,7 @@ export default class PrometheusMetrics { ...@@ -107,7 +107,7 @@ export default class PrometheusMetrics {
if (data && data.success) { if (data && data.success) {
stop(data); stop(data);
} else { } else {
this.backOffRequestCounter = this.backOffRequestCounter += 1; this.backOffRequestCounter += 1;
if (this.backOffRequestCounter < 3) { if (this.backOffRequestCounter < 3) {
next(); next();
} else { } else {
......
...@@ -438,7 +438,7 @@ export default class SearchAutocomplete { ...@@ -438,7 +438,7 @@ export default class SearchAutocomplete {
} }
onClick(item, $el, e) { onClick(item, $el, e) {
if (location.pathname.indexOf(item.url) !== -1) { if (window.location.pathname.indexOf(item.url) !== -1) {
if (!e.metaKey) e.preventDefault(); if (!e.metaKey) e.preventDefault();
if (!this.badgePresent) { if (!this.badgePresent) {
if (item.category === 'Projects') { if (item.category === 'Projects') {
......
...@@ -42,8 +42,8 @@ export default function initSettingsPanels() { ...@@ -42,8 +42,8 @@ export default function initSettingsPanels() {
} }
}); });
if (location.hash) { if (window.location.hash) {
const $target = $(location.hash); const $target = $(window.location.hash);
if ($target.length && $target.hasClass('settings')) { if ($target.length && $target.hasClass('settings')) {
expandSection($target); expandSection($target);
} }
......
...@@ -13,8 +13,8 @@ export default class ShortcutsFindFile extends ShortcutsNavigation { ...@@ -13,8 +13,8 @@ export default class ShortcutsFindFile extends ShortcutsNavigation {
element === this.projectFindFile.inputElement[0] && element === this.projectFindFile.inputElement[0] &&
(combo === 'up' || combo === 'down' || combo === 'esc' || combo === 'enter') (combo === 'up' || combo === 'down' || combo === 'esc' || combo === 'enter')
) { ) {
// when press up/down key in textbox, cusor prevent to move to home/end // when press up/down key in textbox, cursor prevent to move to home/end
event.preventDefault(); e.preventDefault();
return false; return false;
} }
......
...@@ -54,7 +54,7 @@ export default { ...@@ -54,7 +54,7 @@ export default {
updateConfidentialAttribute(confidential) { updateConfidentialAttribute(confidential) {
this.service this.service
.update('issue', { confidential }) .update('issue', { confidential })
.then(() => location.reload()) .then(() => window.location.reload())
.catch(() => { .catch(() => {
Flash( Flash(
__( __(
......
...@@ -76,7 +76,7 @@ export default { ...@@ -76,7 +76,7 @@ export default {
.update(this.issuableType, { .update(this.issuableType, {
discussion_locked: locked, discussion_locked: locked,
}) })
.then(() => location.reload()) .then(() => window.location.reload())
.catch(() => .catch(() =>
Flash( Flash(
this.__( this.__(
......
...@@ -80,7 +80,7 @@ export default class SidebarMediator { ...@@ -80,7 +80,7 @@ export default class SidebarMediator {
return this.service.moveIssue(this.store.moveToProjectId) return this.service.moveIssue(this.store.moveToProjectId)
.then(response => response.json()) .then(response => response.json())
.then((data) => { .then((data) => {
if (location.pathname !== data.web_url) { if (window.location.pathname !== data.web_url) {
visitUrl(data.web_url); visitUrl(data.web_url);
} }
}); });
......
export default () => { export default () => {
const { protocol, host, pathname } = location; const { protocol, host, pathname } = window.location;
const shareBtn = document.querySelector('.js-share-btn'); const shareBtn = document.querySelector('.js-share-btn');
const embedBtn = document.querySelector('.js-embed-btn'); const embedBtn = document.querySelector('.js-embed-btn');
const snippetUrlArea = document.querySelector('.js-snippet-url-area'); const snippetUrlArea = document.querySelector('.js-snippet-url-area');
......
...@@ -259,6 +259,7 @@ function UsersSelect(currentUser, els, options = {}) { ...@@ -259,6 +259,7 @@ function UsersSelect(currentUser, els, options = {}) {
showDivider = 0; showDivider = 0;
if (firstUser) { if (firstUser) {
// Move current user to the front of the list // Move current user to the front of the list
// eslint-disable-next-line no-multi-assign
for (index = j = 0, len = users.length; j < len; index = (j += 1)) { for (index = j = 0, len = users.length; j < len; index = (j += 1)) {
obj = users[index]; obj = users[index];
if (obj.username === firstUser) { if (obj.username === firstUser) {
...@@ -561,6 +562,8 @@ function UsersSelect(currentUser, els, options = {}) { ...@@ -561,6 +562,8 @@ function UsersSelect(currentUser, els, options = {}) {
if (firstUser) { if (firstUser) {
// Move current user to the front of the list // Move current user to the front of the list
ref = data.results; ref = data.results;
// eslint-disable-next-line no-multi-assign
for (index = j = 0, len = ref.length; j < len; index = (j += 1)) { for (index = j = 0, len = ref.length; j < len; index = (j += 1)) {
obj = ref[index]; obj = ref[index];
if (obj.username === firstUser) { if (obj.username === firstUser) {
......
...@@ -105,7 +105,7 @@ export default { ...@@ -105,7 +105,7 @@ export default {
MRWidgetService.fetchMetrics(this.metricsUrl) MRWidgetService.fetchMetrics(this.metricsUrl)
.then((res) => { .then((res) => {
if (res.status === statusCodes.NO_CONTENT) { if (res.status === statusCodes.NO_CONTENT) {
this.backOffRequestCounter = this.backOffRequestCounter += 1; this.backOffRequestCounter += 1;
/* eslint-disable no-unused-expressions */ /* eslint-disable no-unused-expressions */
this.backOffRequestCounter < 3 ? next() : stop(res); this.backOffRequestCounter < 3 ? next() : stop(res);
} else { } else {
......
...@@ -128,11 +128,6 @@ table { ...@@ -128,11 +128,6 @@ table {
border-spacing: 0; border-spacing: 0;
} }
.tooltip {
// Fix bootstrap4 bug whereby tooltips flicker when they are hovered over their borders
pointer-events: none;
}
.popover { .popover {
font-size: 14px; font-size: 14px;
} }
...@@ -213,6 +208,15 @@ table { ...@@ -213,6 +208,15 @@ table {
&:not(:last-of-type) { &:not(:last-of-type) {
border-bottom: 1px solid $well-inner-border; border-bottom: 1px solid $well-inner-border;
} }
p,
ol,
ul,
.form-group {
&:last-of-type {
margin-bottom: 0;
}
}
} }
.badge.badge-gray { .badge.badge-gray {
...@@ -264,15 +268,36 @@ pre code { ...@@ -264,15 +268,36 @@ pre code {
white-space: pre-wrap; white-space: pre-wrap;
} }
.alert,
.flash-notice {
border-radius: 0;
}
.alert-success {
background-color: $green-500;
border-color: $green-500;
}
.alert-info {
background-color: $blue-500;
border-color: $blue-500;
}
.alert-warning {
background-color: $orange-500;
border-color: $orange-500;
}
.alert-danger { .alert-danger {
background-color: $red-500; background-color: $red-500;
border-color: $red-500; border-color: $red-500;
} }
.alert-success,
.alert-info,
.alert-warning, .alert-warning,
.alert-danger, .alert-danger,
.flash-notice { .flash-notice {
border-radius: 0;
color: $white-light; color: $white-light;
h4, h4,
......
...@@ -54,10 +54,6 @@ body { ...@@ -54,10 +54,6 @@ body {
&.limit-container-width { &.limit-container-width {
max-width: $limited-layout-width; max-width: $limited-layout-width;
} }
&.limit-container-width-sm {
max-width: $limited-layout-width-sm;
}
} }
.alert-wrapper { .alert-wrapper {
......
...@@ -347,7 +347,7 @@ ...@@ -347,7 +347,7 @@
.empty-state .project-item-select-holder.btn-group { .empty-state .project-item-select-holder.btn-group {
float: none; float: none;
display: inline-block; justify-content: center;
.btn { .btn {
// overrides styles applied to plain `.empty-state .btn` // overrides styles applied to plain `.empty-state .btn`
......
...@@ -244,10 +244,11 @@ $tooltip-font-size: 12px; ...@@ -244,10 +244,11 @@ $tooltip-font-size: 12px;
/* /*
* Padding * Padding
*/ */
$gl-padding-24: 24px;
$gl-padding: 16px;
$gl-padding-8: 8px;
$gl-padding-4: 4px; $gl-padding-4: 4px;
$gl-padding-8: 8px;
$gl-padding: 16px;
$gl-padding-24: 24px;
$gl-padding-32: 32px;
$gl-col-padding: 15px; $gl-col-padding: 15px;
$gl-input-padding: 10px; $gl-input-padding: 10px;
$gl-vert-padding: 6px; $gl-vert-padding: 6px;
...@@ -265,7 +266,6 @@ $header-height: 40px; ...@@ -265,7 +266,6 @@ $header-height: 40px;
$ide-statusbar-height: 25px; $ide-statusbar-height: 25px;
$fixed-layout-width: 1280px; $fixed-layout-width: 1280px;
$limited-layout-width: 990px; $limited-layout-width: 990px;
$limited-layout-width-sm: 790px;
$container-text-max-width: 540px; $container-text-max-width: 540px;
$gl-avatar-size: 40px; $gl-avatar-size: 40px;
$error-exclamation-point: $red-500; $error-exclamation-point: $red-500;
...@@ -834,3 +834,4 @@ $font-family-sans-serif: $regular_font; ...@@ -834,3 +834,4 @@ $font-family-sans-serif: $regular_font;
$font-family-monospace: $monospace_font; $font-family-monospace: $monospace_font;
$input-line-height: 20px; $input-line-height: 20px;
$btn-line-height: 20px; $btn-line-height: 20px;
$table-accent-bg: $gray-light;
...@@ -193,6 +193,10 @@ ...@@ -193,6 +193,10 @@
display: inline-flex; display: inline-flex;
} }
.ci-status-icon svg {
vertical-align: text-bottom;
}
> .ci-status-link, > .ci-status-link,
> .btn, > .btn,
> .commit-sha-group { > .commit-sha-group {
......
...@@ -280,7 +280,7 @@ ...@@ -280,7 +280,7 @@
width: 150px; width: 150px;
flex-shrink: 0; flex-shrink: 0;
.label { .badge {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
max-width: 100%; max-width: 100%;
......
...@@ -1001,7 +1001,7 @@ button.mini-pipeline-graph-dropdown-toggle { ...@@ -1001,7 +1001,7 @@ button.mini-pipeline-graph-dropdown-toggle {
/** /**
* Center dropdown menu in mini graph * Center dropdown menu in mini graph
*/ */
&.dropdown-menu { .dropdown &.dropdown-menu {
transform: translate(-80%, 0); transform: translate(-80%, 0);
@media (min-width: map-get($grid-breakpoints, md)) { @media (min-width: map-get($grid-breakpoints, md)) {
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
.application-theme { .application-theme {
label { label {
margin: 0 $gl-padding $gl-padding 0; margin: 0 $gl-padding-32 $gl-padding 0;
text-align: center; text-align: center;
} }
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
font-size: 0; font-size: 0;
height: 48px; height: 48px;
border-radius: 4px; border-radius: 4px;
min-width: 135px; min-width: 112px;
margin-bottom: $gl-padding-8; margin-bottom: $gl-padding-8;
&.ui-indigo { &.ui-indigo {
...@@ -75,7 +75,8 @@ ...@@ -75,7 +75,8 @@
.syntax-theme { .syntax-theme {
label { label {
margin-right: 20px; margin-right: $gl-padding-32;
margin-bottom: $gl-padding;
text-align: center; text-align: center;
.preview { .preview {
...@@ -84,7 +85,6 @@ ...@@ -84,7 +85,6 @@
img { img {
border-radius: 4px; border-radius: 4px;
max-width: 100%; max-width: 100%;
} }
} }
......
...@@ -858,7 +858,6 @@ pre.light-well { ...@@ -858,7 +858,6 @@ pre.light-well {
.git-clone-holder { .git-clone-holder {
width: 380px; width: 380px;
height: 28px;
.btn-clipboard { .btn-clipboard {
border: 1px solid $border-color; border: 1px solid $border-color;
......
...@@ -540,36 +540,12 @@ ...@@ -540,36 +540,12 @@
margin-right: -$grid-size; margin-right: -$grid-size;
min-height: 60px; min-height: 60px;
.multi-file-commit-list-item {
margin-left: 0;
margin-right: 0;
}
&.form-text.text-muted { &.form-text.text-muted {
margin-left: 0; margin-left: 0;
right: 0; right: 0;
} }
} }
.multi-file-commit-list-item {
&.is-active {
background-color: $white-normal;
}
.multi-file-discard-btn {
display: none;
margin-top: -2px;
margin-left: auto;
color: $gl-link-color;
}
&:hover {
.multi-file-discard-btn {
display: flex;
}
}
}
.multi-file-addition, .multi-file-addition,
.multi-file-addition-solid { .multi-file-addition-solid {
color: $green-500; color: $green-500;
...@@ -599,7 +575,7 @@ ...@@ -599,7 +575,7 @@
} }
} }
.multi-file-commit-list-item, .multi-file-commit-list-path,
.ide-file-list .file { .ide-file-list .file {
display: flex; display: flex;
align-items: center; align-items: center;
...@@ -616,11 +592,9 @@ ...@@ -616,11 +592,9 @@
} }
.multi-file-commit-list-path { .multi-file-commit-list-path {
padding: 0; &.is-active {
background: none; background-color: $white-normal;
border: 0; }
text-align: left;
width: 100%;
&:hover, &:hover,
&:focus { &:focus {
...@@ -635,7 +609,7 @@ ...@@ -635,7 +609,7 @@
} }
.multi-file-commit-list-file-path { .multi-file-commit-list-file-path {
@include str-truncated(100%); @include str-truncated(calc(100% - 30px));
&:hover { &:hover {
text-decoration: underline; text-decoration: underline;
...@@ -646,6 +620,16 @@ ...@@ -646,6 +620,16 @@
} }
} }
.multi-file-discard-btn {
top: 4px;
right: 8px;
bottom: 4px;
svg {
top: 0;
}
}
.multi-file-commit-form { .multi-file-commit-form {
position: relative; position: relative;
background-color: $white-light; background-color: $white-light;
...@@ -840,18 +824,20 @@ ...@@ -840,18 +824,20 @@
} }
.ide-staged-action-btn { .ide-staged-action-btn {
margin-left: auto; width: 22px;
line-height: 22px; margin-left: -1px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
> svg {
top: 0;
}
} }
.ide-commit-file-count { .ide-commit-file-count {
min-width: 22px; min-width: 22px;
margin-left: auto;
background-color: $gray-light; background-color: $gray-light;
border-radius: $border-radius-default;
border: 1px solid $white-dark; border: 1px solid $white-dark;
line-height: 20px;
text-align: center;
} }
.ide-commit-radios { .ide-commit-radios {
......
...@@ -296,7 +296,8 @@ ...@@ -296,7 +296,8 @@
} }
.btn-clipboard { .btn-clipboard {
margin-left: 5px; background-color: $white-light;
border: 1px solid $theme-gray-200;
} }
.deploy-token-help-block { .deploy-token-help-block {
......
module IssuesAction module IssuesAction
extend ActiveSupport::Concern extend ActiveSupport::Concern
include IssuableCollections include IssuableCollections
include IssuesCalendar
# rubocop:disable Gitlab/ModuleWithInstanceVariables # rubocop:disable Gitlab/ModuleWithInstanceVariables
def issues def issues
...@@ -17,18 +18,9 @@ module IssuesAction ...@@ -17,18 +18,9 @@ module IssuesAction
end end
# rubocop:enable Gitlab/ModuleWithInstanceVariables # rubocop:enable Gitlab/ModuleWithInstanceVariables
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def issues_calendar def issues_calendar
@issues = issuables_collection render_issues_calendar(issuables_collection)
.non_archived
.with_due_date
.limit(100)
respond_to do |format|
format.ics { response.headers['Content-Disposition'] = 'inline' }
end
end end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
private private
......
module IssuesCalendar
extend ActiveSupport::Concern
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def render_issues_calendar(issuables)
@issues = issuables
.non_archived
.with_due_date
.limit(100)
respond_to do |format|
format.ics do
# NOTE: with text/calendar as Content-Type, the browser always downloads
# the content as a file (even ignoring the Content-Disposition
# header). We want to display the content inline when accessed
# from GitLab, similarly to the RSS feed.
if request.referer&.start_with?(::Settings.gitlab.base_url)
response.headers['Content-Type'] = 'text/plain'
end
end
end
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
end
...@@ -7,6 +7,7 @@ class Projects::ArtifactsController < Projects::ApplicationController ...@@ -7,6 +7,7 @@ class Projects::ArtifactsController < Projects::ApplicationController
before_action :authorize_read_build! before_action :authorize_read_build!
before_action :authorize_update_build!, only: [:keep] before_action :authorize_update_build!, only: [:keep]
before_action :extract_ref_name_and_path before_action :extract_ref_name_and_path
before_action :set_request_format, only: [:file]
before_action :validate_artifacts! before_action :validate_artifacts!
before_action :entry, only: [:file] before_action :entry, only: [:file]
...@@ -101,4 +102,12 @@ class Projects::ArtifactsController < Projects::ApplicationController ...@@ -101,4 +102,12 @@ class Projects::ArtifactsController < Projects::ApplicationController
render_404 unless @entry.exists? render_404 unless @entry.exists?
end end
def set_request_format
request.format = :html if set_request_format?
end
def set_request_format?
request.format != :json
end
end end
...@@ -7,6 +7,7 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -7,6 +7,7 @@ class Projects::BlobController < Projects::ApplicationController
prepend_before_action :authenticate_user!, only: [:edit] prepend_before_action :authenticate_user!, only: [:edit]
before_action :set_request_format, only: [:edit, :show, :update]
before_action :require_non_empty_project, except: [:new, :create] before_action :require_non_empty_project, except: [:new, :create]
before_action :authorize_download_code! before_action :authorize_download_code!
...@@ -188,6 +189,18 @@ class Projects::BlobController < Projects::ApplicationController ...@@ -188,6 +189,18 @@ class Projects::BlobController < Projects::ApplicationController
.last_for_path(@repository, @ref, @path).sha .last_for_path(@repository, @ref, @path).sha
end end
# In Rails 4.2 if params[:format] is empty, Rails set it to :html
# But since Rails 5.0 the framework now looks for an extension.
# E.g. for `blob/master/CHANGELOG.md` in Rails 4 the format would be `:html`, but in Rails 5 on it'd be `:md`
# This before_action explicitly sets the `:html` format for all requests unless `:format` is set by a client e.g. by JS for XHR requests.
def set_request_format
request.format = :html if set_request_format?
end
def set_request_format?
params[:id].present? && params[:format].blank? && request.format != "json"
end
def show_html def show_html
environment_params = @repository.branch_exists?(@ref) ? { ref: @ref } : { commit: @commit } environment_params = @repository.branch_exists?(@ref) ? { ref: @ref } : { commit: @commit }
@environment = EnvironmentsFinder.new(@project, current_user, environment_params).execute.last @environment = EnvironmentsFinder.new(@project, current_user, environment_params).execute.last
......
...@@ -4,6 +4,7 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -4,6 +4,7 @@ class Projects::IssuesController < Projects::ApplicationController
include IssuableActions include IssuableActions
include ToggleAwardEmoji include ToggleAwardEmoji
include IssuableCollections include IssuableCollections
include IssuesCalendar
include SpammableActions include SpammableActions
prepend_before_action :authenticate_user!, only: [:new] prepend_before_action :authenticate_user!, only: [:new]
...@@ -40,14 +41,7 @@ class Projects::IssuesController < Projects::ApplicationController ...@@ -40,14 +41,7 @@ class Projects::IssuesController < Projects::ApplicationController
end end
def calendar def calendar
@issues = @issuables render_issues_calendar(@issuables)
.non_archived
.with_due_date
.limit(100)
respond_to do |format|
format.ics { response.headers['Content-Disposition'] = 'inline' }
end
end end
def new def new
......
...@@ -115,7 +115,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo ...@@ -115,7 +115,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
end end
format.json do format.json do
render json: @merge_request.to_json(include: { milestone: {}, assignee: { only: [:name, :username], methods: [:avatar_url] }, labels: { methods: :text_color } }, methods: [:task_status, :task_status_short]) render json: serializer.represent(@merge_request, serializer: 'basic')
end end
end end
rescue ActiveRecord::StaleObjectError rescue ActiveRecord::StaleObjectError
......
...@@ -5,4 +5,8 @@ class MergeRequestBasicEntity < IssuableSidebarEntity ...@@ -5,4 +5,8 @@ class MergeRequestBasicEntity < IssuableSidebarEntity
expose :state expose :state
expose :source_branch_exists?, as: :source_branch_exists expose :source_branch_exists?, as: :source_branch_exists
expose :rebase_in_progress?, as: :rebase_in_progress expose :rebase_in_progress?, as: :rebase_in_progress
expose :milestone, using: API::Entities::Milestone
expose :labels, using: LabelEntity
expose :assignee, using: API::Entities::UserBasic
expose :task_status, :task_status_short
end end
...@@ -25,14 +25,12 @@ module Ci ...@@ -25,14 +25,12 @@ module Ci
valid = true valid = true
if Feature.enabled?('ci_job_request_with_tags_matcher') # pick builds that does not have other tags than runner's one
# pick builds that does not have other tags than runner's one builds = builds.matches_tag_ids(runner.tags.ids)
builds = builds.matches_tag_ids(runner.tags.ids)
# pick builds that have at least one tag # pick builds that have at least one tag
unless runner.run_untagged? unless runner.run_untagged?
builds = builds.with_any_tags builds = builds.with_any_tags
end
end end
builds.find do |build| builds.find do |build|
......
...@@ -11,7 +11,7 @@ module Projects ...@@ -11,7 +11,7 @@ module Projects
order: { due_date: :asc, title: :asc } order: { due_date: :asc, title: :asc }
} }
finder_params[:group_ids] = @project.group.self_and_ancestors.select(:id) if @project.group finder_params[:group_ids] = @project.group.self_and_ancestors_ids if @project.group
MilestonesFinder.new(finder_params).execute.select([:iid, :title]) MilestonesFinder.new(finder_params).execute.select([:iid, :title])
end end
......
class FaviconUploader < AttachmentUploader class FaviconUploader < AttachmentUploader
EXTENSION_WHITELIST = %w[png ico].freeze EXTENSION_WHITELIST = %w[png ico].freeze
include CarrierWave::MiniMagick
version :favicon_main do
process resize_to_fill: [32, 32]
process convert: 'png'
def full_filename(filename)
filename_for_different_format(super(filename), 'png')
end
end
def extension_whitelist def extension_whitelist
EXTENSION_WHITELIST EXTENSION_WHITELIST
end end
......
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
= f.label :favicon, 'Favicon', class: 'col-sm-2 col-form-label' = f.label :favicon, 'Favicon', class: 'col-sm-2 col-form-label'
.col-sm-10 .col-sm-10
- if @appearance.favicon? - if @appearance.favicon?
= image_tag @appearance.favicon.favicon_main.url, class: 'appearance-light-logo-preview' = image_tag @appearance.favicon_url, class: 'appearance-light-logo-preview'
- if @appearance.persisted? - if @appearance.persisted?
%br %br
= link_to 'Remove favicon', favicon_admin_appearances_path, data: { confirm: "Favicon will be removed. Are you sure?"}, method: :delete, class: "btn btn-inverted btn-remove btn-sm remove-logo" = link_to 'Remove favicon', favicon_admin_appearances_path, data: { confirm: "Favicon will be removed. Are you sure?"}, method: :delete, class: "btn btn-inverted btn-remove btn-sm remove-logo"
...@@ -33,9 +33,9 @@ ...@@ -33,9 +33,9 @@
= f.hidden_field :favicon_cache = f.hidden_field :favicon_cache
= f.file_field :favicon, class: '' = f.file_field :favicon, class: ''
.hint .hint
Maximum file size is 1MB. Allowed image formats are #{favicon_extension_whitelist}. Maximum file size is 1MB. Image size must be 32x32px. Allowed image formats are #{favicon_extension_whitelist}.
%br %br
The resulting favicons will be cropped to be square and scaled down to a size of 32x32 px. Images with incorrect dimensions are not resized automatically, and may result in unexpected behavior.
%fieldset.sign-in %fieldset.sign-in
%legend %legend
......
- if current_user - if current_user
.dropdown .dropdown
%button.dropdown-toggle{ href: '#', "data-toggle" => "dropdown" } %button.dropdown-toggle{ href: '#', "data-toggle" => "dropdown", 'data-display' => 'static' }
= icon('globe') = icon('globe')
%span.light Visibility: %span.light Visibility:
- if params[:visibility_level].present? - if params[:visibility_level].present?
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
- if can_create_subgroups - if can_create_subgroups
.btn-group.new-project-subgroup.droplab-dropdown.js-new-project-subgroup{ data: { project_path: new_project_path(namespace_id: @group.id), subgroup_path: new_group_path(parent_id: @group.id) } } .btn-group.new-project-subgroup.droplab-dropdown.js-new-project-subgroup{ data: { project_path: new_project_path(namespace_id: @group.id), subgroup_path: new_group_path(parent_id: @group.id) } }
%input.btn.btn-success.dropdown-primary.js-new-group-child{ type: "button", value: new_project_label, data: { action: "new-project" } } %input.btn.btn-success.dropdown-primary.js-new-group-child{ type: "button", value: new_project_label, data: { action: "new-project" } }
%button.btn.btn-success.dropdown-toggle.js-dropdown-toggle{ type: "button", data: { "dropdown-trigger" => "#new-project-or-subgroup-dropdown" } } %button.btn.btn-success.dropdown-toggle.js-dropdown-toggle{ type: "button", data: { "dropdown-trigger" => "#new-project-or-subgroup-dropdown", 'display' => 'static' } }
= icon("caret-down", class: "dropdown-btn-icon") = icon("caret-down", class: "dropdown-btn-icon")
%ul#new-project-or-subgroup-dropdown.dropdown-menu.dropdown-menu-right{ data: { dropdown: true } } %ul#new-project-or-subgroup-dropdown.dropdown-menu.dropdown-menu-right{ data: { dropdown: true } }
%li.droplab-item-selected{ role: "button", data: { value: "new-project", text: new_project_label } } %li.droplab-item-selected{ role: "button", data: { value: "new-project", text: new_project_label } }
......
...@@ -443,8 +443,6 @@ ...@@ -443,8 +443,6 @@
.col-md-6 .col-md-6
.alert.alert-success .alert.alert-success
= lorem = lorem
.alert.alert-primary
= lorem
.alert.alert-info .alert.alert-info
= lorem = lorem
.col-md-6 .col-md-6
......
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
- else - else
.input-group-prepend.static-namespace.has-tooltip{ title: user_url(current_user.username) + '/' } .input-group-prepend.static-namespace.has-tooltip{ title: user_url(current_user.username) + '/' }
.input-group-text .input-group-text.border-0
#{user_url(current_user.username)}/ #{user_url(current_user.username)}/
= hidden_field_tag :namespace_id, value: current_user.namespace_id = hidden_field_tag :namespace_id, value: current_user.namespace_id
.form-group.col-12.col-sm-6.project-path .form-group.col-12.col-sm-6.project-path
......
%li.header-new.dropdown %li.header-new.dropdown
= link_to new_project_path, class: "header-new-dropdown-toggle has-tooltip qa-new-menu-toggle", title: "New...", ref: 'tooltip', aria: { label: "New..." }, data: { toggle: 'dropdown', placement: 'bottom', container: 'body' } do = link_to new_project_path, class: "header-new-dropdown-toggle has-tooltip qa-new-menu-toggle", title: "New...", ref: 'tooltip', aria: { label: "New..." }, data: { toggle: 'dropdown', placement: 'bottom', container: 'body', display: 'static' } do
= sprite_icon('plus-square', size: 16) = sprite_icon('plus-square', size: 16)
= sprite_icon('angle-down', css_class: 'caret-down') = sprite_icon('angle-down', css_class: 'caret-down')
.dropdown-menu.dropdown-menu-right .dropdown-menu.dropdown-menu-right
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
- else - else
.input-group-prepend.static-namespace.has-tooltip{ title: user_url(current_user.username) + '/' } .input-group-prepend.static-namespace.has-tooltip{ title: user_url(current_user.username) + '/' }
.input-group-text .input-group-text.border-0
#{user_url(current_user.username)}/ #{user_url(current_user.username)}/
= f.hidden_field :namespace_id, value: current_user.namespace_id = f.hidden_field :namespace_id, value: current_user.namespace_id
.form-group.project-path.col-sm-6 .form-group.project-path.col-sm-6
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
- if !project.empty_repo? && can?(current_user, :download_code, project) - if !project.empty_repo? && can?(current_user, :download_code, project)
- archive_prefix = "#{project.path}-#{ref.tr('/', '-')}" - archive_prefix = "#{project.path}-#{ref.tr('/', '-')}"
.project-action-button.dropdown.inline> .project-action-button.dropdown.inline>
%button.btn.has-tooltip{ title: s_('DownloadSource|Download'), 'data-toggle' => 'dropdown', 'aria-label' => s_('DownloadSource|Download') } %button.btn.has-tooltip{ title: s_('DownloadSource|Download'), 'data-toggle' => 'dropdown', 'aria-label' => s_('DownloadSource|Download'), 'data-display' => 'static' }
= sprite_icon('download') = sprite_icon('download')
= icon("caret-down") = icon("caret-down")
%span.sr-only= _('Select Archive Format') %span.sr-only= _('Select Archive Format')
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
- if show_menu - if show_menu
.project-action-button.dropdown.inline .project-action-button.dropdown.inline
%a.btn.dropdown-toggle.has-tooltip{ href: '#', title: _('Create new...'), 'data-toggle' => 'dropdown', 'data-container' => 'body', 'aria-label' => _('Create new...') } %a.btn.dropdown-toggle.has-tooltip{ href: '#', title: _('Create new...'), 'data-toggle' => 'dropdown', 'data-container' => 'body', 'aria-label' => _('Create new...'), 'data-display' => 'static' }
= icon('plus') = icon('plus')
= icon("caret-down") = icon("caret-down")
%ul.dropdown-menu.dropdown-menu-right.project-home-dropdown %ul.dropdown-menu.dropdown-menu-right.project-home-dropdown
......
= javascript_include_tag 'https://apis.google.com/js/api.js' = javascript_include_tag 'https://apis.google.com/js/api.js'
- external_link_icon = icon('external-link')
- zones_link_url = 'https://cloud.google.com/compute/docs/regions-zones/regions-zones'
- machine_type_link_url = 'https://cloud.google.com/compute/docs/machine-types'
- pricing_link_url = 'https://cloud.google.com/compute/pricing#machinetype'
- help_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe
- help_link_end = ' %{external_link_icon}</a>'.html_safe % { external_link_icon: external_link_icon }
%p %p
- link_to_help_page = link_to(s_('ClusterIntegration|help page'), help_page_path('user/project/clusters/index'), target: '_blank', rel: 'noopener noreferrer') - link_to_help_page = link_to(s_('ClusterIntegration|help page'), help_page_path('user/project/clusters/index'), target: '_blank', rel: 'noopener noreferrer')
...@@ -7,15 +13,15 @@ ...@@ -7,15 +13,15 @@
= form_for @cluster, html: { class: 'js-gke-cluster-creation prepend-top-20', data: { token: token_in_session } }, url: gcp_namespace_project_clusters_path(@project.namespace, @project), as: :cluster do |field| = form_for @cluster, html: { class: 'js-gke-cluster-creation prepend-top-20', data: { token: token_in_session } }, url: gcp_namespace_project_clusters_path(@project.namespace, @project), as: :cluster do |field|
= form_errors(@cluster) = form_errors(@cluster)
.form-group .form-group
= field.label :name, s_('ClusterIntegration|Kubernetes cluster name') = field.label :name, s_('ClusterIntegration|Kubernetes cluster name'), class: 'label-light'
= field.text_field :name, class: 'form-control', placeholder: s_('ClusterIntegration|Kubernetes cluster name') = field.text_field :name, class: 'form-control', placeholder: s_('ClusterIntegration|Kubernetes cluster name')
.form-group .form-group
= field.label :environment_scope, s_('ClusterIntegration|Environment scope') = field.label :environment_scope, s_('ClusterIntegration|Environment scope'), class: 'label-light'
= field.text_field :environment_scope, class: 'form-control', readonly: !has_multiple_clusters?(@project), placeholder: s_('ClusterIntegration|Environment scope') = field.text_field :environment_scope, class: 'form-control', readonly: !has_multiple_clusters?(@project), placeholder: s_('ClusterIntegration|Environment scope')
= field.fields_for :provider_gcp, @cluster.provider_gcp do |provider_gcp_field| = field.fields_for :provider_gcp, @cluster.provider_gcp do |provider_gcp_field|
.form-group .form-group
= provider_gcp_field.label :gcp_project_id, s_('ClusterIntegration|Google Cloud Platform project') = provider_gcp_field.label :gcp_project_id, s_('ClusterIntegration|Google Cloud Platform project'), class: 'label-light'
.js-gcp-project-id-dropdown-entry-point{ data: { docsUrl: 'https://console.cloud.google.com/home/dashboard' } } .js-gcp-project-id-dropdown-entry-point{ data: { docsUrl: 'https://console.cloud.google.com/home/dashboard' } }
= provider_gcp_field.hidden_field :gcp_project_id = provider_gcp_field.hidden_field :gcp_project_id
.dropdown .dropdown
...@@ -26,8 +32,7 @@ ...@@ -26,8 +32,7 @@
%span.form-text.text-muted &nbsp; %span.form-text.text-muted &nbsp;
.form-group .form-group
= provider_gcp_field.label :zone, s_('ClusterIntegration|Zone') = provider_gcp_field.label :zone, s_('ClusterIntegration|Zone'), class: 'label-light'
= link_to(s_('ClusterIntegration|See zones'), 'https://cloud.google.com/compute/docs/regions-zones/regions-zones', target: '_blank', rel: 'noopener noreferrer')
.js-gcp-zone-dropdown-entry-point .js-gcp-zone-dropdown-entry-point
= provider_gcp_field.hidden_field :zone = provider_gcp_field.hidden_field :zone
.dropdown .dropdown
...@@ -35,13 +40,15 @@ ...@@ -35,13 +40,15 @@
%span.dropdown-toggle-text %span.dropdown-toggle-text
= _('Select project to choose zone') = _('Select project to choose zone')
= icon('chevron-down') = icon('chevron-down')
%p.form-text.text-muted
= s_('ClusterIntegration|Learn more about %{help_link_start}zones%{help_link_end}.').html_safe % { help_link_start: help_link_start % { url: zones_link_url }, help_link_end: help_link_end }
.form-group .form-group
= provider_gcp_field.label :num_nodes, s_('ClusterIntegration|Number of nodes') = provider_gcp_field.label :num_nodes, s_('ClusterIntegration|Number of nodes'), class: 'label-light'
= provider_gcp_field.text_field :num_nodes, class: 'form-control', placeholder: '3' = provider_gcp_field.text_field :num_nodes, class: 'form-control', placeholder: '3'
.form-group .form-group
= provider_gcp_field.label :machine_type, s_('ClusterIntegration|Machine type') = provider_gcp_field.label :machine_type, s_('ClusterIntegration|Machine type'), class: 'label-light'
.js-gcp-machine-type-dropdown-entry-point .js-gcp-machine-type-dropdown-entry-point
= provider_gcp_field.hidden_field :machine_type = provider_gcp_field.hidden_field :machine_type
.dropdown .dropdown
...@@ -49,6 +56,8 @@ ...@@ -49,6 +56,8 @@
%span.dropdown-toggle-text %span.dropdown-toggle-text
= _('Select project and zone to choose machine type') = _('Select project and zone to choose machine type')
= icon('chevron-down') = icon('chevron-down')
%p.form-text.text-muted
= s_('ClusterIntegration|Learn more about %{help_link_start_machine_type}machine types%{help_link_end} and %{help_link_start_pricing}pricing%{help_link_end}.').html_safe % { help_link_start_machine_type: help_link_start % { url: machine_type_link_url }, help_link_start_pricing: help_link_start % { url: pricing_link_url }, help_link_end: help_link_end }
.form-group .form-group
= field.submit s_('ClusterIntegration|Create Kubernetes cluster'), class: 'js-gke-cluster-creation-submit btn btn-success', disabled: true = field.submit s_('ClusterIntegration|Create Kubernetes cluster'), class: 'js-gke-cluster-creation-submit btn btn-success', disabled: true
...@@ -10,9 +10,8 @@ ...@@ -10,9 +10,8 @@
.settings-content .settings-content
- if @new_deploy_token.persisted? - if @new_deploy_token.persisted?
= render 'projects/deploy_tokens/new_deploy_token', deploy_token: @new_deploy_token = render 'projects/deploy_tokens/new_deploy_token', deploy_token: @new_deploy_token
- else %h5.prepend-top-0
%h5.prepend-top-0 = s_('DeployTokens|Add a deploy token')
= s_('DeployTokens|Add a deploy token') = render 'projects/deploy_tokens/form', project: @project, token: @new_deploy_token, presenter: @deploy_tokens
= render 'projects/deploy_tokens/form', project: @project, token: @new_deploy_token, presenter: @deploy_tokens %hr
%hr
= render 'projects/deploy_tokens/table', project: @project, active_tokens: @deploy_tokens = render 'projects/deploy_tokens/table', project: @project, active_tokens: @deploy_tokens
.created-deploy-token-container .created-deploy-token-container.info-well
%h5.prepend-top-0 .well-segment
= s_('DeployTokens|Your New Deploy Token') %h5.prepend-top-0
= s_('DeployTokens|Your New Deploy Token')
.form-group .form-group
= text_field_tag 'deploy-token-user', deploy_token.username, readonly: true, class: 'deploy-token-field form-control js-select-on-focus' .input-group
= clipboard_button(text: deploy_token.username, title: s_('DeployTokens|Copy username to clipboard'), placement: 'left') = text_field_tag 'deploy-token-user', deploy_token.username, readonly: true, class: 'deploy-token-field form-control js-select-on-focus'
%span.deploy-token-help-block.prepend-top-5.text-success= s_("DeployTokens|Use this username as a login.") .input-group-append
= clipboard_button(text: deploy_token.username, title: s_('DeployTokens|Copy username to clipboard'), placement: 'left')
%span.deploy-token-help-block.prepend-top-5.text-success= s_("DeployTokens|Use this username as a login.")
.form-group .form-group
= text_field_tag 'deploy-token', deploy_token.token, readonly: true, class: 'deploy-token-field form-control js-select-on-focus' .input-group
= clipboard_button(text: deploy_token.token, title: s_('DeployTokens|Copy deploy token to clipboard'), placement: 'left') = text_field_tag 'deploy-token', deploy_token.token, readonly: true, class: 'deploy-token-field form-control js-select-on-focus'
%span.deploy-token-help-block.prepend-top-5.text-danger= s_("DeployTokens|Use this token as a password. Make sure you save it - you won't be able to access it again.") .input-group-append
%hr = clipboard_button(text: deploy_token.token, title: s_('DeployTokens|Copy deploy token to clipboard'), placement: 'left')
%span.deploy-token-help-block.prepend-top-5.text-danger= s_("DeployTokens|Use this token as a password. Make sure you save it - you won't be able to access it again.")
- @content_class = "limit-container-width" unless fluid_layout
- @no_container = true - @no_container = true
- breadcrumb_title _("Details") - breadcrumb_title _("Details")
...@@ -6,7 +7,7 @@ ...@@ -6,7 +7,7 @@
= render "home_panel" = render "home_panel"
.project-empty-note-panel .project-empty-note-panel
%div{ class: [container_class, ("limit-container-width-sm" unless fluid_layout)] } %div{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
.prepend-top-20 .prepend-top-20
%h4 %h4
= _('The repository for this project is empty') = _('The repository for this project is empty')
...@@ -36,7 +37,7 @@ ...@@ -36,7 +37,7 @@
= render 'stat_anchor_list', anchors: @project.empty_repo_statistics_buttons = render 'stat_anchor_list', anchors: @project.empty_repo_statistics_buttons
- if can?(current_user, :push_code, @project) - if can?(current_user, :push_code, @project)
%div{ class: [container_class, ("limit-container-width-sm" unless fluid_layout)] } %div{ class: [container_class, ("limit-container-width" unless fluid_layout)] }
.prepend-top-20 .prepend-top-20
.empty_wrapper .empty_wrapper
%h3#repo-command-line-instructions.page-title-empty %h3#repo-command-line-instructions.page-title-empty
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
%button.btn.js-create-merge-request.btn-success.btn-inverted{ type: 'button', data: { action: data_action } } %button.btn.js-create-merge-request.btn-success.btn-inverted{ type: 'button', data: { action: data_action } }
= value = value
%button.btn.create-merge-request-dropdown-toggle.dropdown-toggle.btn-success.btn-inverted.js-dropdown-toggle{ type: 'button', data: { dropdown: { trigger: '#create-merge-request-dropdown' } } } %button.btn.create-merge-request-dropdown-toggle.dropdown-toggle.btn-success.btn-inverted.js-dropdown-toggle{ type: 'button', data: { dropdown: { trigger: '#create-merge-request-dropdown' }, display: 'static' } }
= icon('caret-down') = icon('caret-down')
.droplab-dropdown .droplab-dropdown
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
.mr-version-menus-container.content-block .mr-version-menus-container.content-block
Changes between Changes between
%span.dropdown.inline.mr-version-dropdown %span.dropdown.inline.mr-version-dropdown
%a.dropdown-toggle.btn.btn-default{ data: {toggle: :dropdown} } %a.dropdown-toggle.btn.btn-default{ data: { toggle: :dropdown, display: 'static' } }
%span %span
- if @merge_request_diff.latest? - if @merge_request_diff.latest?
latest version latest version
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
- if @merge_request_diff.base_commit_sha - if @merge_request_diff.base_commit_sha
and and
%span.dropdown.inline.mr-version-compare-dropdown %span.dropdown.inline.mr-version-compare-dropdown
%a.btn.btn-default.dropdown-toggle{ data: {toggle: :dropdown} } %a.btn.btn-default.dropdown-toggle{ data: { toggle: :dropdown, display: 'static' } }
- if @start_version - if @start_version
version #{version_index(@start_version)} version #{version_index(@start_version)}
- else - else
......
- @content_class = "limit-container-width limit-container-width-sm" unless fluid_layout - @content_class = "limit-container-width" unless fluid_layout
- page_title _("Edit"), @page.title.capitalize, _("Wiki") - page_title _("Edit"), @page.title.capitalize, _("Wiki")
= wiki_page_errors(@error) = wiki_page_errors(@error)
......
- @content_class = "limit-container-width limit-container-width-sm" unless fluid_layout - @content_class = "limit-container-width" unless fluid_layout
- page_title s_("WikiClone|Git Access"), _("Wiki") - page_title s_("WikiClone|Git Access"), _("Wiki")
.wiki-page-header.has-sidebar-toggle .wiki-page-header.has-sidebar-toggle
......
- @content_class = "limit-container-width limit-container-width-sm" unless fluid_layout - @content_class = "limit-container-width" unless fluid_layout
- breadcrumb_title @page.title.capitalize - breadcrumb_title @page.title.capitalize
- wiki_breadcrumb_dropdown_links(@page.slug) - wiki_breadcrumb_dropdown_links(@page.slug)
- page_title @page.title.capitalize, _("Wiki") - page_title @page.title.capitalize, _("Wiki")
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
%span %span
= default_clone_protocol.upcase = default_clone_protocol.upcase
= icon('caret-down') = icon('caret-down')
%ul.dropdown-menu.dropdown-menu-selectable.dropdown-menu-right.clone-options-dropdown %ul.dropdown-menu.dropdown-menu-selectable.clone-options-dropdown
%li %li
= ssh_clone_button(project) = ssh_clone_button(project)
%li %li
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
None None
%a{ href: "#", %a{ href: "#",
"v-for" => "label in issue.labels" } "v-for" => "label in issue.labels" }
%span.badge.color-label.has-tooltip{ ":style" => "{ backgroundColor: label.color, color: label.textColor }" } .badge.color-label.has-tooltip{ ":style" => "{ backgroundColor: label.color, color: label.textColor }" }
{{ label.title }} {{ label.title }}
- if can_admin_issue? - if can_admin_issue?
.selectbox .selectbox
......
- project = @target_project || @project - project = @target_project || @project
- extra_class = extra_class || '' - extra_class = extra_class || ''
- show_menu_above = show_menu_above || false - show_menu_above = show_menu_above || false
- selected = local_assigns.fetch(:selected, nil)
- selected_text = selected.try(:title) || params[:milestone_title] - selected_text = selected.try(:title) || params[:milestone_title]
- dropdown_title = local_assigns.fetch(:dropdown_title, "Filter by milestone") - dropdown_title = local_assigns.fetch(:dropdown_title, "Filter by milestone")
- if selected.present? || params[:milestone_title].present? - if selected.present? || params[:milestone_title].present?
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
- data[:multi_select] = true - data[:multi_select] = true
- data['dropdown-title'] = title - data['dropdown-title'] = title
- data['dropdown-header'] = dropdown_options[:data][:'dropdown-header'] - data['dropdown-header'] = dropdown_options[:data][:'dropdown-header']
- data['max-select'] = dropdown_options[:data][:'max-select'] - data['max-select'] = dropdown_options[:data][:'max-select'] if dropdown_options[:data][:'max-select']
- options[:data].merge!(data) - options[:data].merge!(data)
= dropdown_tag(title, options: options) = dropdown_tag(title, options: options)
...@@ -25,7 +25,10 @@ ...@@ -25,7 +25,10 @@
= form.hidden_field :label_ids, multiple: true, value: '' = form.hidden_field :label_ids, multiple: true, value: ''
.col-sm-10{ class: "#{"col-md-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" } .col-sm-10{ class: "#{"col-md-8" if has_due_date} #{'issuable-form-padding-top' if !has_labels}" }
.issuable-form-select-holder .issuable-form-select-holder
= render "shared/issuable/label_dropdown", classes: ["js-issuable-form-dropdown"], selected: issuable.labels, data_options: { field_name: "#{issuable.class.model_name.param_key}[label_ids][]", show_any: false}, dropdown_title: "Select label" = render "shared/issuable/label_dropdown", classes: ["js-issuable-form-dropdown"], selected: issuable.labels, data_options: { field_name: "#{issuable.class.model_name.param_key}[label_ids][]", show_any: false }, dropdown_title: "Select label"
= render_if_exists "shared/issuable/form/weight", issuable: issuable, form: form
- if has_due_date - if has_due_date
.col-lg-6 .col-lg-6
.form-group.row .form-group.row
......
...@@ -6,14 +6,14 @@ ...@@ -6,14 +6,14 @@
.js-notification-toggle-btns .js-notification-toggle-btns
%div{ class: ("btn-group" if notification_setting.custom?) } %div{ class: ("btn-group" if notification_setting.custom?) }
- if notification_setting.custom? - if notification_setting.custom?
%button.dropdown-new.btn.btn-default.has-tooltip.notifications-btn#notifications-button{ type: "button", title: "Notification setting", "aria-label" => "Notification setting: #{notification_title(notification_setting.level)}", data: { container: "body", toggle: "modal", target: "#" + notifications_menu_identifier("modal", notification_setting) } } %button.dropdown-new.btn.btn-default.has-tooltip.notifications-btn#notifications-button{ type: "button", title: "Notification setting", "aria-label" => "Notification setting: #{notification_title(notification_setting.level)}", data: { container: "body", toggle: "modal", target: "#" + notifications_menu_identifier("modal", notification_setting), display: 'static' } }
= icon("bell", class: "js-notification-loading") = icon("bell", class: "js-notification-loading")
= notification_title(notification_setting.level) = notification_title(notification_setting.level)
%button.btn.dropdown-toggle{ data: { toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting) } } %button.btn.dropdown-toggle{ data: { toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting) } }
= icon('caret-down') = icon('caret-down')
.sr-only Toggle dropdown .sr-only Toggle dropdown
- else - else
%button.dropdown-new.btn.btn-default.has-tooltip.notifications-btn#notifications-button{ type: "button", title: "Notification setting", "aria-label" => "Notification setting: #{notification_title(notification_setting.level)}", data: { container: "body", toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting) } } %button.dropdown-new.btn.btn-default.has-tooltip.notifications-btn#notifications-button{ type: "button", title: "Notification setting", "aria-label" => "Notification setting: #{notification_title(notification_setting.level)}", data: { container: "body", toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting), display: 'static' } }
= icon("bell", class: "js-notification-loading") = icon("bell", class: "js-notification-loading")
= notification_title(notification_setting.level) = notification_title(notification_setting.level)
= icon("caret-down") = icon("caret-down")
......
---
title: Add machine type and pricing documentation links, add class to labels to make
bold
merge_request:
author:
type: changed
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