Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
bc89882970
commit
9c8edcd616
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable no-param-reassign, prefer-template, no-void, consistent-return */
|
||||
/* eslint-disable no-param-reassign, no-void, consistent-return */
|
||||
|
||||
import AccessorUtilities from './lib/utils/accessor';
|
||||
|
||||
|
@ -10,7 +10,7 @@ export default class Autosave {
|
|||
if (key.join != null) {
|
||||
key = key.join('/');
|
||||
}
|
||||
this.key = 'autosave/' + key;
|
||||
this.key = `autosave/${key}`;
|
||||
this.field.data('autosave', this);
|
||||
this.restore();
|
||||
this.field.on('input', () => this.save());
|
||||
|
|
|
@ -26,7 +26,7 @@ $.fn.requiresInput = function requiresInput() {
|
|||
const values = _.map($(fieldSelector, $form), field => field.value);
|
||||
|
||||
// Disable the button if any required fields are empty
|
||||
if (values.length && _.any(values, _.isEmpty)) {
|
||||
if (values.length && _.some(values, _.isEmpty)) {
|
||||
$button.disable();
|
||||
} else {
|
||||
$button.enable();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable func-names, no-var, no-else-return, consistent-return, prefer-template, one-var, no-return-assign, no-unused-expressions, no-sequences */
|
||||
/* eslint-disable func-names, no-var, no-else-return, consistent-return, one-var, no-return-assign, no-unused-expressions, no-sequences */
|
||||
|
||||
import $ from 'jquery';
|
||||
|
||||
|
@ -49,13 +49,13 @@ export default class ImageFile {
|
|||
activateViewMode(viewMode) {
|
||||
$('.view-modes-menu li', this.file)
|
||||
.removeClass('active')
|
||||
.filter('.' + viewMode)
|
||||
.filter(`.${viewMode}`)
|
||||
.addClass('active');
|
||||
return $('.view:visible:not(.' + viewMode + ')', this.file).fadeOut(
|
||||
return $(`.view:visible:not(.${viewMode})`, this.file).fadeOut(
|
||||
200,
|
||||
(function(_this) {
|
||||
return function() {
|
||||
$('.view.' + viewMode, _this.file).fadeIn(200);
|
||||
$(`.view.${viewMode}`, _this.file).fadeIn(200);
|
||||
return _this.initView(viewMode);
|
||||
};
|
||||
})(this),
|
||||
|
@ -139,8 +139,8 @@ export default class ImageFile {
|
|||
}
|
||||
});
|
||||
return _this.requestImageInfo($('img', wrap), (width, height) => {
|
||||
$('.image-info .meta-width', wrap).text(width + 'px');
|
||||
$('.image-info .meta-height', wrap).text(height + 'px');
|
||||
$('.image-info .meta-width', wrap).text(`${width}px`);
|
||||
$('.image-info .meta-height', wrap).text(`${height}px`);
|
||||
return $('.image-info', wrap).removeClass('hide');
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable func-names, no-underscore-dangle, no-var, one-var, vars-on-top, no-shadow, no-cond-assign, no-return-assign, no-else-return, camelcase, no-lonely-if, guard-for-in, no-restricted-syntax, consistent-return, prefer-template, no-param-reassign, no-loop-func */
|
||||
/* eslint-disable func-names, no-underscore-dangle, no-var, one-var, vars-on-top, no-shadow, no-cond-assign, no-return-assign, no-else-return, camelcase, no-lonely-if, guard-for-in, no-restricted-syntax, consistent-return, no-param-reassign, no-loop-func */
|
||||
|
||||
import $ from 'jquery';
|
||||
import _ from 'underscore';
|
||||
|
@ -272,7 +272,7 @@ GitLabDropdown = (function() {
|
|||
|
||||
NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-item';
|
||||
|
||||
SELECTABLE_CLASSES = '.dropdown-content li:not(' + NON_SELECTABLE_CLASSES + ', .option-hidden)';
|
||||
SELECTABLE_CLASSES = `.dropdown-content li:not(${NON_SELECTABLE_CLASSES}, .option-hidden)`;
|
||||
|
||||
CURSOR_SELECT_SCROLL_PADDING = 5;
|
||||
|
||||
|
@ -359,9 +359,9 @@ GitLabDropdown = (function() {
|
|||
instance: this,
|
||||
elements: (function(_this) {
|
||||
return function() {
|
||||
selector = '.dropdown-content li:not(' + NON_SELECTABLE_CLASSES + ')';
|
||||
selector = `.dropdown-content li:not(${NON_SELECTABLE_CLASSES})`;
|
||||
if (_this.dropdown.find('.dropdown-toggle-page').length) {
|
||||
selector = '.dropdown-page-one ' + selector;
|
||||
selector = `.dropdown-page-one ${selector}`;
|
||||
}
|
||||
return $(selector, this.instance.dropdown);
|
||||
};
|
||||
|
@ -377,7 +377,7 @@ GitLabDropdown = (function() {
|
|||
if (_this.filterInput.val() !== '') {
|
||||
selector = SELECTABLE_CLASSES;
|
||||
if (_this.dropdown.find('.dropdown-toggle-page').length) {
|
||||
selector = '.dropdown-page-one ' + selector;
|
||||
selector = `.dropdown-page-one ${selector}`;
|
||||
}
|
||||
if ($(_this.el).is('input')) {
|
||||
currentIndex = -1;
|
||||
|
@ -693,7 +693,7 @@ GitLabDropdown = (function() {
|
|||
.split('')
|
||||
.map((character, i) => {
|
||||
if (indexOf.call(occurrences, i) !== -1) {
|
||||
return '<b>' + character + '</b>';
|
||||
return `<b>${character}</b>`;
|
||||
} else {
|
||||
return character;
|
||||
}
|
||||
|
@ -738,9 +738,7 @@ GitLabDropdown = (function() {
|
|||
} else if (value != null) {
|
||||
field = this.dropdown
|
||||
.parent()
|
||||
.find(
|
||||
"input[name='" + fieldName + "'][value='" + value.toString().replace(/'/g, "\\'") + "']",
|
||||
);
|
||||
.find(`input[name='${fieldName}'][value='${value.toString().replace(/'/g, "\\'")}']`);
|
||||
}
|
||||
|
||||
if (this.options.isSelectable && !this.options.isSelectable(selectedObject, el)) {
|
||||
|
@ -766,11 +764,11 @@ GitLabDropdown = (function() {
|
|||
} else {
|
||||
isMarking = true;
|
||||
if (!this.options.multiSelect || el.hasClass('dropdown-clear-active')) {
|
||||
this.dropdown.find('.' + ACTIVE_CLASS).removeClass(ACTIVE_CLASS);
|
||||
this.dropdown.find(`.${ACTIVE_CLASS}`).removeClass(ACTIVE_CLASS);
|
||||
if (!isInput) {
|
||||
this.dropdown
|
||||
.parent()
|
||||
.find("input[name='" + fieldName + "']")
|
||||
.find(`input[name='${fieldName}']`)
|
||||
.remove();
|
||||
}
|
||||
}
|
||||
|
@ -809,7 +807,7 @@ GitLabDropdown = (function() {
|
|||
var $input;
|
||||
// Create hidden input for form
|
||||
if (single) {
|
||||
$('input[name="' + fieldName + '"]').remove();
|
||||
$(`input[name="${fieldName}"]`).remove();
|
||||
}
|
||||
|
||||
$input = $('<input>')
|
||||
|
@ -837,12 +835,12 @@ GitLabDropdown = (function() {
|
|||
var $el, selector;
|
||||
// If we pass an option index
|
||||
if (typeof index !== 'undefined') {
|
||||
selector = SELECTABLE_CLASSES + ':eq(' + index + ') a';
|
||||
selector = `${SELECTABLE_CLASSES}:eq(${index}) a`;
|
||||
} else {
|
||||
selector = '.dropdown-content .is-focused';
|
||||
}
|
||||
if (this.dropdown.find('.dropdown-toggle-page').length) {
|
||||
selector = '.dropdown-page-one ' + selector;
|
||||
selector = `.dropdown-page-one ${selector}`;
|
||||
}
|
||||
// simulate a click on the first link
|
||||
$el = $(selector, this.dropdown);
|
||||
|
@ -861,7 +859,7 @@ GitLabDropdown = (function() {
|
|||
ARROW_KEY_CODES = [38, 40];
|
||||
selector = SELECTABLE_CLASSES;
|
||||
if (this.dropdown.find('.dropdown-toggle-page').length) {
|
||||
selector = '.dropdown-page-one ' + selector;
|
||||
selector = `.dropdown-page-one ${selector}`;
|
||||
}
|
||||
return $('body').on(
|
||||
'keydown',
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable no-useless-return, func-names, no-var, no-underscore-dangle, one-var, prefer-template, no-new, consistent-return, no-shadow, no-param-reassign, vars-on-top, no-lonely-if, no-else-return, dot-notation, no-empty */
|
||||
/* eslint-disable no-useless-return, func-names, no-var, no-underscore-dangle, one-var, no-new, consistent-return, no-shadow, no-param-reassign, vars-on-top, no-lonely-if, no-else-return, dot-notation, no-empty */
|
||||
/* global Issuable */
|
||||
/* global ListLabel */
|
||||
|
||||
|
@ -70,7 +70,7 @@ export default class LabelsSelect {
|
|||
$loading = $block.find('.block-loading').fadeOut();
|
||||
fieldName = $dropdown.data('fieldName');
|
||||
initialSelected = $selectbox
|
||||
.find('input[name="' + $dropdown.data('fieldName') + '"]')
|
||||
.find(`input[name="${$dropdown.data('fieldName')}"]`)
|
||||
.map(function() {
|
||||
return this.value;
|
||||
})
|
||||
|
@ -92,7 +92,7 @@ export default class LabelsSelect {
|
|||
var data, selected;
|
||||
selected = $dropdown
|
||||
.closest('.selectbox')
|
||||
.find("input[name='" + fieldName + "']")
|
||||
.find(`input[name='${fieldName}']`)
|
||||
.map(function() {
|
||||
return this.value;
|
||||
})
|
||||
|
@ -267,11 +267,7 @@ export default class LabelsSelect {
|
|||
|
||||
if (
|
||||
$form.find(
|
||||
"input[type='hidden'][name='" +
|
||||
this.fieldName +
|
||||
"'][value='" +
|
||||
dropdownValue +
|
||||
"']",
|
||||
`input[type='hidden'][name='${this.fieldName}'][value='${dropdownValue}']`,
|
||||
).length
|
||||
) {
|
||||
selectedClass.push('is-active');
|
||||
|
@ -284,8 +280,7 @@ export default class LabelsSelect {
|
|||
}
|
||||
|
||||
if (label.color) {
|
||||
colorEl =
|
||||
"<span class='dropdown-label-box' style='background: " + label.color + "'></span>";
|
||||
colorEl = `<span class='dropdown-label-box' style='background: ${label.color}'></span>`;
|
||||
} else {
|
||||
colorEl = '';
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable func-names, no-var, no-param-reassign, one-var, operator-assignment, no-else-return, prefer-template, consistent-return */
|
||||
/* eslint-disable func-names, no-var, no-param-reassign, one-var, operator-assignment, no-else-return, consistent-return */
|
||||
import $ from 'jquery';
|
||||
import { insertText } from '~/lib/utils/common_utils';
|
||||
|
||||
|
@ -237,7 +237,7 @@ export function insertMarkdownText({
|
|||
}
|
||||
|
||||
if (removedFirstNewLine) {
|
||||
textToInsert = '\n' + textToInsert;
|
||||
textToInsert = `\n${textToInsert}`;
|
||||
}
|
||||
|
||||
if (removedLastNewLine) {
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable func-names, no-var, no-underscore-dangle, no-param-reassign, prefer-template, consistent-return, one-var, no-else-return */
|
||||
/* eslint-disable func-names, no-var, no-underscore-dangle, no-param-reassign, consistent-return, one-var, no-else-return */
|
||||
|
||||
import $ from 'jquery';
|
||||
|
||||
|
@ -106,7 +106,7 @@ LineHighlighter.prototype.clickHandler = function(event) {
|
|||
};
|
||||
|
||||
LineHighlighter.prototype.clearHighlight = function() {
|
||||
return $('.' + this.highlightLineClass).removeClass(this.highlightLineClass);
|
||||
return $(`.${this.highlightLineClass}`).removeClass(this.highlightLineClass);
|
||||
};
|
||||
|
||||
// Convert a URL hash String into line numbers
|
||||
|
@ -137,7 +137,7 @@ LineHighlighter.prototype.hashToRange = function(hash) {
|
|||
//
|
||||
// lineNumber - Line number to highlight
|
||||
LineHighlighter.prototype.highlightLine = function(lineNumber) {
|
||||
return $('#LC' + lineNumber).addClass(this.highlightLineClass);
|
||||
return $(`#LC${lineNumber}`).addClass(this.highlightLineClass);
|
||||
};
|
||||
|
||||
// Highlight all lines within a range
|
||||
|
@ -162,9 +162,9 @@ LineHighlighter.prototype.highlightRange = function(range) {
|
|||
LineHighlighter.prototype.setHash = function(firstLineNumber, lastLineNumber) {
|
||||
var hash;
|
||||
if (lastLineNumber) {
|
||||
hash = '#L' + firstLineNumber + '-' + lastLineNumber;
|
||||
hash = `#L${firstLineNumber}-${lastLineNumber}`;
|
||||
} else {
|
||||
hash = '#L' + firstLineNumber;
|
||||
hash = `#L${firstLineNumber}`;
|
||||
}
|
||||
this._hash = hash;
|
||||
return this.__setLocationHash__(hash);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable no-else-return, prefer-template */
|
||||
/* eslint-disable no-else-return */
|
||||
|
||||
import $ from 'jquery';
|
||||
import '~/gl_dropdown';
|
||||
|
@ -24,7 +24,7 @@ export default class NamespaceSelect {
|
|||
if (selected.id == null) {
|
||||
return selected.text;
|
||||
} else {
|
||||
return selected.kind + ': ' + selected.full_path;
|
||||
return `${selected.kind}: ${selected.full_path}`;
|
||||
}
|
||||
},
|
||||
data(term, dataCallback) {
|
||||
|
@ -44,7 +44,7 @@ export default class NamespaceSelect {
|
|||
if (namespace.id == null) {
|
||||
return namespace.text;
|
||||
} else {
|
||||
return namespace.kind + ': ' + namespace.full_path;
|
||||
return `${namespace.kind}: ${namespace.full_path}`;
|
||||
}
|
||||
},
|
||||
renderRow: this.renderRow,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable func-names, no-var, one-var, no-loop-func, consistent-return, prefer-template, camelcase */
|
||||
/* eslint-disable func-names, no-var, one-var, no-loop-func, consistent-return, camelcase */
|
||||
|
||||
import $ from 'jquery';
|
||||
import { __ } from '../locale';
|
||||
|
@ -223,7 +223,7 @@ export default (function() {
|
|||
shortrefs = commit.refs;
|
||||
// Truncate if longer than 15 chars
|
||||
if (shortrefs.length > 17) {
|
||||
shortrefs = shortrefs.substr(0, 15) + '…';
|
||||
shortrefs = `${shortrefs.substr(0, 15)}…`;
|
||||
}
|
||||
text = r.text(x + 4, y, shortrefs).attr({
|
||||
'text-anchor': 'start',
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable func-names, no-var, one-var, consistent-return, no-return-assign, prefer-template, no-shadow, no-else-return, @gitlab/i18n/no-non-i18n-strings */
|
||||
/* eslint-disable func-names, no-var, one-var, consistent-return, no-return-assign, no-shadow, no-else-return, @gitlab/i18n/no-non-i18n-strings */
|
||||
|
||||
import $ from 'jquery';
|
||||
import RefSelectDropdown from './ref_select_dropdown';
|
||||
|
@ -70,10 +70,10 @@ export default class NewBranchForm {
|
|||
case !/\/{2,}/g.test(value):
|
||||
return 'consecutive slashes';
|
||||
default:
|
||||
return "'" + value + "'";
|
||||
return `'${value}'`;
|
||||
}
|
||||
});
|
||||
return restriction.prefix + ' ' + formatted.join(restriction.conjunction);
|
||||
return `${restriction.prefix} ${formatted.join(restriction.conjunction)}`;
|
||||
};
|
||||
validator = (function(_this) {
|
||||
return function(errors, restriction) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* eslint-disable no-restricted-properties, func-names, no-var, camelcase,
|
||||
no-unused-expressions, one-var, default-case,
|
||||
prefer-template, consistent-return, no-alert, no-return-assign,
|
||||
consistent-return, no-alert, no-return-assign,
|
||||
no-param-reassign, no-else-return, vars-on-top,
|
||||
no-shadow, no-useless-escape, class-methods-use-this */
|
||||
|
||||
|
@ -490,7 +490,7 @@ export default class Notes {
|
|||
diffAvatarContainer = row
|
||||
.prevAll('.line_holder')
|
||||
.first()
|
||||
.find('.js-avatar-container.' + lineType + '_line');
|
||||
.find(`.js-avatar-container.${lineType}_line`);
|
||||
// is this the first note of discussion?
|
||||
discussionContainer = $(`.notes[data-discussion-id="${noteEntity.discussion_id}"]`);
|
||||
if (!discussionContainer.length) {
|
||||
|
@ -506,16 +506,14 @@ export default class Notes {
|
|||
} else {
|
||||
// Merge new discussion HTML in
|
||||
var $notes = $discussion.find(`.notes[data-discussion-id="${noteEntity.discussion_id}"]`);
|
||||
var contentContainerClass =
|
||||
'.' +
|
||||
$notes
|
||||
.closest('.notes-content')
|
||||
.attr('class')
|
||||
.split(' ')
|
||||
.join('.');
|
||||
var contentContainerClass = $notes
|
||||
.closest('.notes-content')
|
||||
.attr('class')
|
||||
.split(' ')
|
||||
.join('.');
|
||||
|
||||
row
|
||||
.find(contentContainerClass + ' .content')
|
||||
.find(`.${contentContainerClass} .content`)
|
||||
.append($notes.closest('.content').children());
|
||||
}
|
||||
} else {
|
||||
|
@ -722,7 +720,7 @@ export default class Notes {
|
|||
this.revertNoteEditForm($targetNote);
|
||||
$noteEntityEl.renderGFM();
|
||||
// Find the note's `li` element by ID and replace it with the updated HTML
|
||||
$note_li = $('.note-row-' + noteEntity.id);
|
||||
$note_li = $(`.note-row-${noteEntity.id}`);
|
||||
|
||||
$note_li.replaceWith($noteEntityEl);
|
||||
this.setupNewNote($noteEntityEl);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable func-names, no-var, one-var, camelcase, no-param-reassign, prefer-template, no-return-assign */
|
||||
/* eslint-disable func-names, no-var, one-var, camelcase, no-param-reassign, no-return-assign */
|
||||
|
||||
import $ from 'jquery';
|
||||
import _ from 'underscore';
|
||||
|
@ -66,8 +66,8 @@ export default (function() {
|
|||
class: 'person',
|
||||
style: 'display: block;',
|
||||
});
|
||||
author_name = $('<h4>' + author.author_name + '</h4>');
|
||||
author_email = $('<p class="graph-author-email">' + author.author_email + '</p>');
|
||||
author_name = $(`<h4>${author.author_name}</h4>`);
|
||||
author_email = $(`<p class="graph-author-email">${author.author_email}</p>`);
|
||||
author_commit_info_span = $('<span/>', {
|
||||
class: 'commits',
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable func-names, no-restricted-syntax, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, no-return-assign, prefer-template, no-else-return, no-shadow */
|
||||
/* eslint-disable func-names, no-restricted-syntax, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, no-return-assign, no-else-return, no-shadow */
|
||||
|
||||
import $ from 'jquery';
|
||||
import _ from 'underscore';
|
||||
|
@ -118,14 +118,11 @@ export const ContributorsGraph = (function() {
|
|||
};
|
||||
|
||||
ContributorsGraph.prototype.draw_x_axis = function() {
|
||||
return (
|
||||
this.svg
|
||||
.append('g')
|
||||
.attr('class', 'x axis')
|
||||
/* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
|
||||
.attr('transform', 'translate(0, ' + this.height + ')')
|
||||
.call(this.x_axis)
|
||||
);
|
||||
return this.svg
|
||||
.append('g')
|
||||
.attr('class', 'x axis')
|
||||
.attr('transform', `translate(0, ${this.height})`)
|
||||
.call(this.x_axis);
|
||||
};
|
||||
|
||||
ContributorsGraph.prototype.draw_y_axis = function() {
|
||||
|
@ -200,8 +197,7 @@ export const ContributorsMasterGraph = (function(superClass) {
|
|||
.attr('height', this.height + this.MARGIN.top + this.MARGIN.bottom)
|
||||
.attr('class', 'tint-box')
|
||||
.append('g')
|
||||
/* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
|
||||
.attr('transform', 'translate(' + this.MARGIN.left + ',' + this.MARGIN.top + ')');
|
||||
.attr('transform', `translate(${this.MARGIN.left},${this.MARGIN.top})`);
|
||||
return this.svg;
|
||||
};
|
||||
|
||||
|
@ -348,8 +344,7 @@ export const ContributorsAuthorGraph = (function(superClass) {
|
|||
.attr('height', this.height + this.MARGIN.top + this.MARGIN.bottom)
|
||||
.attr('class', 'spark')
|
||||
.append('g')
|
||||
/* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
|
||||
.attr('transform', 'translate(' + this.MARGIN.left + ',' + this.MARGIN.top + ')');
|
||||
.attr('transform', `translate(${this.MARGIN.left},${this.MARGIN.top})`);
|
||||
return this.svg;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable func-names, no-var, prefer-template */
|
||||
/* eslint-disable func-names, no-var */
|
||||
|
||||
import $ from 'jquery';
|
||||
import BranchGraph from '../../../network/branch_graph';
|
||||
|
@ -14,7 +14,7 @@ export default (function() {
|
|||
this.branch_graph = new BranchGraph($('.network-graph'), opts);
|
||||
vph = $(window).height() - 250;
|
||||
$('.network-graph').css({
|
||||
height: vph + 'px',
|
||||
height: `${vph}px`,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable func-names, no-var, consistent-return, one-var, no-cond-assign, prefer-template, no-return-assign */
|
||||
/* eslint-disable func-names, no-var, consistent-return, one-var, no-cond-assign, no-return-assign */
|
||||
|
||||
import $ from 'jquery';
|
||||
import fuzzaldrinPlus from 'fuzzaldrin-plus';
|
||||
|
@ -112,7 +112,7 @@ export default class ProjectFindFile {
|
|||
if (searchText) {
|
||||
matches = fuzzaldrinPlus.match(filePath, searchText);
|
||||
}
|
||||
blobItemUrl = this.options.blobUrlTemplate + '/' + encodeURIComponent(filePath);
|
||||
blobItemUrl = `${this.options.blobUrlTemplate}/${encodeURIComponent(filePath)}`;
|
||||
html = ProjectFindFile.makeHtml(filePath, matches, blobItemUrl);
|
||||
results.push(this.element.find('.tree-table > tbody').append(html));
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable func-names, no-var, consistent-return, one-var, prefer-template, no-else-return, no-param-reassign */
|
||||
/* eslint-disable func-names, no-var, consistent-return, one-var, no-else-return, no-param-reassign */
|
||||
|
||||
import $ from 'jquery';
|
||||
import _ from 'underscore';
|
||||
|
@ -247,7 +247,7 @@ Sidebar.prototype.isOpen = function() {
|
|||
};
|
||||
|
||||
Sidebar.prototype.getBlock = function(name) {
|
||||
return this.sidebar.find('.block.' + name);
|
||||
return this.sidebar.find(`.block.${name}`);
|
||||
};
|
||||
|
||||
export default Sidebar;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable no-return-assign, one-var, no-var, consistent-return, prefer-template, class-methods-use-this, no-lonely-if, vars-on-top */
|
||||
/* eslint-disable no-return-assign, one-var, no-var, consistent-return, class-methods-use-this, no-lonely-if, vars-on-top */
|
||||
|
||||
import $ from 'jquery';
|
||||
import { escape, throttle } from 'underscore';
|
||||
|
@ -416,7 +416,7 @@ export class SearchAutocomplete {
|
|||
inputs = Object.keys(this.originalState);
|
||||
for (i = 0, len = inputs.length; i < len; i += 1) {
|
||||
input = inputs[i];
|
||||
this.getElement('#' + input).val(this.originalState[input]);
|
||||
this.getElement(`#${input}`).val(this.originalState[input]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -426,7 +426,7 @@ export class SearchAutocomplete {
|
|||
results = [];
|
||||
for (i = 0, len = inputs.length; i < len; i += 1) {
|
||||
input = inputs[i];
|
||||
results.push(this.getElement('#' + input).val(''));
|
||||
results.push(this.getElement(`#${input}`).val(''));
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable func-names, one-var, no-var, prefer-rest-params, vars-on-top, consistent-return, no-shadow, no-else-return, no-self-compare, prefer-template, no-unused-expressions, yoda, prefer-spread, camelcase, no-param-reassign */
|
||||
/* eslint-disable func-names, one-var, no-var, prefer-rest-params, vars-on-top, consistent-return, no-shadow, no-else-return, no-self-compare, no-unused-expressions, yoda, prefer-spread, camelcase, no-param-reassign */
|
||||
/* global Issuable */
|
||||
/* global emitSidebarEvent */
|
||||
|
||||
|
@ -428,8 +428,7 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
const isActive = $el.hasClass('is-active');
|
||||
const previouslySelected = $dropdown
|
||||
.closest('.selectbox')
|
||||
/* eslint-disable-next-line @gitlab/i18n/no-non-i18n-strings */
|
||||
.find("input[name='" + $dropdown.data('fieldName') + "'][value!=0]");
|
||||
.find(`input[name='${$dropdown.data('fieldName')}'][value!=0]`);
|
||||
|
||||
// Enables support for limiting the number of users selected
|
||||
// Automatically removes the first on the list if more users are selected
|
||||
|
@ -448,7 +447,7 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
// Remove unassigned selection (if it was previously selected)
|
||||
const unassignedSelected = $dropdown
|
||||
.closest('.selectbox')
|
||||
.find("input[name='" + $dropdown.data('fieldName') + "'][value=0]");
|
||||
.find(`input[name='${$dropdown.data('fieldName')}'][value=0]`);
|
||||
|
||||
if (unassignedSelected) {
|
||||
unassignedSelected.remove();
|
||||
|
@ -502,7 +501,7 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
} else if (!$dropdown.hasClass('js-multiselect')) {
|
||||
selected = $dropdown
|
||||
.closest('.selectbox')
|
||||
.find("input[name='" + $dropdown.data('fieldName') + "']")
|
||||
.find(`input[name='${$dropdown.data('fieldName')}']`)
|
||||
.val();
|
||||
return assignTo(selected);
|
||||
}
|
||||
|
@ -544,7 +543,7 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
updateLabel: $dropdown.data('dropdownTitle'),
|
||||
renderRow(user) {
|
||||
var avatar, img, username;
|
||||
username = user.username ? '@' + user.username : '';
|
||||
username = user.username ? `@${user.username}` : '';
|
||||
avatar = user.avatar_url ? user.avatar_url : gon.default_avatar_url;
|
||||
|
||||
let selected = false;
|
||||
|
@ -555,7 +554,7 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
const { fieldName } = this;
|
||||
const field = $dropdown
|
||||
.closest('.selectbox')
|
||||
.find("input[name='" + fieldName + "'][value='" + user.id + "']");
|
||||
.find(`input[name='${fieldName}'][value='${user.id}']`);
|
||||
|
||||
if (field.length) {
|
||||
selected = true;
|
||||
|
@ -571,7 +570,7 @@ function UsersSelect(currentUser, els, options = {}) {
|
|||
)}</a></li>`;
|
||||
} else {
|
||||
// 0 margin, because it's now handled by a wrapper
|
||||
img = "<img src='" + avatar + "' class='avatar avatar-inline m-0' width='32' />";
|
||||
img = `<img src='${avatar}' class='avatar avatar-inline m-0' width='32' />`;
|
||||
}
|
||||
|
||||
return _this.renderRow(options.issuableType, user, selected, username, img);
|
||||
|
@ -715,7 +714,7 @@ UsersSelect.prototype.formatResult = function(user) {
|
|||
${_.escape(user.name)}
|
||||
</div>
|
||||
<div class='user-username dropdown-menu-user-username text-secondary'>
|
||||
${!user.invite ? '@' + _.escape(user.username) : ''}
|
||||
${!user.invite ? `@${_.escape(user.username)}` : ''}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Use GetBlobs RPC for uri type
|
||||
merge_request: 16824
|
||||
author:
|
||||
type: performance
|
|
@ -20,16 +20,12 @@ module Banzai
|
|||
def call
|
||||
return doc if context[:system_note]
|
||||
|
||||
@uri_types = {}
|
||||
clear_memoization(:linkable_files)
|
||||
|
||||
doc.search('a:not(.gfm)').each do |el|
|
||||
process_link_attr el.attribute('href')
|
||||
end
|
||||
load_uri_types
|
||||
|
||||
doc.css('img, video').each do |el|
|
||||
process_link_attr el.attribute('src')
|
||||
process_link_attr el.attribute('data-src')
|
||||
linkable_attributes.each do |attr|
|
||||
process_link_attr(attr)
|
||||
end
|
||||
|
||||
doc
|
||||
|
@ -37,16 +33,81 @@ module Banzai
|
|||
|
||||
protected
|
||||
|
||||
def load_uri_types
|
||||
return unless linkable_files?
|
||||
return {} unless repository
|
||||
|
||||
clear_memoization(:linkable_attributes)
|
||||
|
||||
@uri_types = request_path.present? ? get_uri_types([request_path]) : {}
|
||||
|
||||
paths = linkable_attributes.flat_map do |attr|
|
||||
[get_uri(attr).to_s, relative_file_path(get_uri(attr))]
|
||||
end
|
||||
|
||||
paths.reject!(&:blank?)
|
||||
paths.uniq!
|
||||
|
||||
@uri_types.merge!(get_uri_types(paths))
|
||||
end
|
||||
|
||||
def linkable_files?
|
||||
strong_memoize(:linkable_files) do
|
||||
context[:project_wiki].nil? && repository.try(:exists?) && !repository.empty?
|
||||
end
|
||||
end
|
||||
|
||||
def process_link_attr(html_attr)
|
||||
return if html_attr.blank?
|
||||
return if html_attr.value.start_with?('//')
|
||||
def linkable_attributes
|
||||
strong_memoize(:linkable_attributes) do
|
||||
attrs = []
|
||||
|
||||
attrs += doc.search('a:not(.gfm)').map do |el|
|
||||
el.attribute('href')
|
||||
end
|
||||
|
||||
attrs += doc.search('img, video').flat_map do |el|
|
||||
[el.attribute('src'), el.attribute('data-src')]
|
||||
end
|
||||
|
||||
attrs.reject do |attr|
|
||||
attr.blank? || attr.value.start_with?('//')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def get_uri_types(paths)
|
||||
return {} if paths.empty?
|
||||
|
||||
uri_types = Hash[paths.collect { |name| [name, nil] }]
|
||||
|
||||
get_blob_types(paths).each do |name, type|
|
||||
if type == :blob
|
||||
blob = ::Blob.decorate(Gitlab::Git::Blob.new(name: name), project)
|
||||
uri_types[name] = blob.image? || blob.video? ? :raw : :blob
|
||||
else
|
||||
uri_types[name] = type
|
||||
end
|
||||
end
|
||||
|
||||
uri_types
|
||||
end
|
||||
|
||||
def get_blob_types(paths)
|
||||
revision_paths = paths.collect do |path|
|
||||
[current_commit.sha, path.chomp("/")]
|
||||
end
|
||||
|
||||
Gitlab::GitalyClient::BlobService.new(repository).get_blob_types(revision_paths, 1)
|
||||
end
|
||||
|
||||
def get_uri(html_attr)
|
||||
uri = URI(html_attr.value)
|
||||
|
||||
uri if uri.relative? && uri.path.present?
|
||||
rescue URI::Error, Addressable::URI::InvalidURIError
|
||||
end
|
||||
|
||||
def process_link_attr(html_attr)
|
||||
if html_attr.value.start_with?('/uploads/')
|
||||
process_link_to_upload_attr(html_attr)
|
||||
elsif linkable_files? && repo_visible_to_user?
|
||||
|
@ -81,6 +142,7 @@ module Banzai
|
|||
|
||||
def process_link_to_repository_attr(html_attr)
|
||||
uri = URI(html_attr.value)
|
||||
|
||||
if uri.relative? && uri.path.present?
|
||||
html_attr.value = rebuild_relative_uri(uri).to_s
|
||||
end
|
||||
|
@ -89,7 +151,7 @@ module Banzai
|
|||
end
|
||||
|
||||
def rebuild_relative_uri(uri)
|
||||
file_path = relative_file_path(uri)
|
||||
file_path = nested_file_path_if_exists(uri)
|
||||
|
||||
uri.path = [
|
||||
relative_url_root,
|
||||
|
@ -102,13 +164,29 @@ module Banzai
|
|||
uri
|
||||
end
|
||||
|
||||
def relative_file_path(uri)
|
||||
path = Addressable::URI.unescape(uri.path).delete("\0")
|
||||
request_path = Addressable::URI.unescape(context[:requested_path])
|
||||
nested_path = build_relative_path(path, request_path)
|
||||
def nested_file_path_if_exists(uri)
|
||||
path = cleaned_file_path(uri)
|
||||
nested_path = relative_file_path(uri)
|
||||
|
||||
file_exists?(nested_path) ? nested_path : path
|
||||
end
|
||||
|
||||
def cleaned_file_path(uri)
|
||||
Addressable::URI.unescape(uri.path).delete("\0").chomp("/")
|
||||
end
|
||||
|
||||
def relative_file_path(uri)
|
||||
return if uri.nil?
|
||||
|
||||
build_relative_path(cleaned_file_path(uri), request_path)
|
||||
end
|
||||
|
||||
def request_path
|
||||
return unless context[:requested_path]
|
||||
|
||||
Addressable::URI.unescape(context[:requested_path]).chomp("/")
|
||||
end
|
||||
|
||||
# Convert a relative path into its correct location based on the currently
|
||||
# requested path
|
||||
#
|
||||
|
@ -136,6 +214,7 @@ module Banzai
|
|||
return path[1..-1] if path.start_with?('/')
|
||||
|
||||
parts = request_path.split('/')
|
||||
|
||||
parts.pop if uri_type(request_path) != :tree
|
||||
|
||||
path.sub!(%r{\A\./}, '')
|
||||
|
@ -149,14 +228,11 @@ module Banzai
|
|||
end
|
||||
|
||||
def file_exists?(path)
|
||||
path.present? && !!uri_type(path)
|
||||
path.present? && uri_type(path).present?
|
||||
end
|
||||
|
||||
def uri_type(path)
|
||||
# https://gitlab.com/gitlab-org/gitlab-foss/issues/58657
|
||||
Gitlab::GitalyClient.allow_n_plus_1_calls do
|
||||
@uri_types[path] ||= current_commit.uri_type(path)
|
||||
end
|
||||
@uri_types[path] == :unknown ? "" : @uri_types[path]
|
||||
end
|
||||
|
||||
def current_commit
|
||||
|
|
|
@ -76,6 +76,30 @@ module Gitlab
|
|||
GitalyClient::BlobsStitcher.new(response)
|
||||
end
|
||||
|
||||
def get_blob_types(revision_paths, limit = -1)
|
||||
return {} if revision_paths.empty?
|
||||
|
||||
request_revision_paths = revision_paths.map do |rev, path|
|
||||
Gitaly::GetBlobsRequest::RevisionPath.new(revision: rev, path: encode_binary(path))
|
||||
end
|
||||
|
||||
request = Gitaly::GetBlobsRequest.new(
|
||||
repository: @gitaly_repo,
|
||||
revision_paths: request_revision_paths,
|
||||
limit: limit
|
||||
)
|
||||
|
||||
response = GitalyClient.call(
|
||||
@gitaly_repo.storage_name,
|
||||
:blob_service,
|
||||
:get_blobs,
|
||||
request,
|
||||
timeout: GitalyClient.fast_timeout
|
||||
)
|
||||
|
||||
map_blob_types(response)
|
||||
end
|
||||
|
||||
def get_new_lfs_pointers(revision, limit, not_in, dynamic_timeout = nil)
|
||||
request = Gitaly::GetNewLFSPointersRequest.new(
|
||||
repository: @gitaly_repo,
|
||||
|
@ -132,6 +156,16 @@ module Gitlab
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
def map_blob_types(response)
|
||||
types = {}
|
||||
|
||||
response.each do |msg|
|
||||
types[msg.path.dup.force_encoding('utf-8')] = msg.type.downcase
|
||||
end
|
||||
|
||||
types
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -234,6 +234,12 @@ describe 'Issue Boards', :js do
|
|||
|
||||
expect(find('.board:nth-child(2)')).to have_content(development.title)
|
||||
expect(find('.board:nth-child(2)')).to have_content(planning.title)
|
||||
|
||||
# Make sure list positions are preserved after a reload
|
||||
visit project_board_path(project, board)
|
||||
|
||||
expect(find('.board:nth-child(2)')).to have_content(development.title)
|
||||
expect(find('.board:nth-child(2)')).to have_content(planning.title)
|
||||
end
|
||||
|
||||
it 'dragging does not duplicate list' do
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/* eslint-disable no-var, prefer-template, no-else-return, dot-notation, no-return-assign, no-new, no-underscore-dangle */
|
||||
/* eslint-disable no-var, no-else-return, dot-notation, no-return-assign, no-new, no-underscore-dangle */
|
||||
|
||||
import $ from 'jquery';
|
||||
import LineHighlighter from '~/line_highlighter';
|
||||
|
@ -8,10 +8,10 @@ describe('LineHighlighter', function() {
|
|||
preloadFixtures('static/line_highlighter.html');
|
||||
clickLine = function(number, eventData = {}) {
|
||||
if ($.isEmptyObject(eventData)) {
|
||||
return $('#L' + number).click();
|
||||
return $(`#L${number}`).click();
|
||||
} else {
|
||||
const e = $.Event('click', eventData);
|
||||
return $('#L' + number).trigger(e);
|
||||
return $(`#L${number}`).trigger(e);
|
||||
}
|
||||
};
|
||||
beforeEach(function() {
|
||||
|
@ -42,9 +42,9 @@ describe('LineHighlighter', function() {
|
|||
var line;
|
||||
new LineHighlighter({ hash: '#L5-25' });
|
||||
|
||||
expect($('.' + this.css).length).toBe(21);
|
||||
expect($(`.${this.css}`).length).toBe(21);
|
||||
for (line = 5; line <= 25; line += 1) {
|
||||
expect($('#LC' + line)).toHaveClass(this.css);
|
||||
expect($(`#LC${line}`)).toHaveClass(this.css);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -130,7 +130,7 @@ describe('LineHighlighter', function() {
|
|||
});
|
||||
|
||||
expect($('#LC13')).toHaveClass(this.css);
|
||||
expect($('.' + this.css).length).toBe(1);
|
||||
expect($(`.${this.css}`).length).toBe(1);
|
||||
});
|
||||
|
||||
it('sets the hash', function() {
|
||||
|
@ -152,9 +152,9 @@ describe('LineHighlighter', function() {
|
|||
shiftKey: true,
|
||||
});
|
||||
|
||||
expect($('.' + this.css).length).toBe(6);
|
||||
expect($(`.${this.css}`).length).toBe(6);
|
||||
for (line = 15; line <= 20; line += 1) {
|
||||
expect($('#LC' + line)).toHaveClass(this.css);
|
||||
expect($(`#LC${line}`)).toHaveClass(this.css);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -165,9 +165,9 @@ describe('LineHighlighter', function() {
|
|||
shiftKey: true,
|
||||
});
|
||||
|
||||
expect($('.' + this.css).length).toBe(6);
|
||||
expect($(`.${this.css}`).length).toBe(6);
|
||||
for (line = 5; line <= 10; line += 1) {
|
||||
expect($('#LC' + line)).toHaveClass(this.css);
|
||||
expect($(`#LC${line}`)).toHaveClass(this.css);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
@ -188,9 +188,9 @@ describe('LineHighlighter', function() {
|
|||
shiftKey: true,
|
||||
});
|
||||
|
||||
expect($('.' + this.css).length).toBe(6);
|
||||
expect($(`.${this.css}`).length).toBe(6);
|
||||
for (line = 5; line <= 10; line += 1) {
|
||||
expect($('#LC' + line)).toHaveClass(this.css);
|
||||
expect($(`#LC${line}`)).toHaveClass(this.css);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -200,9 +200,9 @@ describe('LineHighlighter', function() {
|
|||
shiftKey: true,
|
||||
});
|
||||
|
||||
expect($('.' + this.css).length).toBe(6);
|
||||
expect($(`.${this.css}`).length).toBe(6);
|
||||
for (line = 10; line <= 15; line += 1) {
|
||||
expect($('#LC' + line)).toHaveClass(this.css);
|
||||
expect($(`#LC${line}`)).toHaveClass(this.css);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,6 +3,9 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe Banzai::Filter::RelativeLinkFilter do
|
||||
include GitHelpers
|
||||
include RepoHelpers
|
||||
|
||||
def filter(doc, contexts = {})
|
||||
contexts.reverse_merge!({
|
||||
commit: commit,
|
||||
|
@ -34,6 +37,12 @@ describe Banzai::Filter::RelativeLinkFilter do
|
|||
%(<div>#{element}</div>)
|
||||
end
|
||||
|
||||
def allow_gitaly_n_plus_1
|
||||
Gitlab::GitalyClient.allow_n_plus_1_calls do
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
let(:project) { create(:project, :repository, :public) }
|
||||
let(:user) { create(:user) }
|
||||
let(:group) { nil }
|
||||
|
@ -44,6 +53,19 @@ describe Banzai::Filter::RelativeLinkFilter do
|
|||
let(:requested_path) { '/' }
|
||||
let(:only_path) { true }
|
||||
|
||||
it 'does not trigger a gitaly n+1', :request_store do
|
||||
raw_doc = ""
|
||||
|
||||
allow_gitaly_n_plus_1 do
|
||||
30.times do |i|
|
||||
create_file_in_repo(project, ref, ref, "new_file_#{i}", "x" )
|
||||
raw_doc += link("new_file_#{i}")
|
||||
end
|
||||
end
|
||||
|
||||
expect { filter(raw_doc) }.to change { Gitlab::GitalyClient.get_request_count }.by(2)
|
||||
end
|
||||
|
||||
shared_examples :preserve_unchanged do
|
||||
it 'does not modify any relative URL in anchor' do
|
||||
doc = filter(link('README.md'))
|
||||
|
@ -244,7 +266,8 @@ describe Banzai::Filter::RelativeLinkFilter do
|
|||
end
|
||||
|
||||
context 'when ref name contains special chars' do
|
||||
let(:ref) {'mark#\'@],+;-._/#@!$&()+down'}
|
||||
let(:ref) { 'mark#\'@],+;-._/#@!$&()+down' }
|
||||
let(:path) { 'files/images/logo-black.png' }
|
||||
|
||||
it 'correctly escapes the ref' do
|
||||
# Addressable won't escape the '#', so we do this manually
|
||||
|
@ -252,8 +275,9 @@ describe Banzai::Filter::RelativeLinkFilter do
|
|||
|
||||
# Stub this method so the branch doesn't actually need to be in the repo
|
||||
allow_any_instance_of(described_class).to receive(:uri_type).and_return(:raw)
|
||||
allow_any_instance_of(described_class).to receive(:get_uri_types).and_return({ path: :tree })
|
||||
|
||||
doc = filter(link('files/images/logo-black.png'))
|
||||
doc = filter(link(path))
|
||||
|
||||
expect(doc.at_css('a')['href'])
|
||||
.to eq "/#{project_path}/raw/#{ref_escaped}/files/images/logo-black.png"
|
||||
|
|
Loading…
Reference in New Issue