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:
body: 1
## Destructuring: https://eslint.org/docs/rules/prefer-destructuring
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
rouge (~> 3.1)
sanitize (~> 4.6.4)
stringex (~> 2.6)
gitlab-gollum-rugged_adapter (0.4.4)
gitlab-gollum-rugged_adapter (0.4.4.1)
mime-types (>= 1.15)
rugged (~> 0.25)
gitlab-grit (2.8.2)
......
......@@ -70,7 +70,7 @@ export default class BlobViewer {
const initialViewer = this.$fileHolder[0].querySelector('.blob-viewer:not(.hidden)');
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';
}
......
/* eslint-disable comma-dangle, space-before-function-paren, one-var */
import $ from 'jquery';
import Sortable from 'sortablejs';
import Vue from 'vue';
import AccessorUtilities from '../../lib/utils/accessor';
......@@ -57,40 +56,6 @@ gl.issueBoards.Board = Vue.extend({
});
},
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 () {
......
......@@ -17,7 +17,7 @@ gl.issueBoards.BoardDelete = Vue.extend({
deleteBoard () {
$(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();
}
}
......
......@@ -145,6 +145,6 @@ gl.issueBoards.BoardsStore = {
return filteredList[0];
},
updateFiltersUrl () {
history.pushState(null, null, `?${this.filter.path}`);
window.history.pushState(null, null, `?${this.filter.path}`);
}
};
......@@ -45,7 +45,7 @@ export default class CommitsList {
this.content.fadeTo('fast', 1.0);
// Change url so if user reload a page - search results are saved
history.replaceState({
window.history.replaceState({
page: commitsUrl,
}, document.title, commitsUrl);
})
......
......@@ -98,7 +98,7 @@ export default {
},
disableKey(deployKey, callback) {
// 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
.disableKey(deployKey.id)
.then(this.fetchKeys)
......
......@@ -40,7 +40,7 @@
methods: {
onClick() {
// 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.$el).tooltip('dispose');
......
......@@ -34,6 +34,10 @@ export default {
type: String,
required: true,
},
actionBtnIcon: {
type: String,
required: true,
},
itemActionComponent: {
type: String,
required: true,
......@@ -53,26 +57,21 @@ export default {
required: true,
},
},
data() {
return {
showActionButton: false,
};
},
computed: {
titleText() {
return sprintf(__('%{title} changes'), {
title: this.title,
});
},
filesLength() {
return this.fileList.length;
},
},
methods: {
...mapActions(['stageAllChanges', 'unstageAllChanges']),
actionBtnClicked() {
this[this.action]();
},
setShowActionButton(show) {
this.showActionButton = show;
},
},
};
</script>
......@@ -83,8 +82,6 @@ export default {
>
<header
class="multi-file-commit-panel-header"
@mouseenter="setShowActionButton(true)"
@mouseleave="setShowActionButton(false)"
>
<div
class="multi-file-commit-panel-header-title"
......@@ -95,24 +92,40 @@ export default {
:size="18"
/>
{{ titleText }}
<span
v-show="!showActionButton"
class="ide-commit-file-count"
>
{{ fileList.length }}
</span>
<button
v-show="showActionButton"
type="button"
class="btn btn-blank btn-link ide-staged-action-btn"
@click="actionBtnClicked"
>
{{ actionBtnText }}
</button>
<div class="d-flex ml-auto">
<button
v-tooltip
v-show="filesLength"
:class="{
'd-flex': filesLength
}"
:title="actionBtnText"
type="button"
class="btn btn-default ide-staged-action-btn p-0 order-1 align-items-center"
data-placement="bottom"
data-container="body"
data-boundary="viewport"
@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>
</header>
<ul
v-if="fileList.length"
v-if="filesLength"
class="multi-file-commit-list list-unstyled append-bottom-0"
>
<li
......
<script>
import { mapActions } from 'vuex';
import tooltip from '~/vue_shared/directives/tooltip';
import Icon from '~/vue_shared/components/icon.vue';
import StageButton from './stage_button.vue';
import UnstageButton from './unstage_button.vue';
......@@ -11,6 +12,9 @@ export default {
StageButton,
UnstageButton,
},
directives: {
tooltip,
},
props: {
file: {
type: Object,
......@@ -50,6 +54,9 @@ export default {
isActive() {
return this.activeFileKey === this.fullKey;
},
tooltipTitle() {
return this.file.path === this.file.name ? '' : this.file.path;
},
},
methods: {
...mapActions([
......@@ -81,29 +88,30 @@ export default {
</script>
<template>
<div
:class="{
'is-active': isActive
}"
class="multi-file-commit-list-item"
>
<div class="multi-file-commit-list-item position-relative">
<button
v-tooltip
:title="tooltipTitle"
:class="{
'is-active': isActive
}"
type="button"
class="multi-file-commit-list-path"
class="multi-file-commit-list-path w-100 border-0 ml-0 mr-0"
@dblclick="fileAction"
@click="openFileInEditor"
>
<span class="multi-file-commit-list-file-path">
<span class="multi-file-commit-list-file-path d-flex align-items-center">
<icon
:name="iconName"
:size="16"
:css-classes="iconClass"
/>{{ file.path }}
/>{{ file.name }}
</span>
</button>
<component
:is="actionComponent"
:path="file.path"
class="d-flex position-absolute"
/>
</div>
</template>
......@@ -25,15 +25,17 @@ export default {
<template>
<div
v-once
class="multi-file-discard-btn"
class="multi-file-discard-btn dropdown"
>
<button
v-tooltip
:aria-label="__('Stage changes')"
:title="__('Stage changes')"
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-boundary="viewport"
data-placement="bottom"
@click.stop="stageChange(path)"
>
<icon
......@@ -43,17 +45,31 @@ export default {
</button>
<button
v-tooltip
:aria-label="__('Discard changes')"
:title="__('Discard changes')"
:title="__('More actions')"
type="button"
class="btn btn-blank"
class="btn btn-blank d-flex align-items-center"
data-container="body"
@click.stop="discardFileChanges(path)"
data-boundary="viewport"
data-placement="bottom"
data-toggle="dropdown"
data-display="static"
>
<icon
:size="12"
name="remove"
name="more"
/>
</button>
<div class="dropdown-menu dropdown-menu-right">
<ul>
<li>
<button
type="button"
@click.stop="discardFileChanges(path)"
>
{{ __('Discard changes') }}
</button>
</li>
</ul>
</div>
</div>
</template>
......@@ -32,8 +32,10 @@ export default {
:aria-label="__('Unstage changes')"
:title="__('Unstage changes')"
type="button"
class="btn btn-blank"
class="btn btn-blank d-flex align-items-center"
data-container="body"
data-boundary="viewport"
data-placement="bottom"
@click="unstageChange(path)"
>
<icon
......
......@@ -93,23 +93,25 @@ export default {
:title="__('Unstaged')"
:key-prefix="$options.stageKeys.unstaged"
:file-list="changedFiles"
:action-btn-text="__('Stage all')"
:action-btn-text="__('Stage all changes')"
:active-file-key="activeFileKey"
class="is-first"
icon-name="unstaged"
action="stageAllChanges"
action-btn-icon="mobile-issue-close"
item-action-component="stage-button"
class="is-first"
icon-name="unstaged"
/>
<commit-files-list
:title="__('Staged')"
:key-prefix="$options.stageKeys.staged"
:file-list="stagedFiles"
:action-btn-text="__('Unstage all')"
:action-btn-text="__('Unstage all changes')"
:staged-list="true"
:active-file-key="activeFileKey"
icon-name="staged"
action="unstageAllChanges"
action-btn-icon="history"
item-action-component="unstage-button"
icon-name="staged"
/>
</template>
<empty-state
......
import { computeDiff } from './diff';
// eslint-disable-next-line no-restricted-globals
self.addEventListener('message', (e) => {
const data = e.data;
// eslint-disable-next-line no-restricted-globals
self.postMessage({
path: data.path,
changes: computeDiff(data.originalContent, data.newContent),
......
......@@ -12,5 +12,6 @@ export const defaultEditorOptions = {
export default [
{
readOnly: model => !!model.file.file_lock,
quickSuggestions: model => !(model.language === 'markdown'),
},
];
import { viewerInformationForPath } from '~/vue_shared/components/content_viewer/lib/viewer_utils';
import { decorateData, sortTree } from '../utils';
// eslint-disable-next-line no-restricted-globals
self.addEventListener('message', e => {
const { data, projectId, branchId, tempFile = false, content = '', base64 = false } = e.data;
......@@ -89,6 +90,7 @@ self.addEventListener('message', e => {
return acc;
}, {});
// eslint-disable-next-line no-restricted-globals
self.postMessage({
entries,
treeList: sortTree(treeList),
......
......@@ -226,7 +226,7 @@
.then(res => res.data)
.then(data => this.checkForSpam(data))
.then((data) => {
if (location.pathname !== data.web_url) {
if (window.location.pathname !== data.web_url) {
visitUrl(data.web_url);
}
......
......@@ -38,7 +38,7 @@
},
deleteIssuable() {
// 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;
eventHub.$emit('delete.issuable');
......
......@@ -2,7 +2,7 @@
export default {
computed: {
currentPath() {
return location.pathname;
return window.location.pathname;
},
},
};
......
......@@ -44,8 +44,8 @@ export default class LazyLoader {
requestAnimationFrame(() => this.checkElementsInView());
}
checkElementsInView() {
const scrollTop = pageYOffset;
const visHeight = scrollTop + innerHeight + SCROLL_THRESHOLD;
const scrollTop = window.pageYOffset;
const visHeight = scrollTop + window.innerHeight + SCROLL_THRESHOLD;
// Loading Images which are in the current viewport or close to them
this.lazyImages = this.lazyImages.filter((selectedImage) => {
......
......@@ -93,7 +93,7 @@ export default class LinkedTabs {
const newState = `${copySource}${this.currentLocation.search}${this.currentLocation.hash}`;
history.replaceState({
window.history.replaceState({
url: newState,
}, document.title, newState);
return newState;
......
......@@ -197,7 +197,10 @@ export const insertText = (target, text) => {
// eslint-disable-next-line no-param-reassign
target.value = newText;
// 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
target.dispatchEvent(new Event('input'));
......
......@@ -12,7 +12,7 @@ export function formatRelevantDigits(number) {
let digitsLeft = '';
let relevantDigits = 0;
let formattedNumber = '';
if (!isNaN(Number(number))) {
if (!Number.isNaN(Number(number))) {
digitsLeft = number.toString().split('.')[0];
switch (digitsLeft.length) {
case 1:
......
......@@ -35,7 +35,7 @@ const LineHighlighter = function(options = {}) {
options.highlightLineClass = options.highlightLineClass || 'hll';
options.fileHolderSelector = options.fileHolderSelector || '.file-holder';
options.scrollFileHolder = options.scrollFileHolder || false;
options.hash = options.hash || location.hash;
options.hash = options.hash || window.location.hash;
this.options = options;
this._hash = options.hash;
......@@ -145,6 +145,8 @@ LineHighlighter.prototype.highlightRange = function(range) {
var i, lineNumber, ref, ref1, results;
if (range[1]) {
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)) {
results.push(this.highlightLine(lineNumber));
}
......@@ -170,7 +172,7 @@ LineHighlighter.prototype.setHash = function(firstLineNumber, lastLineNumber) {
//
// This method is stubbed in tests.
LineHighlighter.prototype.__setLocationHash__ = function(value) {
return history.pushState({
return window.history.pushState({
url: value
// We're using pushState instead of assigning location.hash directly to
// prevent the page from scrolling on the hashchange event
......
......@@ -18,13 +18,13 @@ export default class Milestone {
return $('a[data-toggle="tab"]').on('show.bs.tab', (e) => {
const $target = $(e.target);
location.hash = $target.attr('href');
window.location.hash = $target.attr('href');
this.loadTab($target);
});
}
// eslint-disable-next-line class-methods-use-this
loadInitialTab() {
const $target = $(`.js-milestone-tabs a[href="${location.hash}"]`);
const $target = $(`.js-milestone-tabs a[href="${window.location.hash}"]`);
if ($target.length) {
$target.tab('show');
......
......@@ -16,10 +16,10 @@ export default class MilestoneSelect {
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);
if (!els) {
......@@ -224,7 +224,6 @@ export default class MilestoneSelect {
$selectBox.hide();
$value.css('display', '');
if (data.milestone != null) {
data.milestone.full_path = this.currentProject.full_path;
data.milestone.remaining = timeFor(data.milestone.due_date);
data.milestone.name = data.milestone.title;
$value.html(milestoneLinkTemplate(data.milestone));
......
......@@ -139,7 +139,7 @@ export default {
this.updateAspectRatio = true;
},
toggleAspectRatio() {
this.updatedAspectRatios = this.updatedAspectRatios += 1;
this.updatedAspectRatios += 1;
if (this.store.getMetricsCount() === this.updatedAspectRatios) {
this.updateAspectRatio = !this.updateAspectRatio;
this.updatedAspectRatios = 0;
......
......@@ -154,7 +154,7 @@ export default {
point.x = e.clientX;
point.y = e.clientY;
point = point.matrixTransform(this.$refs.graphData.getScreenCTM().inverse());
point.x = point.x += 7;
point.x += 7;
const firstTimeSeries = this.timeSeries[0];
const timeValueOverlay = firstTimeSeries.timeSeriesScaleX.invert(point.x);
const overlayIndex = bisectDate(firstTimeSeries.values, timeValueOverlay, 1);
......
......@@ -97,7 +97,7 @@ export default {
? this.deploymentFlagData.seriesIndex
: indexFromCoordinates;
const value = series.values[index] && series.values[index].value;
if (isNaN(value)) {
if (Number.isNaN(value)) {
return '-';
}
return `${formatRelevantDigits(value)}${this.unitOfDisplay}`;
......
......@@ -73,7 +73,7 @@ function queryTimeSeries(query, graphWidth, graphHeight, graphHeightOffset, xDom
timeSeriesScaleX.ticks(d3.timeMinute, 60);
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
.line()
......
......@@ -112,6 +112,8 @@ export default (function() {
fill: "#444"
});
ref = this.days;
// eslint-disable-next-line no-multi-assign
for (mm = j = 0, len = ref.length; j < len; mm = (j += 1)) {
day = ref[mm];
if (cuday !== day[0] || cumonth !== day[1]) {
......@@ -285,6 +287,8 @@ export default (function() {
r = this.r;
ref = commit.parents;
results = [];
// eslint-disable-next-line no-multi-assign
for (i = j = 0, len = ref.length; j < len; i = (j += 1)) {
parent = ref[i];
parentCommit = this.preparedCommits[parent[0]];
......
......@@ -315,7 +315,7 @@ export default class Notes {
if (discussionNoteForm.length) {
if ($textarea.val() !== '') {
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;
}
......@@ -329,7 +329,7 @@ export default class Notes {
newText = $textarea.val();
if (originalText !== newText) {
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;
}
......
......@@ -152,7 +152,7 @@ export default {
const msg = 'Are you sure you want to cancel creating this comment?';
// eslint-disable-next-line no-alert
if (!confirm(msg)) {
if (!window.confirm(msg)) {
return;
}
}
......
......@@ -77,7 +77,7 @@ export default {
},
deleteHandler() {
// 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.deleteNote(this.note)
......@@ -129,7 +129,7 @@ export default {
formCancelHandler(shouldConfirm, isDirty) {
if (shouldConfirm && isDirty) {
// 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;
}
this.$refs.noteBody.resetAutoSave();
......
......@@ -36,7 +36,9 @@ export default (function() {
var author_graph, author_header;
author_header = _this.create_author_header(d);
$(".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();
};
})(this));
......
......@@ -111,10 +111,15 @@ export default {
parse_log_entry: function(log_entry, field, date_range) {
var parsed_entry;
parsed_entry = {};
parsed_entry.author_name = log_entry.author_name;
parsed_entry.author_email = log_entry.author_email;
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) {
return function(value, key) {
if (_this.in_range(value.date, date_range)) {
......
......@@ -187,7 +187,7 @@ export default class UserTabs {
let newState = source;
newState = newState.replace(/\/+$/, '');
newState += this.windowLocation.search + this.windowLocation.hash;
history.replaceState(
window.history.replaceState(
{
url: newState,
},
......
......@@ -91,6 +91,7 @@ export default {
class="js-ci-action btn btn-blank
btn-transparent ci-action-icon-container ci-action-icon-wrapper"
data-container="body"
data-boundary="viewport"
@click="onClickAction"
>
<icon :name="actionIcon"/>
......
......@@ -87,6 +87,7 @@ export default {
data-toggle="dropdown"
data-container="body"
data-boundary="viewport"
data-display="static"
class="dropdown-menu-toggle build-content"
>
......
......@@ -165,6 +165,7 @@ export default {
class="mini-pipeline-graph-dropdown-toggle js-builds-dropdown-button"
data-placement="top"
data-toggle="dropdown"
data-display="static"
type="button"
aria-haspopup="true"
aria-expanded="false"
......
......@@ -139,6 +139,8 @@ import _ from 'underscore';
var array, binary, i, k, len, v;
binary = atob(dataURL.split(',')[1]);
array = [];
// eslint-disable-next-line no-multi-assign
for (k = i = 0, len = binary.length; i < len; k = (i += 1)) {
v = binary[k];
array.push(binary.charCodeAt(k));
......
......@@ -91,6 +91,8 @@ export default class ProjectFindFile {
var blobItemUrl, filePath, html, i, j, len, matches, results;
this.element.find(".tree-table > tbody").empty();
results = [];
// eslint-disable-next-line no-multi-assign
for (i = j = 0, len = filePaths.length; j < len; i = (j += 1)) {
filePath = filePaths[i];
if (i === 20) {
......@@ -150,7 +152,7 @@ export default class ProjectFindFile {
}
goToTree() {
return location.href = this.options.treeUrl;
return window.location.href = this.options.treeUrl;
}
goToBlob() {
......
......@@ -2,7 +2,7 @@ import { visitUrl } from './lib/utils/url_utility';
export default function projectImport() {
setTimeout(() => {
visitUrl(location.href);
visitUrl(window.location.href);
}, 5000);
}
......@@ -107,7 +107,7 @@ export default class PrometheusMetrics {
if (data && data.success) {
stop(data);
} else {
this.backOffRequestCounter = this.backOffRequestCounter += 1;
this.backOffRequestCounter += 1;
if (this.backOffRequestCounter < 3) {
next();
} else {
......
......@@ -438,7 +438,7 @@ export default class SearchAutocomplete {
}
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 (!this.badgePresent) {
if (item.category === 'Projects') {
......
......@@ -42,8 +42,8 @@ export default function initSettingsPanels() {
}
});
if (location.hash) {
const $target = $(location.hash);
if (window.location.hash) {
const $target = $(window.location.hash);
if ($target.length && $target.hasClass('settings')) {
expandSection($target);
}
......
......@@ -13,8 +13,8 @@ export default class ShortcutsFindFile extends ShortcutsNavigation {
element === this.projectFindFile.inputElement[0] &&
(combo === 'up' || combo === 'down' || combo === 'esc' || combo === 'enter')
) {
// when press up/down key in textbox, cusor prevent to move to home/end
event.preventDefault();
// when press up/down key in textbox, cursor prevent to move to home/end
e.preventDefault();
return false;
}
......
......@@ -54,7 +54,7 @@ export default {
updateConfidentialAttribute(confidential) {
this.service
.update('issue', { confidential })
.then(() => location.reload())
.then(() => window.location.reload())
.catch(() => {
Flash(
__(
......
......@@ -76,7 +76,7 @@ export default {
.update(this.issuableType, {
discussion_locked: locked,
})
.then(() => location.reload())
.then(() => window.location.reload())
.catch(() =>
Flash(
this.__(
......
......@@ -80,7 +80,7 @@ export default class SidebarMediator {
return this.service.moveIssue(this.store.moveToProjectId)
.then(response => response.json())
.then((data) => {
if (location.pathname !== data.web_url) {
if (window.location.pathname !== data.web_url) {
visitUrl(data.web_url);
}
});
......
export default () => {
const { protocol, host, pathname } = location;
const { protocol, host, pathname } = window.location;
const shareBtn = document.querySelector('.js-share-btn');
const embedBtn = document.querySelector('.js-embed-btn');
const snippetUrlArea = document.querySelector('.js-snippet-url-area');
......
......@@ -259,6 +259,7 @@ function UsersSelect(currentUser, els, options = {}) {
showDivider = 0;
if (firstUser) {
// 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)) {
obj = users[index];
if (obj.username === firstUser) {
......@@ -561,6 +562,8 @@ function UsersSelect(currentUser, els, options = {}) {
if (firstUser) {
// Move current user to the front of the list
ref = data.results;
// eslint-disable-next-line no-multi-assign
for (index = j = 0, len = ref.length; j < len; index = (j += 1)) {
obj = ref[index];
if (obj.username === firstUser) {
......
......@@ -105,7 +105,7 @@ export default {
MRWidgetService.fetchMetrics(this.metricsUrl)
.then((res) => {
if (res.status === statusCodes.NO_CONTENT) {
this.backOffRequestCounter = this.backOffRequestCounter += 1;
this.backOffRequestCounter += 1;
/* eslint-disable no-unused-expressions */
this.backOffRequestCounter < 3 ? next() : stop(res);
} else {
......
......@@ -128,11 +128,6 @@ table {
border-spacing: 0;
}
.tooltip {
// Fix bootstrap4 bug whereby tooltips flicker when they are hovered over their borders
pointer-events: none;
}
.popover {
font-size: 14px;
}
......@@ -213,6 +208,15 @@ table {
&:not(:last-of-type) {
border-bottom: 1px solid $well-inner-border;
}
p,
ol,
ul,
.form-group {
&:last-of-type {
margin-bottom: 0;
}
}
}
.badge.badge-gray {
......@@ -264,15 +268,36 @@ pre code {
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 {
background-color: $red-500;
border-color: $red-500;
}
.alert-success,
.alert-info,
.alert-warning,
.alert-danger,
.flash-notice {
border-radius: 0;
color: $white-light;
h4,
......
......@@ -54,10 +54,6 @@ body {
&.limit-container-width {
max-width: $limited-layout-width;
}
&.limit-container-width-sm {
max-width: $limited-layout-width-sm;
}
}
.alert-wrapper {
......
......@@ -347,7 +347,7 @@
.empty-state .project-item-select-holder.btn-group {
float: none;
display: inline-block;
justify-content: center;
.btn {
// overrides styles applied to plain `.empty-state .btn`
......
......@@ -244,10 +244,11 @@ $tooltip-font-size: 12px;
/*
* Padding
*/
$gl-padding-24: 24px;
$gl-padding: 16px;
$gl-padding-8: 8px;
$gl-padding-4: 4px;
$gl-padding-8: 8px;
$gl-padding: 16px;
$gl-padding-24: 24px;
$gl-padding-32: 32px;
$gl-col-padding: 15px;
$gl-input-padding: 10px;
$gl-vert-padding: 6px;
......@@ -265,7 +266,6 @@ $header-height: 40px;
$ide-statusbar-height: 25px;
$fixed-layout-width: 1280px;
$limited-layout-width: 990px;
$limited-layout-width-sm: 790px;
$container-text-max-width: 540px;
$gl-avatar-size: 40px;
$error-exclamation-point: $red-500;
......@@ -834,3 +834,4 @@ $font-family-sans-serif: $regular_font;
$font-family-monospace: $monospace_font;
$input-line-height: 20px;
$btn-line-height: 20px;
$table-accent-bg: $gray-light;
......@@ -193,6 +193,10 @@
display: inline-flex;
}
.ci-status-icon svg {
vertical-align: text-bottom;
}
> .ci-status-link,
> .btn,
> .commit-sha-group {
......
......@@ -280,7 +280,7 @@
width: 150px;
flex-shrink: 0;
.label {
.badge {
overflow: hidden;
text-overflow: ellipsis;
max-width: 100%;
......
......@@ -1001,7 +1001,7 @@ button.mini-pipeline-graph-dropdown-toggle {
/**
* Center dropdown menu in mini graph
*/
&.dropdown-menu {
.dropdown &.dropdown-menu {
transform: translate(-80%, 0);
@media (min-width: map-get($grid-breakpoints, md)) {
......
......@@ -16,7 +16,7 @@
.application-theme {
label {
margin: 0 $gl-padding $gl-padding 0;
margin: 0 $gl-padding-32 $gl-padding 0;
text-align: center;
}
......@@ -24,7 +24,7 @@
font-size: 0;
height: 48px;
border-radius: 4px;
min-width: 135px;
min-width: 112px;
margin-bottom: $gl-padding-8;
&.ui-indigo {
......@@ -75,7 +75,8 @@
.syntax-theme {
label {
margin-right: 20px;
margin-right: $gl-padding-32;
margin-bottom: $gl-padding;
text-align: center;
.preview {
......@@ -84,7 +85,6 @@
img {
border-radius: 4px;
max-width: 100%;
}
}
......
......@@ -858,7 +858,6 @@ pre.light-well {
.git-clone-holder {
width: 380px;
height: 28px;
.btn-clipboard {
border: 1px solid $border-color;
......
......@@ -540,36 +540,12 @@
margin-right: -$grid-size;
min-height: 60px;
.multi-file-commit-list-item {
margin-left: 0;
margin-right: 0;
}
&.form-text.text-muted {
margin-left: 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-solid {
color: $green-500;
......@@ -599,7 +575,7 @@
}
}
.multi-file-commit-list-item,
.multi-file-commit-list-path,
.ide-file-list .file {
display: flex;
align-items: center;
......@@ -616,11 +592,9 @@
}
.multi-file-commit-list-path {
padding: 0;
background: none;
border: 0;
text-align: left;
width: 100%;
&.is-active {
background-color: $white-normal;
}
&:hover,
&:focus {
......@@ -635,7 +609,7 @@
}
.multi-file-commit-list-file-path {
@include str-truncated(100%);
@include str-truncated(calc(100% - 30px));
&:hover {
text-decoration: underline;
......@@ -646,6 +620,16 @@
}
}
.multi-file-discard-btn {
top: 4px;
right: 8px;
bottom: 4px;
svg {
top: 0;
}
}
.multi-file-commit-form {
position: relative;
background-color: $white-light;
......@@ -840,18 +824,20 @@
}
.ide-staged-action-btn {
margin-left: auto;
line-height: 22px;
width: 22px;
margin-left: -1px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
> svg {
top: 0;
}
}
.ide-commit-file-count {
min-width: 22px;
margin-left: auto;
background-color: $gray-light;
border-radius: $border-radius-default;
border: 1px solid $white-dark;
line-height: 20px;
text-align: center;
}
.ide-commit-radios {
......
......@@ -296,7 +296,8 @@
}
.btn-clipboard {
margin-left: 5px;
background-color: $white-light;
border: 1px solid $theme-gray-200;
}
.deploy-token-help-block {
......
module IssuesAction
extend ActiveSupport::Concern
include IssuableCollections
include IssuesCalendar
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def issues
......@@ -17,18 +18,9 @@ module IssuesAction
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
# rubocop:disable Gitlab/ModuleWithInstanceVariables
def issues_calendar
@issues = issuables_collection
.non_archived
.with_due_date
.limit(100)
respond_to do |format|
format.ics { response.headers['Content-Disposition'] = 'inline' }
end
render_issues_calendar(issuables_collection)
end
# rubocop:enable Gitlab/ModuleWithInstanceVariables
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
before_action :authorize_read_build!
before_action :authorize_update_build!, only: [:keep]
before_action :extract_ref_name_and_path
before_action :set_request_format, only: [:file]
before_action :validate_artifacts!
before_action :entry, only: [:file]
......@@ -101,4 +102,12 @@ class Projects::ArtifactsController < Projects::ApplicationController
render_404 unless @entry.exists?
end
def set_request_format
request.format = :html if set_request_format?
end
def set_request_format?
request.format != :json
end
end
......@@ -7,6 +7,7 @@ class Projects::BlobController < Projects::ApplicationController
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 :authorize_download_code!
......@@ -188,6 +189,18 @@ class Projects::BlobController < Projects::ApplicationController
.last_for_path(@repository, @ref, @path).sha
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
environment_params = @repository.branch_exists?(@ref) ? { ref: @ref } : { commit: @commit }
@environment = EnvironmentsFinder.new(@project, current_user, environment_params).execute.last
......
......@@ -4,6 +4,7 @@ class Projects::IssuesController < Projects::ApplicationController
include IssuableActions
include ToggleAwardEmoji
include IssuableCollections
include IssuesCalendar
include SpammableActions
prepend_before_action :authenticate_user!, only: [:new]
......@@ -40,14 +41,7 @@ class Projects::IssuesController < Projects::ApplicationController
end
def calendar
@issues = @issuables
.non_archived
.with_due_date
.limit(100)
respond_to do |format|
format.ics { response.headers['Content-Disposition'] = 'inline' }
end
render_issues_calendar(@issuables)
end
def new
......
......@@ -115,7 +115,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
end
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
rescue ActiveRecord::StaleObjectError
......
......@@ -5,4 +5,8 @@ class MergeRequestBasicEntity < IssuableSidebarEntity
expose :state
expose :source_branch_exists?, as: :source_branch_exists
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
......@@ -25,14 +25,12 @@ module Ci
valid = true
if Feature.enabled?('ci_job_request_with_tags_matcher')
# pick builds that does not have other tags than runner's one
builds = builds.matches_tag_ids(runner.tags.ids)
# pick builds that does not have other tags than runner's one
builds = builds.matches_tag_ids(runner.tags.ids)
# pick builds that have at least one tag
unless runner.run_untagged?
builds = builds.with_any_tags
end
# pick builds that have at least one tag
unless runner.run_untagged?
builds = builds.with_any_tags
end
builds.find do |build|
......
......@@ -11,7 +11,7 @@ module Projects
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])
end
......
class FaviconUploader < AttachmentUploader
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
EXTENSION_WHITELIST
end
......
......@@ -25,7 +25,7 @@
= f.label :favicon, 'Favicon', class: 'col-sm-2 col-form-label'
.col-sm-10
- 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?
%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"
......@@ -33,9 +33,9 @@
= f.hidden_field :favicon_cache
= f.file_field :favicon, class: ''
.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
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
%legend
......
- if current_user
.dropdown
%button.dropdown-toggle{ href: '#', "data-toggle" => "dropdown" }
%button.dropdown-toggle{ href: '#', "data-toggle" => "dropdown", 'data-display' => 'static' }
= icon('globe')
%span.light Visibility:
- if params[:visibility_level].present?
......
......@@ -18,7 +18,7 @@
- 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) } }
%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")
%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 } }
......
......@@ -443,8 +443,6 @@
.col-md-6
.alert.alert-success
= lorem
.alert.alert-primary
= lorem
.alert.alert-info
= lorem
.col-md-6
......
......@@ -20,7 +20,7 @@
- else
.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)}/
= hidden_field_tag :namespace_id, value: current_user.namespace_id
.form-group.col-12.col-sm-6.project-path
......
%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('angle-down', css_class: 'caret-down')
.dropdown-menu.dropdown-menu-right
......
......@@ -16,7 +16,7 @@
- else
.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)}/
= f.hidden_field :namespace_id, value: current_user.namespace_id
.form-group.project-path.col-sm-6
......
......@@ -3,7 +3,7 @@
- if !project.empty_repo? && can?(current_user, :download_code, project)
- archive_prefix = "#{project.path}-#{ref.tr('/', '-')}"
.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')
= icon("caret-down")
%span.sr-only= _('Select Archive Format')
......
......@@ -8,7 +8,7 @@
- if show_menu
.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("caret-down")
%ul.dropdown-menu.dropdown-menu-right.project-home-dropdown
......
= 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
- 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 @@
= 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-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')
.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.fields_for :provider_gcp, @cluster.provider_gcp do |provider_gcp_field|
.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' } }
= provider_gcp_field.hidden_field :gcp_project_id
.dropdown
......@@ -26,8 +32,7 @@
%span.form-text.text-muted &nbsp;
.form-group
= provider_gcp_field.label :zone, s_('ClusterIntegration|Zone')
= link_to(s_('ClusterIntegration|See zones'), 'https://cloud.google.com/compute/docs/regions-zones/regions-zones', target: '_blank', rel: 'noopener noreferrer')
= provider_gcp_field.label :zone, s_('ClusterIntegration|Zone'), class: 'label-light'
.js-gcp-zone-dropdown-entry-point
= provider_gcp_field.hidden_field :zone
.dropdown
......@@ -35,13 +40,15 @@
%span.dropdown-toggle-text
= _('Select project to choose zone')
= 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
= 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'
.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
= provider_gcp_field.hidden_field :machine_type
.dropdown
......@@ -49,6 +56,8 @@
%span.dropdown-toggle-text
= _('Select project and zone to choose machine type')
= 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
= field.submit s_('ClusterIntegration|Create Kubernetes cluster'), class: 'js-gke-cluster-creation-submit btn btn-success', disabled: true
......@@ -10,9 +10,8 @@
.settings-content
- if @new_deploy_token.persisted?
= render 'projects/deploy_tokens/new_deploy_token', deploy_token: @new_deploy_token
- else
%h5.prepend-top-0
= s_('DeployTokens|Add a deploy token')
= render 'projects/deploy_tokens/form', project: @project, token: @new_deploy_token, presenter: @deploy_tokens
%hr
%h5.prepend-top-0
= s_('DeployTokens|Add a deploy token')
= render 'projects/deploy_tokens/form', project: @project, token: @new_deploy_token, presenter: @deploy_tokens
%hr
= render 'projects/deploy_tokens/table', project: @project, active_tokens: @deploy_tokens
.created-deploy-token-container
%h5.prepend-top-0
= s_('DeployTokens|Your New Deploy Token')
.created-deploy-token-container.info-well
.well-segment
%h5.prepend-top-0
= s_('DeployTokens|Your New Deploy Token')
.form-group
= text_field_tag 'deploy-token-user', deploy_token.username, readonly: true, class: 'deploy-token-field form-control js-select-on-focus'
= 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
.input-group
= text_field_tag 'deploy-token-user', deploy_token.username, readonly: true, class: 'deploy-token-field form-control js-select-on-focus'
.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
= text_field_tag 'deploy-token', deploy_token.token, readonly: true, class: 'deploy-token-field form-control js-select-on-focus'
= 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.")
%hr
.form-group
.input-group
= text_field_tag 'deploy-token', deploy_token.token, readonly: true, class: 'deploy-token-field form-control js-select-on-focus'
.input-group-append
= 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
- breadcrumb_title _("Details")
......@@ -6,7 +7,7 @@
= render "home_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
%h4
= _('The repository for this project is empty')
......@@ -36,7 +37,7 @@
= render 'stat_anchor_list', anchors: @project.empty_repo_statistics_buttons
- 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
.empty_wrapper
%h3#repo-command-line-instructions.page-title-empty
......
......@@ -18,7 +18,7 @@
%button.btn.js-create-merge-request.btn-success.btn-inverted{ type: 'button', data: { action: data_action } }
= 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')
.droplab-dropdown
......
......@@ -3,7 +3,7 @@
.mr-version-menus-container.content-block
Changes between
%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
- if @merge_request_diff.latest?
latest version
......@@ -36,7 +36,7 @@
- if @merge_request_diff.base_commit_sha
and
%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
version #{version_index(@start_version)}
- 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")
= 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")
.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
- wiki_breadcrumb_dropdown_links(@page.slug)
- page_title @page.title.capitalize, _("Wiki")
......
......@@ -11,7 +11,7 @@
%span
= default_clone_protocol.upcase
= 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
= ssh_clone_button(project)
%li
......
......@@ -9,7 +9,7 @@
None
%a{ href: "#",
"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 }}
- if can_admin_issue?
.selectbox
......
- project = @target_project || @project
- extra_class = extra_class || ''
- show_menu_above = show_menu_above || false
- selected = local_assigns.fetch(:selected, nil)
- selected_text = selected.try(:title) || params[:milestone_title]
- dropdown_title = local_assigns.fetch(:dropdown_title, "Filter by milestone")
- if selected.present? || params[:milestone_title].present?
......
......@@ -50,7 +50,7 @@
- data[:multi_select] = true
- data['dropdown-title'] = title
- 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)
= dropdown_tag(title, options: options)
......@@ -25,7 +25,10 @@
= 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}" }
.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
.col-lg-6
.form-group.row
......
......@@ -6,14 +6,14 @@
.js-notification-toggle-btns
%div{ class: ("btn-group" 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")
= notification_title(notification_setting.level)
%button.btn.dropdown-toggle{ data: { toggle: "dropdown", target: notifications_menu_identifier("dropdown", notification_setting) } }
= icon('caret-down')
.sr-only Toggle dropdown
- 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")
= notification_title(notification_setting.level)
= 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