Merge branch 'master' into sh-headless-chrome-support

* master: (104 commits)
  Update licenses
  fix a wrong method call in the refactor
  fix a whitespace
  fix for discussion
  Update templates via:
  Update doc accordingly to:
  Cache issuable template names
  Fix the format of rugged alternate directory list
  Match full file path in FileDetector
  Fixes from CSS refactor
  Resolve "Prometheus service page shows error"
  Explicit state integration deletion
  Move all API authentication code to APIGuard
  Shorten example translation for inclusive language
  [ci-skip] add changelog
  fix the merger override to remove source branch
  add spec
  Removed d3.js  from the users and graphs bundle
  Cleanup data-page attribute after each Karma test
  Update template description wording
  ...
This commit is contained in:
Mike Greiling 2017-10-12 17:52:09 -05:00
commit 53e11239ce
No known key found for this signature in database
GPG Key ID: 0303DF507FA67596
313 changed files with 4807 additions and 3425 deletions

View File

@ -296,9 +296,9 @@ might be edited to make them small and simple.
Please submit Feature Proposals using the ['Feature Proposal' issue template](.gitlab/issue_templates/Feature Proposal.md) provided on the issue tracker.
For changes in the interface, it is helpful to include a mockup. Issues that add to, or change, the interface should
be given the ~"UX" label. This will allow the UX team to provide input and guidance. You may
need to ask one of the [core team] members to add the label, if you do not have permissions to do it by yourself.
For changes in the interface, it is helpful to include a mockup. Issues that add to, or change, the interface should
be given the ~"UX" label. This will allow the UX team to provide input and guidance. You may
need to ask one of the [core team] members to add the label, if you do not have permissions to do it by yourself.
If you want to create something yourself, consider opening an issue first to
discuss whether it is interesting to include this in GitLab.
@ -658,7 +658,7 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[license-finder-doc]: doc/development/licensing.md
[GitLab Inc engineering workflow]: https://about.gitlab.com/handbook/engineering/workflow/#labelling-issues
[polling-etag]: https://docs.gitlab.com/ce/development/polling.html
[testing]: doc/development/testing.md
[testing]: doc/development/testing_guide/index.md
[^1]: Please note that specs other than JavaScript specs are considered backend
code.

View File

@ -1 +1 @@
0.43.0
0.46.0

View File

@ -1,2 +1 @@
5.9.3
5.9.4

View File

@ -398,7 +398,7 @@ group :ed25519 do
end
# Gitaly GRPC client
gem 'gitaly-proto', '~> 0.39.0', require: 'gitaly'
gem 'gitaly-proto', '~> 0.41.0', require: 'gitaly'
gem 'toml-rb', '~> 0.3.15', require: false

View File

@ -274,7 +274,7 @@ GEM
po_to_json (>= 1.0.0)
rails (>= 3.2.0)
gherkin-ruby (0.3.2)
gitaly-proto (0.39.0)
gitaly-proto (0.41.0)
google-protobuf (~> 3.1)
grpc (~> 1.0)
github-linguist (4.7.6)
@ -1023,7 +1023,7 @@ DEPENDENCIES
gettext (~> 3.2.2)
gettext_i18n_rails (~> 1.8.0)
gettext_i18n_rails_js (~> 1.2.0)
gitaly-proto (~> 0.39.0)
gitaly-proto (~> 0.41.0)
github-linguist (~> 4.7.0)
gitlab-flowdock-git-hook (~> 1.0.1)
gitlab-markup (~> 1.6.2)

View File

@ -1,4 +1,4 @@
## GitLab Core Team & GitLab Inc. Contribution Process
## GitLab core team & GitLab Inc. contribution process
---

View File

@ -1,8 +1,8 @@
/* eslint-disable class-methods-use-this */
/* global Flash */
import _ from 'underscore';
import Cookies from 'js-cookie';
import { isInIssuePage, updateTooltipTitle } from './lib/utils/common_utils';
import Flash from './flash';
const animationEndEventString = 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd';
const transitionEndEventString = 'transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd';

View File

@ -1,9 +1,8 @@
/* global Flash */
import Flash from '../flash';
import BalsamiqViewer from './balsamiq/balsamiq_viewer';
function onError() {
const flash = new window.Flash('Balsamiq file could not be loaded.');
const flash = new Flash('Balsamiq file could not be loaded.');
return flash;
}

View File

@ -1,6 +1,5 @@
/* eslint-disable class-methods-use-this */
/* global Flash */
import Flash from '../flash';
import FileTemplateTypeSelector from './template_selectors/type_selector';
import BlobCiYamlSelector from './template_selectors/ci_yaml_selector';
import DockerfileSelector from './template_selectors/dockerfile_selector';

View File

@ -1,4 +1,4 @@
/* global Flash */
import Flash from '../../flash';
import { handleLocationHash } from '../../lib/utils/common_utils';
export default class BlobViewer {

View File

@ -1,10 +1,10 @@
/* eslint-disable one-var, quote-props, comma-dangle, space-before-function-paren */
/* global BoardService */
/* global Flash */
import _ from 'underscore';
import Vue from 'vue';
import VueResource from 'vue-resource';
import Flash from '../flash';
import FilteredSearchBoards from './filtered_search_boards';
import eventHub from './eventhub';
import './models/issue';

View File

@ -3,9 +3,9 @@
/* global MilestoneSelect */
/* global LabelsSelect */
/* global Sidebar */
/* global Flash */
import Vue from 'vue';
import Flash from '../../flash';
import eventHub from '../../sidebar/event_hub';
import AssigneeTitle from '../../sidebar/components/assignees/assignee_title';
import Assignees from '../../sidebar/components/assignees/assignees';

View File

@ -1,7 +1,7 @@
/* eslint-disable no-new */
/* global Flash */
import Vue from 'vue';
import Flash from '../../../flash';
import './lists_dropdown';
const ModalStore = gl.issueBoards.ModalStore;

View File

@ -1,7 +1,7 @@
/* eslint-disable no-new */
/* global Flash */
import Vue from 'vue';
import Flash from '../../../flash';
const Store = gl.issueBoards.BoardsStore;

View File

@ -1,30 +1,30 @@
/* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, no-unused-vars, no-return-assign, max-len */
/* eslint-disable func-names, prefer-arrow-callback, no-return-assign */
import { visitUrl } from './lib/utils/url_utility';
import { convertPermissionToBoolean } from './lib/utils/common_utils';
window.BuildArtifacts = (function() {
function BuildArtifacts() {
export default class BuildArtifacts {
constructor() {
this.disablePropagation();
this.setupEntryClick();
this.setupTooltips();
}
BuildArtifacts.prototype.disablePropagation = function() {
$('.top-block').on('click', '.download', function(e) {
// eslint-disable-next-line class-methods-use-this
disablePropagation() {
$('.top-block').on('click', '.download', function (e) {
return e.stopPropagation();
});
return $('.tree-holder').on('click', 'tr[data-link] a', function(e) {
return $('.tree-holder').on('click', 'tr[data-link] a', function (e) {
return e.stopImmediatePropagation();
});
};
BuildArtifacts.prototype.setupEntryClick = function() {
return $('.tree-holder').on('click', 'tr[data-link]', function(e) {
}
// eslint-disable-next-line class-methods-use-this
setupEntryClick() {
return $('.tree-holder').on('click', 'tr[data-link]', function () {
visitUrl(this.dataset.link, convertPermissionToBoolean(this.dataset.externalLink));
});
};
BuildArtifacts.prototype.setupTooltips = function() {
}
// eslint-disable-next-line class-methods-use-this
setupTooltips() {
$('.js-artifact-tree-tooltip').tooltip({
placement: 'bottom',
// Stop the tooltip from hiding when we stop hovering the element directly
@ -41,7 +41,5 @@ window.BuildArtifacts = (function() {
.on('mouseleave', (e) => {
$(e.currentTarget).find('.js-artifact-tree-tooltip').tooltip('hide');
});
};
return BuildArtifacts;
})();
}
}

View File

@ -1,8 +1,10 @@
/* eslint-disable func-names, prefer-arrow-callback, space-before-function-paren */
/* eslint-disable func-names*/
$(function() {
$('.reveal-variables').off('click').on('click', function() {
$('.js-build-variables').toggle();
$(this).hide();
});
});
export default function handleRevealVariables() {
$('.js-reveal-variables')
.off('click')
.on('click', function () {
$('.js-build-variables').toggle();
$(this).hide();
});
}

View File

@ -1,7 +1,4 @@
window.gl = window.gl || {};
class CILintEditor {
export default class CILintEditor {
constructor() {
this.editor = window.ace.edit('ci-editor');
this.textarea = document.querySelector('#content');
@ -13,5 +10,3 @@ class CILintEditor {
});
}
}
gl.CILintEditor = CILintEditor;

View File

@ -1,5 +1,5 @@
/* eslint-disable no-new */
/* global Flash */
import Flash from './flash';
import DropLab from './droplab/drop_lab';
import ISetter from './droplab/plugins/input_setter';

View File

@ -1,7 +1,6 @@
/* global Flash */
import Vue from 'vue';
import Cookies from 'js-cookie';
import Flash from '../flash';
import Translate from '../vue_shared/translate';
import banner from './components/banner.vue';
import stageCodeComponent from './components/stage_code_component.vue';

View File

@ -1,5 +1,5 @@
<script>
/* global Flash */
import Flash from '../../flash';
import eventHub from '../eventhub';
import DeployKeysService from '../service';
import DeployKeysStore from '../store';

View File

@ -1,9 +1,9 @@
/* eslint-disable comma-dangle, object-shorthand, func-names, quote-props, no-else-return, camelcase, max-len */
/* global CommentsStore */
/* global ResolveService */
/* global Flash */
import Vue from 'vue';
import Flash from '../../flash';
const ResolveBtn = Vue.extend({
props: {

View File

@ -1,7 +1,7 @@
/* global Flash */
/* global CommentsStore */
import Vue from 'vue';
import Flash from '../../flash';
import '../../vue_shared/vue_resource_interceptor';
window.gl = window.gl || {};

View File

@ -12,7 +12,8 @@
/* global NotificationsDropdown */
/* global GroupAvatar */
/* global LineHighlighter */
/* global BuildArtifacts */
import BuildArtifacts from './build_artifacts';
import CILintEditor from './ci_lint_editor';
/* global GroupsSelect */
/* global Search */
/* global Admin */
@ -28,7 +29,8 @@
/* global ProjectNew */
/* global ProjectShow */
/* global ProjectImport */
/* global Labels */
import Labels from './labels';
import LabelManager from './label_manager';
/* global Shortcuts */
/* global ShortcutsFindFile */
/* global Sidebar */
@ -78,6 +80,9 @@ import initChangesDropdown from './init_changes_dropdown';
import AbuseReports from './abuse_reports';
import { ajaxGet, convertPermissionToBoolean } from './lib/utils/common_utils';
import AjaxLoadingSpinner from './ajax_loading_spinner';
import GlFieldErrors from './gl_field_errors';
import GLForm from './gl_form';
import U2FAuthenticate from './u2f/authenticate';
(function() {
var Dispatcher;
@ -90,8 +95,8 @@ import AjaxLoadingSpinner from './ajax_loading_spinner';
}
Dispatcher.prototype.initPageScripts = function() {
var page, path, shortcut_handler, fileBlobPermalinkUrlElement, fileBlobPermalinkUrl;
page = $('body').attr('data-page');
var path, shortcut_handler, fileBlobPermalinkUrlElement, fileBlobPermalinkUrl;
const page = $('body').attr('data-page');
if (!page) {
return false;
}
@ -228,7 +233,7 @@ import AjaxLoadingSpinner from './ajax_loading_spinner';
case 'groups:milestones:update':
new ZenMode();
new gl.DueDateSelectors();
new gl.GLForm($('.milestone-form'), true);
new GLForm($('.milestone-form'), true);
break;
case 'projects:compare:show':
new gl.Diff();
@ -245,7 +250,7 @@ import AjaxLoadingSpinner from './ajax_loading_spinner';
case 'projects:issues:new':
case 'projects:issues:edit':
shortcut_handler = new ShortcutsNavigation();
new gl.GLForm($('.issue-form'), true);
new GLForm($('.issue-form'), true);
new IssuableForm($('.issue-form'));
new LabelsSelect();
new MilestoneSelect();
@ -269,7 +274,7 @@ import AjaxLoadingSpinner from './ajax_loading_spinner';
case 'projects:merge_requests:edit':
new gl.Diff();
shortcut_handler = new ShortcutsNavigation();
new gl.GLForm($('.merge-request-form'), true);
new GLForm($('.merge-request-form'), true);
new IssuableForm($('.merge-request-form'));
new LabelsSelect();
new MilestoneSelect();
@ -278,7 +283,7 @@ import AjaxLoadingSpinner from './ajax_loading_spinner';
break;
case 'projects:tags:new':
new ZenMode();
new gl.GLForm($('.tag-form'), true);
new GLForm($('.tag-form'), true);
new RefSelectDropdown($('.js-branch-select'));
break;
case 'projects:snippets:show':
@ -288,17 +293,17 @@ import AjaxLoadingSpinner from './ajax_loading_spinner';
case 'projects:snippets:edit':
case 'projects:snippets:create':
case 'projects:snippets:update':
new gl.GLForm($('.snippet-form'), true);
new GLForm($('.snippet-form'), true);
break;
case 'snippets:new':
case 'snippets:edit':
case 'snippets:create':
case 'snippets:update':
new gl.GLForm($('.snippet-form'), false);
new GLForm($('.snippet-form'), false);
break;
case 'projects:releases:edit':
new ZenMode();
new gl.GLForm($('.release-form'), true);
new GLForm($('.release-form'), true);
break;
case 'projects:merge_requests:show':
new gl.Diff();
@ -457,7 +462,7 @@ import AjaxLoadingSpinner from './ajax_loading_spinner';
case 'groups:labels:index':
case 'projects:labels:index':
if ($('.prioritized-labels').length) {
new gl.LabelManager();
new LabelManager();
}
$('.label-subscription').each((i, el) => {
const $el = $(el);
@ -505,7 +510,7 @@ import AjaxLoadingSpinner from './ajax_loading_spinner';
break;
case 'ci:lints:create':
case 'ci:lints:show':
new gl.CILintEditor();
new CILintEditor();
break;
case 'users:show':
new UserCallout();
@ -535,14 +540,16 @@ import AjaxLoadingSpinner from './ajax_loading_spinner';
case 'sessions':
case 'omniauth_callbacks':
if (!gon.u2f) break;
gl.u2fAuthenticate = new gl.U2FAuthenticate(
const u2fAuthenticate = new U2FAuthenticate(
$('#js-authenticate-u2f'),
'#js-login-u2f-form',
gon.u2f,
document.querySelector('#js-login-2fa-device'),
document.querySelector('.js-2fa-form'),
);
gl.u2fAuthenticate.start();
u2fAuthenticate.start();
// needed in rspec
gl.u2fAuthenticate = u2fAuthenticate;
case 'admin':
new Admin();
switch (path[1]) {
@ -602,7 +609,7 @@ import AjaxLoadingSpinner from './ajax_loading_spinner';
new Wikis();
shortcut_handler = new ShortcutsWiki();
new ZenMode();
new gl.GLForm($('.wiki-form'), true);
new GLForm($('.wiki-form'), true);
break;
case 'snippets':
shortcut_handler = new ShortcutsNavigation();
@ -627,12 +634,6 @@ import AjaxLoadingSpinner from './ajax_loading_spinner';
shortcut_handler = new ShortcutsNavigation();
}
break;
case 'users':
const action = path[1];
import(/* webpackChunkName: 'user_profile' */ './users')
.then(user => user.default(action))
.catch(() => {});
break;
}
// If we haven't installed a custom shortcut handler, install the default one
if (!shortcut_handler) {
@ -653,7 +654,7 @@ import AjaxLoadingSpinner from './ajax_loading_spinner';
Dispatcher.prototype.initFieldErrors = function() {
$('.gl-show-field-errors').each((i, form) => {
new gl.GlFieldErrors(form);
new GlFieldErrors(form);
});
};

View File

@ -237,9 +237,12 @@ window.DropzoneInput = (function() {
};
const insertToTextArea = function(filename, url) {
return $(child).val(function(index, val) {
const $child = $(child);
$child.val(function(index, val) {
return val.replace(`{{${filename}}}`, url);
});
$child.trigger('change');
};
const appendToTextArea = function(url) {

View File

@ -1,6 +1,6 @@
<script>
/* global Flash */
import Visibility from 'visibilityjs';
import Flash from '../../flash';
import EnvironmentsService from '../services/environments_service';
import environmentTable from './environments_table.vue';
import EnvironmentsStore from '../stores/environments_store';

View File

@ -1,6 +1,6 @@
<script>
/* global Flash */
import Visibility from 'visibilityjs';
import Flash from '../../flash';
import EnvironmentsService from '../services/environments_service';
import environmentTable from '../components/environments_table.vue';
import EnvironmentsStore from '../stores/environments_store';

View File

@ -1,7 +1,6 @@
/* global Flash */
import Ajax from '~/droplab/plugins/ajax';
import Filter from '~/droplab/plugins/filter';
import Flash from '../flash';
import Ajax from '../droplab/plugins/ajax';
import Filter from '../droplab/plugins/filter';
import './filtered_search_dropdown';
class DropdownEmoji extends gl.FilteredSearchDropdown {

View File

@ -1,7 +1,6 @@
/* global Flash */
import Ajax from '~/droplab/plugins/ajax';
import Filter from '~/droplab/plugins/filter';
import Flash from '../flash';
import Ajax from '../droplab/plugins/ajax';
import Filter from '../droplab/plugins/filter';
import './filtered_search_dropdown';
class DropdownNonUser extends gl.FilteredSearchDropdown {

View File

@ -1,6 +1,5 @@
/* global Flash */
import AjaxFilter from '~/droplab/plugins/ajax_filter';
import Flash from '../flash';
import AjaxFilter from '../droplab/plugins/ajax_filter';
import './filtered_search_dropdown';
import { addClassIfElementExists } from '../lib/utils/dom_utils';

View File

@ -1,3 +1,4 @@
import Flash from '../flash';
import FilteredSearchContainer from './container';
import RecentSearchesRoot from './recent_searches_root';
import RecentSearchesStore from './stores/recent_searches_store';
@ -36,7 +37,7 @@ class FilteredSearchManager {
.catch((error) => {
if (error.name === 'RecentSearchesServiceError') return undefined;
// eslint-disable-next-line no-new
new window.Flash('An error occurred while parsing recent searches');
new Flash('An error occurred while parsing recent searches');
// Gracefully fail to empty array
return [];
})

View File

@ -1,5 +1,5 @@
import AjaxCache from '../lib/utils/ajax_cache';
import '../flash'; /* global Flash */
import Flash from '../flash';
import FilteredSearchContainer from './container';
import UsersCache from '../lib/utils/users_cache';

View File

@ -1,71 +1,94 @@
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, one-var-declaration-per-line, no-param-reassign, quotes, quote-props, prefer-template, comma-dangle, max-len */
import _ from 'underscore';
window.Flash = (function() {
var hideFlash;
hideFlash = function() {
return $(this).fadeOut();
};
/**
* Flash banner supports different types of Flash configurations
* along with ability to provide actionConfig which can be used to show
* additional action or link on banner next to message
*
* @param {String} message Flash message
* @param {String} type Type of Flash, it can be `notice` or `alert` (default)
* @param {Object} parent Reference to Parent element under which Flash needs to appear
* @param {Object} actionConfig Map of config to show action on banner
* @param {String} href URL to which action link should point (default '#')
* @param {String} title Title of action
* @param {Function} clickHandler Method to call when action is clicked on
*/
function Flash(message, type, parent, actionConfig) {
var flash, textDiv, actionLink;
if (type == null) {
type = 'alert';
}
if (parent == null) {
parent = null;
}
if (parent) {
this.flashContainer = parent.find('.flash-container');
} else {
this.flashContainer = $('.flash-container-page');
}
this.flashContainer.html('');
flash = $('<div/>', {
"class": "flash-" + type
const hideFlash = (flashEl, fadeTransition = true) => {
if (fadeTransition) {
Object.assign(flashEl.style, {
transition: 'opacity .3s',
opacity: '0',
});
flash.on('click', hideFlash);
textDiv = $('<div/>', {
"class": 'flash-text',
text: message
});
textDiv.appendTo(flash);
if (actionConfig) {
const actionLinkConfig = {
class: 'flash-action',
href: actionConfig.href || '#',
text: actionConfig.title
};
if (!actionConfig.href) {
actionLinkConfig.role = 'button';
}
actionLink = $('<a/>', actionLinkConfig);
actionLink.appendTo(flash);
this.flashContainer.on('click', '.flash-action', actionConfig.clickHandler);
}
if (this.flashContainer.parent().hasClass('content-wrapper')) {
textDiv.addClass('container-fluid container-limited');
}
flash.appendTo(this.flashContainer);
this.flashContainer.show();
}
return Flash;
})();
flashEl.addEventListener('transitionend', () => {
flashEl.remove();
}, {
once: true,
passive: true,
});
if (!fadeTransition) flashEl.dispatchEvent(new Event('transitionend'));
};
const createAction = config => `
<a
href="${config.href || '#'}"
class="flash-action"
${config.href ? '' : 'role="button"'}
>
${_.escape(config.title)}
</a>
`;
const createFlashEl = (message, type, isInContentWrapper = false) => `
<div
class="flash-${type}"
>
<div
class="flash-text ${isInContentWrapper ? 'container-fluid container-limited' : ''}"
>
${_.escape(message)}
</div>
</div>
`;
/*
* Flash banner supports different types of Flash configurations
* along with ability to provide actionConfig which can be used to show
* additional action or link on banner next to message
*
* @param {String} message Flash message text
* @param {String} type Type of Flash, it can be `notice` or `alert` (default)
* @param {Object} parent Reference to parent element under which Flash needs to appear
* @param {Object} actonConfig Map of config to show action on banner
* @param {String} href URL to which action config should point to (default: '#')
* @param {String} title Title of action
* @param {Function} clickHandler Method to call when action is clicked on
* @param {Boolean} fadeTransition Boolean to determine whether to fade the alert out
*/
const createFlash = function createFlash(
message,
type = 'alert',
parent = document,
actionConfig = null,
fadeTransition = true,
) {
const flashContainer = parent.querySelector('.flash-container');
if (!flashContainer) return null;
const isInContentWrapper = flashContainer.parentNode.classList.contains('content-wrapper');
flashContainer.innerHTML = createFlashEl(message, type, isInContentWrapper);
const flashEl = flashContainer.querySelector(`.flash-${type}`);
flashEl.addEventListener('click', () => hideFlash(flashEl, fadeTransition));
if (actionConfig) {
flashEl.innerHTML += createAction(actionConfig);
if (actionConfig.clickHandler) {
flashEl.querySelector('.flash-action').addEventListener('click', e => actionConfig.clickHandler(e));
}
}
flashContainer.style.display = 'block';
return flashContainer;
};
export {
createFlash as default,
createFlashEl,
createAction,
hideFlash,
};
window.Flash = createFlash;

View File

@ -54,7 +54,7 @@ const inputErrorClass = 'gl-field-error-outline';
const errorAnchorSelector = '.gl-field-error-anchor';
const ignoreInputSelector = '.gl-field-error-ignore';
class GlFieldError {
export default class GlFieldError {
constructor({ input, formErrors }) {
this.inputElement = $(input);
this.inputDomElement = this.inputElement.get(0);
@ -159,6 +159,3 @@ class GlFieldError {
this.fieldErrorElement.hide();
}
}
window.gl = window.gl || {};
window.gl.GlFieldError = GlFieldError;

View File

@ -1,42 +1,40 @@
/* eslint-disable comma-dangle, class-methods-use-this, max-len, space-before-function-paren, arrow-parens, no-param-reassign */
import './gl_field_error';
import GlFieldError from './gl_field_error';
const customValidationFlag = 'gl-field-error-ignore';
class GlFieldErrors {
export default class GlFieldErrors {
constructor(form) {
this.form = $(form);
this.state = {
inputs: [],
valid: false
valid: false,
};
this.initValidators();
}
initValidators () {
initValidators() {
// register selectors here as needed
const validateSelectors = [':text', ':password', '[type=email]']
.map((selector) => `input${selector}`).join(',');
.map(selector => `input${selector}`).join(',');
this.state.inputs = this.form.find(validateSelectors).toArray()
.filter((input) => !input.classList.contains(customValidationFlag))
.map((input) => new window.gl.GlFieldError({ input, formErrors: this }));
.filter(input => !input.classList.contains(customValidationFlag))
.map(input => new GlFieldError({ input, formErrors: this }));
this.form.on('submit', this.catchInvalidFormSubmit);
this.form.on('submit', GlFieldErrors.catchInvalidFormSubmit);
}
/* Neccessary to prevent intercept and override invalid form submit
* because Safari & iOS quietly allow form submission when form is invalid
* and prevents disabling of invalid submit button by application.js */
catchInvalidFormSubmit (event) {
const $form = $(event.currentTarget);
static catchInvalidFormSubmit(e) {
const $form = $(e.currentTarget);
if (!$form.attr('novalidate')) {
if (!event.currentTarget.checkValidity()) {
event.preventDefault();
event.stopPropagation();
if (!e.currentTarget.checkValidity()) {
e.preventDefault();
e.stopPropagation();
}
}
}
@ -50,11 +48,9 @@ class GlFieldErrors {
});
}
focusOnFirstInvalid () {
const firstInvalid = this.state.inputs.filter((input) => !input.inputDomElement.validity.valid)[0];
focusOnFirstInvalid() {
const firstInvalid = this.state.inputs
.filter(input => !input.inputDomElement.validity.valid)[0];
firstInvalid.inputElement.focus();
}
}
window.gl = window.gl || {};
window.gl.GlFieldErrors = GlFieldErrors;

View File

@ -1,104 +1,99 @@
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-new, max-len */
/* global GitLab */
/* global DropzoneInput */
/* global autosize */
import GfmAutoComplete from './gfm_auto_complete';
window.gl = window.gl || {};
function GLForm(form, enableGFM = false) {
this.form = form;
this.textarea = this.form.find('textarea.js-gfm-input');
this.enableGFM = enableGFM;
// Before we start, we should clean up any previous data for this form
this.destroy();
// Setup the form
this.setupForm();
this.form.data('gl-form', this);
}
GLForm.prototype.destroy = function() {
// Clean form listeners
this.clearEventListeners();
if (this.autoComplete) {
this.autoComplete.destroy();
export default class GLForm {
constructor(form, enableGFM = false) {
this.form = form;
this.textarea = this.form.find('textarea.js-gfm-input');
this.enableGFM = enableGFM;
// Before we start, we should clean up any previous data for this form
this.destroy();
// Setup the form
this.setupForm();
this.form.data('gl-form', this);
}
return this.form.data('gl-form', null);
};
GLForm.prototype.setupForm = function() {
var isNewForm;
isNewForm = this.form.is(':not(.gfm-form)');
this.form.removeClass('js-new-note-form');
if (isNewForm) {
this.form.find('.div-dropzone').remove();
this.form.addClass('gfm-form');
// remove notify commit author checkbox for non-commit notes
gl.utils.disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button, .js-note-new-discussion'));
this.autoComplete = new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources);
this.autoComplete.setup(this.form.find('.js-gfm-input'), {
emojis: true,
members: this.enableGFM,
issues: this.enableGFM,
milestones: this.enableGFM,
mergeRequests: this.enableGFM,
labels: this.enableGFM,
destroy() {
// Clean form listeners
this.clearEventListeners();
if (this.autoComplete) {
this.autoComplete.destroy();
}
this.form.data('gl-form', null);
}
setupForm() {
const isNewForm = this.form.is(':not(.gfm-form)');
this.form.removeClass('js-new-note-form');
if (isNewForm) {
this.form.find('.div-dropzone').remove();
this.form.addClass('gfm-form');
// remove notify commit author checkbox for non-commit notes
gl.utils.disableButtonIfEmptyField(this.form.find('.js-note-text'), this.form.find('.js-comment-button, .js-note-new-discussion'));
this.autoComplete = new GfmAutoComplete(gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources);
this.autoComplete.setup(this.form.find('.js-gfm-input'), {
emojis: true,
members: this.enableGFM,
issues: this.enableGFM,
milestones: this.enableGFM,
mergeRequests: this.enableGFM,
labels: this.enableGFM,
});
new DropzoneInput(this.form); // eslint-disable-line no-new
autosize(this.textarea);
}
// form and textarea event listeners
this.addEventListeners();
gl.text.init(this.form);
// hide discard button
this.form.find('.js-note-discard').hide();
this.form.show();
if (this.isAutosizeable) this.setupAutosize();
}
setupAutosize() {
this.textarea.off('autosize:resized')
.on('autosize:resized', this.setHeightData.bind(this));
this.textarea.off('mouseup.autosize')
.on('mouseup.autosize', this.destroyAutosize.bind(this));
setTimeout(() => {
autosize(this.textarea);
this.textarea.css('resize', 'vertical');
}, 0);
}
setHeightData() {
this.textarea.data('height', this.textarea.outerHeight());
}
destroyAutosize() {
const outerHeight = this.textarea.outerHeight();
if (this.textarea.data('height') === outerHeight) return;
autosize.destroy(this.textarea);
this.textarea.data('height', outerHeight);
this.textarea.outerHeight(outerHeight);
this.textarea.css('max-height', window.outerHeight);
}
clearEventListeners() {
this.textarea.off('focus');
this.textarea.off('blur');
gl.text.removeListeners(this.form);
}
addEventListeners() {
this.textarea.on('focus', function focusTextArea() {
$(this).closest('.md-area').addClass('is-focused');
});
this.textarea.on('blur', function blurTextArea() {
$(this).closest('.md-area').removeClass('is-focused');
});
new DropzoneInput(this.form);
autosize(this.textarea);
}
// form and textarea event listeners
this.addEventListeners();
gl.text.init(this.form);
// hide discard button
this.form.find('.js-note-discard').hide();
this.form.show();
if (this.isAutosizeable) this.setupAutosize();
};
GLForm.prototype.setupAutosize = function () {
this.textarea.off('autosize:resized')
.on('autosize:resized', this.setHeightData.bind(this));
this.textarea.off('mouseup.autosize')
.on('mouseup.autosize', this.destroyAutosize.bind(this));
setTimeout(() => {
autosize(this.textarea);
this.textarea.css('resize', 'vertical');
}, 0);
};
GLForm.prototype.setHeightData = function () {
this.textarea.data('height', this.textarea.outerHeight());
};
GLForm.prototype.destroyAutosize = function () {
const outerHeight = this.textarea.outerHeight();
if (this.textarea.data('height') === outerHeight) return;
autosize.destroy(this.textarea);
this.textarea.data('height', outerHeight);
this.textarea.outerHeight(outerHeight);
this.textarea.css('max-height', window.outerHeight);
};
GLForm.prototype.clearEventListeners = function() {
this.textarea.off('focus');
this.textarea.off('blur');
return gl.text.removeListeners(this.form);
};
GLForm.prototype.addEventListeners = function() {
this.textarea.on('focus', function() {
return $(this).closest('.md-area').addClass('is-focused');
});
return this.textarea.on('blur', function() {
return $(this).closest('.md-area').removeClass('is-focused');
});
};
window.gl.GLForm = GLForm;
}

View File

@ -1,6 +1,5 @@
/* global Flash */
import Vue from 'vue';
import Flash from '../flash';
import GroupFilterableList from './groups_filterable_list';
import GroupsComponent from './components/groups.vue';
import GroupFolder from './components/group_folder.vue';

View File

@ -1,7 +1,16 @@
/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var */
import { highCountTrim } from '~/lib/utils/text_utility';
$(document).on('todo:toggle', function(e, count) {
var $todoPendingCount = $('.todos-count');
$todoPendingCount.text(gl.text.highCountTrim(count));
$todoPendingCount.toggleClass('hidden', count === 0);
/**
* Updates todo counter when todos are toggled.
* When count is 0, we hide the badge.
*
* @param {jQuery.Event} e
* @param {String} count
*/
$(document).on('todo:toggle', (e, count) => {
const parsedCount = parseInt(count, 10);
const $todoPendingCount = $('.todos-count');
$todoPendingCount.text(highCountTrim(parsedCount));
$todoPendingCount.toggleClass('hidden', parsedCount === 0);
});

View File

@ -1,4 +1,4 @@
/* global Flash */
import Flash from '../flash';
export default class IntegrationSettingsForm {
constructor(formSelector) {
@ -102,7 +102,7 @@ export default class IntegrationSettingsForm {
})
.done((res) => {
if (res.error) {
new Flash(`${res.message} ${res.service_response}`, null, null, {
new Flash(`${res.message} ${res.service_response}`, 'alert', document, {
title: 'Save anyway',
clickHandler: (e) => {
e.preventDefault();

View File

@ -1,7 +1,7 @@
/* eslint-disable comma-dangle, quotes, consistent-return, func-names, array-callback-return, space-before-function-paren, prefer-arrow-callback, max-len, no-unused-expressions, no-sequences, no-underscore-dangle, no-unused-vars, no-param-reassign */
/* global IssuableIndex */
/* global Flash */
import _ from 'underscore';
import Flash from './flash';
export default {
init({ container, form, issues, prefixId } = {}) {

View File

@ -1,9 +1,7 @@
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, one-var, no-underscore-dangle, one-var-declaration-per-line, object-shorthand, no-unused-vars, no-new, comma-dangle, consistent-return, quotes, dot-notation, quote-props, prefer-arrow-callback, max-len */
/* global Flash */
import 'vendor/jquery.waitforimages';
import '~/lib/utils/text_utility';
import './flash';
import Flash from './flash';
import TaskList from './task_list';
import CreateMergeRequestDropdown from './create_merge_request_dropdown';
import IssuablesHelper from './helpers/issuables_helper';

View File

@ -1,5 +1,4 @@
<script>
/* global Flash */
import Visibility from 'visibilityjs';
import Poll from '../../lib/utils/poll';
import eventHub from '../event_hub';
@ -153,7 +152,7 @@ export default {
})
.catch(() => {
eventHub.$emit('close.form');
return new Flash('Error updating issue');
window.Flash('Error updating issue');
});
},
deleteIssuable() {
@ -167,7 +166,7 @@ export default {
})
.catch(() => {
eventHub.$emit('close.form');
return new Flash('Error deleting issue');
window.Flash('Error deleting issue');
});
},
},

View File

@ -1,5 +1,4 @@
<script>
/* global Flash */
import updateMixin from '../../mixins/update';
import markdownField from '../../../vue_shared/components/markdown/field.vue';

View File

@ -1,15 +1,12 @@
/* eslint-disable func-names, wrap-iife, no-use-before-define,
consistent-return, prefer-rest-params */
import _ from 'underscore';
import bp from './breakpoints';
import { bytesToKiB } from './lib/utils/number_utils';
import { setCiStatusFavicon } from './lib/utils/common_utils';
window.Build = (function () {
Build.timeout = null;
Build.state = null;
function Build(options) {
export default class Job {
constructor(options) {
this.timeout = null;
this.state = null;
this.options = options || $('.js-build-options').data();
this.pageUrl = this.options.pageUrl;
@ -19,9 +16,7 @@ window.Build = (function () {
this.$document = $(document);
this.logBytes = 0;
this.hasBeenScrolled = false;
this.updateDropdown = this.updateDropdown.bind(this);
this.getBuildTrace = this.getBuildTrace.bind(this);
this.$buildTrace = $('#build-trace');
this.$buildRefreshAnimation = $('.js-build-refresh');
@ -33,7 +28,7 @@ window.Build = (function () {
this.$scrollTopBtn = $('.js-scroll-up');
this.$scrollBottomBtn = $('.js-scroll-down');
clearTimeout(Build.timeout);
clearTimeout(this.timeout);
this.initSidebar();
this.populateJobs(this.buildStage);
@ -85,7 +80,7 @@ window.Build = (function () {
this.getBuildTrace();
}
Build.prototype.initAffixTopArea = function () {
initAffixTopArea() {
/**
If the browser does not support position sticky, it returns the position as static.
If the browser does support sticky, then we allow the browser to handle it, if not
@ -100,13 +95,14 @@ window.Build = (function () {
top: offsetTop,
},
});
};
}
Build.prototype.canScroll = function () {
// eslint-disable-next-line class-methods-use-this
canScroll() {
return $(document).height() > $(window).height();
};
}
Build.prototype.toggleScroll = function () {
toggleScroll() {
const currentPosition = $(document).scrollTop();
const scrollHeight = $(document).height();
@ -119,7 +115,7 @@ window.Build = (function () {
this.toggleDisableButton(this.$scrollTopBtn, false);
this.toggleDisableButton(this.$scrollBottomBtn, false);
} else if (currentPosition === 0) {
// User is at Top of Build Log
// User is at Top of Log
this.toggleDisableButton(this.$scrollTopBtn, true);
this.toggleDisableButton(this.$scrollBottomBtn, false);
@ -133,38 +129,40 @@ window.Build = (function () {
this.toggleDisableButton(this.$scrollTopBtn, true);
this.toggleDisableButton(this.$scrollBottomBtn, true);
}
};
}
Build.prototype.scrollDown = function () {
// eslint-disable-next-line class-methods-use-this
scrollDown() {
$(document).scrollTop($(document).height());
};
}
Build.prototype.scrollToBottom = function () {
scrollToBottom() {
this.scrollDown();
this.hasBeenScrolled = true;
this.toggleScroll();
};
}
Build.prototype.scrollToTop = function () {
scrollToTop() {
$(document).scrollTop(0);
this.hasBeenScrolled = true;
this.toggleScroll();
};
}
Build.prototype.toggleDisableButton = function ($button, disable) {
// eslint-disable-next-line class-methods-use-this
toggleDisableButton($button, disable) {
if (disable && $button.prop('disabled')) return;
$button.prop('disabled', disable);
};
}
Build.prototype.toggleScrollAnimation = function (toggle) {
toggleScrollAnimation(toggle) {
this.$scrollBottomBtn.toggleClass('animate', toggle);
};
}
Build.prototype.initSidebar = function () {
initSidebar() {
this.$sidebar = $('.js-build-sidebar');
};
}
Build.prototype.getBuildTrace = function () {
getBuildTrace() {
return $.ajax({
url: `${this.pageUrl}/trace.json`,
data: { state: this.state },
@ -204,7 +202,7 @@ window.Build = (function () {
this.toggleScrollAnimation(false);
}
Build.timeout = setTimeout(() => {
this.timeout = setTimeout(() => {
this.getBuildTrace();
}, 4000);
} else {
@ -225,14 +223,14 @@ window.Build = (function () {
}
})
.then(() => this.toggleScroll());
};
Build.prototype.shouldHideSidebarForViewport = function () {
}
// eslint-disable-next-line class-methods-use-this
shouldHideSidebarForViewport() {
const bootstrapBreakpoint = bp.getBreakpointSize();
return bootstrapBreakpoint === 'xs' || bootstrapBreakpoint === 'sm';
};
}
Build.prototype.toggleSidebar = function (shouldHide) {
toggleSidebar(shouldHide) {
const shouldShow = typeof shouldHide === 'boolean' ? !shouldHide : undefined;
const $toggleButton = $('.js-sidebar-build-toggle-header');
@ -249,17 +247,17 @@ window.Build = (function () {
} else {
$toggleButton.removeClass('hidden');
}
};
}
Build.prototype.sidebarOnResize = function () {
sidebarOnResize() {
this.toggleSidebar(this.shouldHideSidebarForViewport());
};
}
Build.prototype.sidebarOnClick = function () {
sidebarOnClick() {
if (this.shouldHideSidebarForViewport()) this.toggleSidebar();
};
Build.prototype.updateArtifactRemoveDate = function () {
}
// eslint-disable-next-line class-methods-use-this, consistent-return
updateArtifactRemoveDate() {
const $date = $('.js-artifacts-remove');
if ($date.length) {
const date = $date.text();
@ -267,23 +265,21 @@ window.Build = (function () {
gl.utils.timeFor(new Date(date.replace(/([0-9]+)-([0-9]+)-([0-9]+)/g, '$1/$2/$3')), ' '),
);
}
};
Build.prototype.populateJobs = function (stage) {
}
// eslint-disable-next-line class-methods-use-this
populateJobs(stage) {
$('.build-job').hide();
$(`.build-job[data-stage="${stage}"]`).show();
};
Build.prototype.updateStageDropdownText = function (stage) {
}
// eslint-disable-next-line class-methods-use-this
updateStageDropdownText(stage) {
$('.stage-selection').text(stage);
};
}
Build.prototype.updateDropdown = function (e) {
updateDropdown(e) {
e.preventDefault();
const stage = e.currentTarget.text;
this.updateStageDropdownText(stage);
this.populateJobs(stage);
};
return Build;
})();
}
}

View File

@ -1,5 +1,3 @@
/* global Flash */
import Vue from 'vue';
import JobMediator from './job_details_mediator';
import jobHeader from './components/header.vue';

View File

@ -1,11 +1,12 @@
/* global Flash */
/* global Build */
import Visibility from 'visibilityjs';
import Flash from '../flash';
import Poll from '../lib/utils/poll';
import JobStore from './stores/job_store';
import JobService from './services/job_service';
import '../build';
import Job from '../job';
import handleRevealVariables from '../build_variables';
export default class JobMediator {
constructor(options = {}) {
@ -20,7 +21,8 @@ export default class JobMediator {
}
initBuildClass() {
this.build = new Build();
this.build = new Job();
handleRevealVariables();
}
fetchJob() {

View File

@ -1,124 +1,121 @@
/* eslint-disable comma-dangle, class-methods-use-this, no-underscore-dangle, no-param-reassign, no-unused-vars, consistent-return, func-names, space-before-function-paren, max-len */
/* global Flash */
/* global Sortable */
((global) => {
class LabelManager {
constructor({ togglePriorityButton, prioritizedLabels, otherLabels } = {}) {
this.togglePriorityButton = togglePriorityButton || $('.js-toggle-priority');
this.prioritizedLabels = prioritizedLabels || $('.js-prioritized-labels');
this.otherLabels = otherLabels || $('.js-other-labels');
this.errorMessage = 'Unable to update label prioritization at this time';
this.emptyState = document.querySelector('#js-priority-labels-empty-state');
this.sortable = Sortable.create(this.prioritizedLabels.get(0), {
filter: '.empty-message',
forceFallback: true,
fallbackClass: 'is-dragging',
dataIdAttr: 'data-id',
onUpdate: this.onPrioritySortUpdate.bind(this),
});
this.bindEvents();
}
import Flash from './flash';
bindEvents() {
this.prioritizedLabels.find('.btn-action').on('mousedown', this, this.onButtonActionClick);
return this.togglePriorityButton.on('click', this, this.onTogglePriorityClick);
}
onTogglePriorityClick(e) {
e.preventDefault();
const _this = e.data;
const $btn = $(e.currentTarget);
const $label = $(`#${$btn.data('domId')}`);
const action = $btn.parents('.js-prioritized-labels').length ? 'remove' : 'add';
const $tooltip = $(`#${$btn.find('.has-tooltip:visible').attr('aria-describedby')}`);
$tooltip.tooltip('destroy');
_this.toggleLabelPriority($label, action);
_this.toggleEmptyState($label, $btn, action);
}
onButtonActionClick(e) {
e.stopPropagation();
$(e.currentTarget).tooltip('hide');
}
toggleEmptyState($label, $btn, action) {
this.emptyState.classList.toggle('hidden', !!this.prioritizedLabels[0].querySelector(':scope > li'));
}
toggleLabelPriority($label, action, persistState) {
if (persistState == null) {
persistState = true;
}
let xhr;
const _this = this;
const url = $label.find('.js-toggle-priority').data('url');
let $target = this.prioritizedLabels;
let $from = this.otherLabels;
if (action === 'remove') {
$target = this.otherLabels;
$from = this.prioritizedLabels;
}
$label.detach().appendTo($target);
if ($from.find('li').length) {
$from.find('.empty-message').removeClass('hidden');
}
if ($target.find('> li:not(.empty-message)').length) {
$target.find('.empty-message').addClass('hidden');
}
// Return if we are not persisting state
if (!persistState) {
return;
}
if (action === 'remove') {
xhr = $.ajax({
url,
type: 'DELETE'
});
// Restore empty message
if (!$from.find('li').length) {
$from.find('.empty-message').removeClass('hidden');
}
} else {
xhr = this.savePrioritySort($label, action);
}
return xhr.fail(this.rollbackLabelPosition.bind(this, $label, action));
}
onPrioritySortUpdate() {
const xhr = this.savePrioritySort();
return xhr.fail(function() {
return new Flash(this.errorMessage, 'alert');
});
}
savePrioritySort() {
return $.post({
url: this.prioritizedLabels.data('url'),
data: {
label_ids: this.getSortedLabelsIds()
}
});
}
rollbackLabelPosition($label, originalAction) {
const action = originalAction === 'remove' ? 'add' : 'remove';
this.toggleLabelPriority($label, action, false);
return new Flash(this.errorMessage, 'alert');
}
getSortedLabelsIds() {
const sortedIds = [];
this.prioritizedLabels.find('> li').each(function() {
const id = $(this).data('id');
if (id) {
sortedIds.push(id);
}
});
return sortedIds;
}
export default class LabelManager {
constructor({ togglePriorityButton, prioritizedLabels, otherLabels } = {}) {
this.togglePriorityButton = togglePriorityButton || $('.js-toggle-priority');
this.prioritizedLabels = prioritizedLabels || $('.js-prioritized-labels');
this.otherLabels = otherLabels || $('.js-other-labels');
this.errorMessage = 'Unable to update label prioritization at this time';
this.emptyState = document.querySelector('#js-priority-labels-empty-state');
this.sortable = Sortable.create(this.prioritizedLabels.get(0), {
filter: '.empty-message',
forceFallback: true,
fallbackClass: 'is-dragging',
dataIdAttr: 'data-id',
onUpdate: this.onPrioritySortUpdate.bind(this),
});
this.bindEvents();
}
gl.LabelManager = LabelManager;
})(window.gl || (window.gl = {}));
bindEvents() {
this.prioritizedLabels.find('.btn-action').on('mousedown', this, this.onButtonActionClick);
return this.togglePriorityButton.on('click', this, this.onTogglePriorityClick);
}
onTogglePriorityClick(e) {
e.preventDefault();
const _this = e.data;
const $btn = $(e.currentTarget);
const $label = $(`#${$btn.data('domId')}`);
const action = $btn.parents('.js-prioritized-labels').length ? 'remove' : 'add';
const $tooltip = $(`#${$btn.find('.has-tooltip:visible').attr('aria-describedby')}`);
$tooltip.tooltip('destroy');
_this.toggleLabelPriority($label, action);
_this.toggleEmptyState($label, $btn, action);
}
onButtonActionClick(e) {
e.stopPropagation();
$(e.currentTarget).tooltip('hide');
}
toggleEmptyState($label, $btn, action) {
this.emptyState.classList.toggle('hidden', !!this.prioritizedLabels[0].querySelector(':scope > li'));
}
toggleLabelPriority($label, action, persistState) {
if (persistState == null) {
persistState = true;
}
let xhr;
const _this = this;
const url = $label.find('.js-toggle-priority').data('url');
let $target = this.prioritizedLabels;
let $from = this.otherLabels;
if (action === 'remove') {
$target = this.otherLabels;
$from = this.prioritizedLabels;
}
$label.detach().appendTo($target);
if ($from.find('li').length) {
$from.find('.empty-message').removeClass('hidden');
}
if ($target.find('> li:not(.empty-message)').length) {
$target.find('.empty-message').addClass('hidden');
}
// Return if we are not persisting state
if (!persistState) {
return;
}
if (action === 'remove') {
xhr = $.ajax({
url,
type: 'DELETE'
});
// Restore empty message
if (!$from.find('li').length) {
$from.find('.empty-message').removeClass('hidden');
}
} else {
xhr = this.savePrioritySort($label, action);
}
return xhr.fail(this.rollbackLabelPosition.bind(this, $label, action));
}
onPrioritySortUpdate() {
const xhr = this.savePrioritySort();
return xhr.fail(function() {
return new Flash(this.errorMessage, 'alert');
});
}
savePrioritySort() {
return $.post({
url: this.prioritizedLabels.data('url'),
data: {
label_ids: this.getSortedLabelsIds()
}
});
}
rollbackLabelPosition($label, originalAction) {
const action = originalAction === 'remove' ? 'add' : 'remove';
this.toggleLabelPriority($label, action, false);
return new Flash(this.errorMessage, 'alert');
}
getSortedLabelsIds() {
const sortedIds = [];
this.prioritizedLabels.find('> li').each(function() {
const id = $(this).data('id');
if (id) {
sortedIds.push(id);
}
});
return sortedIds;
}
}

View File

@ -1,44 +1,35 @@
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, vars-on-top, no-unused-vars, max-len */
(function() {
this.Labels = (function() {
function Labels() {
this.setSuggestedColor = this.setSuggestedColor.bind(this);
this.updateColorPreview = this.updateColorPreview.bind(this);
var form;
form = $('.label-form');
this.cleanBinding();
this.addBinding();
this.updateColorPreview();
}
export default class Labels {
constructor() {
this.setSuggestedColor = this.setSuggestedColor.bind(this);
this.updateColorPreview = this.updateColorPreview.bind(this);
this.cleanBinding();
this.addBinding();
this.updateColorPreview();
}
Labels.prototype.addBinding = function() {
$(document).on('click', '.suggest-colors a', this.setSuggestedColor);
return $(document).on('input', 'input#label_color', this.updateColorPreview);
};
addBinding() {
$(document).on('click', '.suggest-colors a', this.setSuggestedColor);
return $(document).on('input', 'input#label_color', this.updateColorPreview);
}
// eslint-disable-next-line class-methods-use-this
cleanBinding() {
$(document).off('click', '.suggest-colors a');
return $(document).off('input', 'input#label_color');
}
// eslint-disable-next-line class-methods-use-this
updateColorPreview() {
const previewColor = $('input#label_color').val();
return $('div.label-color-preview').css('background-color', previewColor);
// Updates the the preview color with the hex-color input
}
Labels.prototype.cleanBinding = function() {
$(document).off('click', '.suggest-colors a');
return $(document).off('input', 'input#label_color');
};
Labels.prototype.updateColorPreview = function() {
var previewColor;
previewColor = $('input#label_color').val();
return $('div.label-color-preview').css('background-color', previewColor);
// Updates the the preview color with the hex-color input
};
// Updates the preview color with a click on a suggested color
Labels.prototype.setSuggestedColor = function(e) {
var color;
color = $(e.currentTarget).data('color');
$('input#label_color').val(color);
this.updateColorPreview();
// Notify the form, that color has changed
$('.label-form').trigger('keyup');
return e.preventDefault();
};
return Labels;
})();
}).call(window);
// Updates the preview color with a click on a suggested color
setSuggestedColor(e) {
const color = $(e.currentTarget).data('color');
$('input#label_color').val(color);
this.updateColorPreview();
// Notify the form, that color has changed
$('.label-form').trigger('keyup');
return e.preventDefault();
}
}

View File

@ -285,7 +285,7 @@ import CreateLabelDropdown from './create_label';
},
hidden: function() {
var isIssueIndex, isMRIndex, page, selectedLabels;
page = $('body').data('page');
page = $('body').attr('data-page');
isIssueIndex = page === 'projects:issues:index';
isMRIndex = page === 'projects:merge_requests:index';
$selectbox.hide();
@ -325,7 +325,7 @@ import CreateLabelDropdown from './create_label';
$loading.fadeOut();
};
page = $('body').data('page');
page = $('body').attr('data-page');
isIssueIndex = page === 'projects:issues:index';
isMRIndex = page === 'projects:merge_requests:index';

View File

@ -1,5 +1,5 @@
export const getPagePath = (index = 0) => $('body').data('page').split(':')[index];
export const getPagePath = (index = 0) => $('body').attr('data-page').split(':')[index];
export const isInGroupsPage = () => getPagePath() === 'groups';

View File

@ -1,4 +1,4 @@
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-param-reassign, no-cond-assign, quotes, one-var, one-var-declaration-per-line, operator-assignment, no-else-return, prefer-template, prefer-arrow-callback, no-empty, max-len, consistent-return, no-unused-vars, no-return-assign, max-len, vars-on-top */
/* eslint-disable import/prefer-default-export, func-names, space-before-function-paren, wrap-iife, no-var, no-param-reassign, no-cond-assign, quotes, one-var, one-var-declaration-per-line, operator-assignment, no-else-return, prefer-template, prefer-arrow-callback, no-empty, max-len, consistent-return, no-unused-vars, no-return-assign, max-len, vars-on-top */
import 'vendor/latinise';
@ -13,9 +13,17 @@ if ((base = w.gl).text == null) {
gl.text.addDelimiter = function(text) {
return text ? text.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") : text;
};
gl.text.highCountTrim = function(count) {
/**
* Returns '99+' for numbers bigger than 99.
*
* @param {Number} count
* @return {Number|String}
*/
export function highCountTrim(count) {
return count > 99 ? '99+' : count;
};
}
gl.text.randomString = function() {
return Math.random().toString(36).substring(7);
};

View File

@ -1,5 +1,4 @@
/* eslint-disable func-names, space-before-function-paren, no-var, quotes, consistent-return, prefer-arrow-callback, comma-dangle, object-shorthand, no-new, max-len, no-multi-spaces, import/newline-after-import, import/first */
/* global Flash */
/* global ConfirmDangerModal */
/* global Aside */
@ -47,25 +46,14 @@ import './lib/utils/url_utility';
// behaviors
import './behaviors/';
// u2f
import './u2f/authenticate';
import './u2f/error';
import './u2f/register';
import './u2f/util';
// everything else
import './activities';
import './admin';
import './api';
import './aside';
import './autosave';
import loadAwardsHandler from './awards_handler';
import bp from './breakpoints';
import './broadcast_message';
import './build';
import './build_artifacts';
import './build_variables';
import './ci_lint_editor';
import './commits';
import './compare';
import './compare_autocomplete';
@ -76,7 +64,7 @@ import './diff';
import './dropzone_input';
import './due_date_select';
import './files_comment_button';
import './flash';
import Flash from './flash';
import './gl_dropdown';
import './gl_field_error';
import './gl_field_errors';
@ -91,8 +79,6 @@ import './issuable_context';
import './issuable_form';
import './issue';
import './issue_status_select';
import './label_manager';
import './labels';
import './labels_select';
import './layout_nav';
import LazyLoader from './lazy_loader';
@ -130,7 +116,6 @@ import './right_sidebar';
import './search';
import './search_autocomplete';
import './smart_interval';
import './star';
import './subscription';
import './subscription_select';
import initBreadcrumbs from './breadcrumb';
@ -169,7 +154,6 @@ $(function () {
var $document = $(document);
var $window = $(window);
var $sidebarGutterToggle = $('.js-sidebar-toggle');
var $flash = $('.flash-container');
var bootstrapBreakpoint = bp.getBreakpointSize();
var fitSidebarForSize;
@ -254,13 +238,6 @@ $(function () {
// Form submitter
});
gl.utils.localTimeAgo($('abbr.timeago, .js-timeago'), true);
// Flash
if ($flash.length > 0) {
$flash.click(function () {
return $(this).fadeOut();
});
$flash.show();
}
// Disable form buttons while a form is submitting
$body.on('ajax:complete, ajax:beforeSend, submit', 'form', function (e) {
var buttons;

View File

@ -1,8 +1,8 @@
/* eslint-disable comma-dangle, quote-props, no-useless-computed-key, object-shorthand, no-new, no-param-reassign, max-len */
/* global ace */
/* global Flash */
import Vue from 'vue';
import Flash from '../../flash';
((global) => {
global.mergeConflicts = global.mergeConflicts || {};

View File

@ -1,7 +1,7 @@
/* eslint-disable new-cap, comma-dangle, no-new */
/* global Flash */
import Vue from 'vue';
import Flash from '../flash';
import initIssuableSidebar from '../init_issuable_sidebar';
import './merge_conflict_store';
import './merge_conflict_service';

View File

@ -1,9 +1,8 @@
/* eslint-disable no-new, class-methods-use-this */
/* global Flash */
/* global notes */
import Cookies from 'js-cookie';
import './flash';
import Flash from './flash';
import BlobForkSuggestion from './blob/blob_fork_suggestion';
import initChangesDropdown from './init_changes_dropdown';
import bp from './breakpoints';

View File

@ -1,7 +1,8 @@
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-use-before-define, camelcase, quotes, object-shorthand, no-shadow, no-unused-vars, comma-dangle, no-var, prefer-template, no-underscore-dangle, consistent-return, one-var, one-var-declaration-per-line, default-case, prefer-arrow-callback, max-len */
/* global Flash */
/* global Sortable */
import Flash from './flash';
(function() {
this.Milestone = (function() {
function Milestone() {

View File

@ -147,7 +147,7 @@ import _ from 'underscore';
const { $el, e } = options;
let selected = options.selectedObj;
var data, isIssueIndex, isMRIndex, isSelecting, page, boardsStore;
page = $('body').data('page');
page = $('body').attr('data-page');
isIssueIndex = page === 'projects:issues:index';
isMRIndex = (page === page && page === 'projects:merge_requests:index');
isSelecting = (selected.name !== selectedMilestone);

View File

@ -1,5 +1,5 @@
/* eslint-disable no-new */
/* global Flash */
import Flash from './flash';
/**
* In each pipelines table we have a mini pipeline graph for each pipeline.

View File

@ -1,6 +1,6 @@
<script>
/* global Flash */
import _ from 'underscore';
import Flash from '../../flash';
import MonitoringService from '../services/monitoring_service';
import GraphGroup from './graph_group.vue';
import Graph from './graph.vue';

View File

@ -5,7 +5,6 @@ default-case, prefer-template, consistent-return, no-alert, no-return-assign,
no-param-reassign, prefer-arrow-callback, no-else-return, comma-dangle, no-new,
brace-style, no-lonely-if, vars-on-top, no-unused-vars, no-sequences, no-shadow,
newline-per-chained-call, no-useless-escape, class-methods-use-this */
/* global Flash */
/* global Autosave */
/* global ResolveService */
/* global mrRefreshWidgetUrl */
@ -18,7 +17,9 @@ import Dropzone from 'dropzone';
import 'vendor/jquery.caret'; // required by jquery.atwho
import 'vendor/jquery.atwho';
import AjaxCache from '~/lib/utils/ajax_cache';
import Flash from './flash';
import CommentTypeToggle from './comment_type_toggle';
import GLForm from './gl_form';
import loadAwardsHandler from './awards_handler';
import './autosave';
import './dropzone_input';
@ -354,7 +355,7 @@ export default class Notes {
Object.keys(noteEntity.commands_changes).length > 0) {
$notesList.find('.system-note.being-posted').remove();
}
this.addFlash(noteEntity.errors.commands_only, 'notice', this.parentTimeline);
this.addFlash(noteEntity.errors.commands_only, 'notice', this.parentTimeline.get(0));
this.refresh();
}
return;
@ -557,7 +558,7 @@ export default class Notes {
*/
setupNoteForm(form) {
var textarea, key;
new gl.GLForm(form, this.enableGFM);
this.glForm = new GLForm(form, this.enableGFM);
textarea = form.find('.js-note-text');
key = [
'Note',
@ -593,7 +594,7 @@ export default class Notes {
} else if ($form.hasClass('js-discussion-note-form')) {
formParentTimeline = $form.closest('.discussion-notes').find('.notes');
}
return this.addFlash('Your comment could not be submitted! Please check your network connection and try again.', 'alert', formParentTimeline);
return this.addFlash('Your comment could not be submitted! Please check your network connection and try again.', 'alert', formParentTimeline.get(0));
}
updateNoteError($parentTimeline) {
@ -1152,7 +1153,7 @@ export default class Notes {
var targetId = $originalContentEl.data('target-id');
var targetType = $originalContentEl.data('target-type');
new gl.GLForm($editForm.find('form'), this.enableGFM);
this.glForm = new GLForm($editForm.find('form'), this.enableGFM);
$editForm.find('form')
.attr('action', postUrl)
@ -1213,13 +1214,13 @@ export default class Notes {
}
addFlash(...flashParams) {
this.flashInstance = new Flash(...flashParams);
this.flashContainer = new Flash(...flashParams);
}
clearFlash() {
if (this.flashInstance && this.flashInstance.flashContainer) {
this.flashInstance.flashContainer.hide();
this.flashInstance = null;
if (this.flashContainer) {
this.flashContainer.style.display = 'none';
this.flashContainer = null;
}
}
@ -1257,7 +1258,7 @@ export default class Notes {
}
static checkMergeRequestStatus() {
if (getPagePath(1) === 'merge_requests') {
if (getPagePath(1) === 'merge_requests' && gl.mrWidget) {
gl.mrWidget.checkStatus();
}
}

View File

@ -1,8 +1,9 @@
<script>
/* global Flash, Autosave */
/* global Autosave */
import { mapActions, mapGetters } from 'vuex';
import _ from 'underscore';
import autosize from 'vendor/autosize';
import Flash from '../../flash';
import '../../autosave';
import TaskList from '../../task_list';
import * as constants from '../constants';
@ -145,7 +146,7 @@
Flash(
'Something went wrong while adding your comment. Please try again.',
'alert',
$(this.$refs.commentForm),
this.$refs.commentForm,
);
}
} else {
@ -160,7 +161,7 @@
this.isSubmitting = false;
this.discard(false);
const msg = 'Your comment could not be submitted! Please check your network connection and try again.';
Flash(msg, 'alert', $(this.$el));
Flash(msg, 'alert', this.$el);
this.note = noteData.data.note.note; // Restore textarea content.
this.removePlaceholderNotes();
});

View File

@ -1,6 +1,6 @@
<script>
/* global Flash */
import { mapActions, mapGetters } from 'vuex';
import Flash from '../../flash';
import { SYSTEM_NOTE } from '../constants';
import issueNote from './issue_note.vue';
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
@ -133,7 +133,7 @@
this.isReplying = true;
this.$nextTick(() => {
const msg = 'Your comment could not be submitted! Please check your network connection and try again.';
Flash(msg, 'alert', $(this.$el));
Flash(msg, 'alert', this.$el);
this.$refs.noteForm.note = noteText;
callback(err);
});

View File

@ -1,7 +1,6 @@
<script>
/* global Flash */
import { mapGetters, mapActions } from 'vuex';
import Flash from '../../flash';
import userAvatarLink from '../../vue_shared/components/user_avatar/user_avatar_link.vue';
import issueNoteHeader from './issue_note_header.vue';
import issueNoteActions from './issue_note_actions.vue';
@ -101,7 +100,7 @@
this.isEditing = true;
this.$nextTick(() => {
const msg = 'Something went wrong while editing your comment. Please try again.';
Flash(msg, 'alert', $(this.$el));
Flash(msg, 'alert', this.$el);
this.recoverNoteContent(noteText);
callback();
});

View File

@ -1,10 +1,9 @@
<script>
/* global Flash */
import { mapActions, mapGetters } from 'vuex';
import emojiSmiling from 'icons/_emoji_slightly_smiling_face.svg';
import emojiSmile from 'icons/_emoji_smile.svg';
import emojiSmiley from 'icons/_emoji_smiley.svg';
import Flash from '../../flash';
import { glEmojiTag } from '../../emoji';
import tooltip from '../../vue_shared/directives/tooltip';

View File

@ -1,6 +1,6 @@
<script>
/* global Flash */
import { mapGetters, mapActions } from 'vuex';
import Flash from '../../flash';
import store from '../stores/';
import * as constants from '../constants';
import issueNote from './issue_note.vue';

View File

@ -1,5 +1,5 @@
/* global Flash */
import Visibility from 'visibilityjs';
import Flash from '../../flash';
import Poll from '../../lib/utils/poll';
import * as types from './mutation_types';
import * as utils from './utils';
@ -99,7 +99,7 @@ export const saveNote = ({ commit, dispatch }, noteData) => {
eTagPoll.makeRequest();
$('.js-gfm-input').trigger('clear-commands-cache.atwho');
Flash('Commands applied', 'notice', $(noteData.flashContainer));
Flash('Commands applied', 'notice', noteData.flashContainer);
}
if (commandsChanges) {
@ -114,8 +114,8 @@ export const saveNote = ({ commit, dispatch }, noteData) => {
.catch(() => {
Flash(
'Something went wrong while adding your award. Please try again.',
null,
$(noteData.flashContainer),
'alert',
noteData.flashContainer,
);
});
}
@ -126,7 +126,7 @@ export const saveNote = ({ commit, dispatch }, noteData) => {
}
if (errors && errors.commands_only) {
Flash(errors.commands_only, 'notice', $(noteData.flashContainer));
Flash(errors.commands_only, 'notice', noteData.flashContainer);
}
commit(types.REMOVE_PLACEHOLDER_NOTES);

View File

@ -1,5 +1,5 @@
/* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, no-unused-vars, consistent-return, prefer-arrow-callback, no-else-return, max-len */
/* global Flash */
import Flash from './flash';
(function() {
this.NotificationsDropdown = (function() {

View File

@ -1,5 +1,6 @@
import Vue from 'vue';
import Translate from '../vue_shared/translate';
import GlFieldErrors from '../gl_field_errors';
import intervalPatternInput from './components/interval_pattern_input.vue';
import TimezoneDropdown from './components/timezone_dropdown';
import TargetBranchDropdown from './components/target_branch_dropdown';
@ -39,7 +40,7 @@ document.addEventListener('DOMContentLoaded', () => {
gl.timezoneDropdown = new TimezoneDropdown();
gl.targetBranchDropdown = new TargetBranchDropdown();
gl.pipelineScheduleFieldErrors = new gl.GlFieldErrors(formElement);
gl.pipelineScheduleFieldErrors = new GlFieldErrors(formElement);
setupPipelineVariableList($('.js-pipeline-variable-list'));
});

View File

@ -1,6 +1,4 @@
<script>
/* global Flash */
import '~/flash';
import playIconSvg from 'icons/_icon_play.svg';
import eventHub from '../event_hub';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';

View File

@ -13,7 +13,7 @@
* 4. Commit widget
*/
/* global Flash */
import Flash from '../../flash';
import { borderlessStatusIconEntityMap } from '../../vue_shared/ci_status_icons';
import loadingIcon from '../../vue_shared/components/loading_icon.vue';
import tooltip from '../../vue_shared/directives/tooltip';

View File

@ -1,6 +1,5 @@
/* global Flash */
import '~/flash';
import Visibility from 'visibilityjs';
import Flash from '../../flash';
import Poll from '../../lib/utils/poll';
import emptyState from '../components/empty_state.vue';
import errorState from '../components/error_state.vue';

View File

@ -1,6 +1,5 @@
/* global Flash */
import Vue from 'vue';
import Flash from '../flash';
import PipelinesMediator from './pipeline_details_mediatior';
import pipelineGraph from './components/graph/graph_component.vue';
import pipelineHeader from './components/header_component.vue';

View File

@ -1,6 +1,5 @@
/* global Flash */
import Visibility from 'visibilityjs';
import Flash from '../flash';
import Poll from '../lib/utils/poll';
import PipelineStore from './stores/pipeline_store';
import PipelineService from './services/pipeline_service';

View File

@ -1,5 +1,5 @@
/* eslint-disable comma-dangle, no-unused-vars, class-methods-use-this, quotes, consistent-return, func-names, prefer-arrow-callback, space-before-function-paren, max-len */
/* global Flash */
import Flash from '../flash';
import { getPagePath } from '../lib/utils/common_utils';
((global) => {

View File

@ -29,6 +29,12 @@ const bindEvents = () => {
const $newProjectForm = $('#new_project');
const $projectImportUrl = $('#project_import_url');
const $projectPath = $('#project_path');
const $useTemplateBtn = $('.template-button > input');
const $projectFieldsForm = $('.project-fields-form');
const $selectedTemplateText = $('.selected-template');
const $changeTemplateBtn = $('.change-template');
const $selectedIcon = $('.selected-icon svg');
const $templateProjectNameInput = $('#template-project-name #project_path');
if ($newProjectForm.length !== 1) {
return;
@ -48,6 +54,40 @@ const bindEvents = () => {
$('.btn_import_gitlab_project').attr('href', `${importHref}?namespace_id=${$('#project_namespace_id').val()}&path=${$projectPath.val()}`);
});
function chooseTemplate() {
$('.template-option').hide();
$projectFieldsForm.addClass('selected');
$selectedIcon.removeClass('active');
const value = $(this).val();
const templates = {
rails: {
text: 'Ruby on Rails',
icon: '.selected-icon .icon-rails',
},
express: {
text: 'NodeJS Express',
icon: '.selected-icon .icon-node-express',
},
spring: {
text: 'Spring',
icon: '.selected-icon .icon-java-spring',
},
};
const selectedTemplate = templates[value];
$selectedTemplateText.text(selectedTemplate.text);
$(selectedTemplate.icon).addClass('active');
$templateProjectNameInput.focus();
}
$useTemplateBtn.on('change', chooseTemplate);
$changeTemplateBtn.on('click', () => {
$('.template-option').show();
$projectFieldsForm.removeClass('selected');
$useTemplateBtn.prop('checked', false);
});
$newProjectForm.on('submit', () => {
$projectPath.val($projectPath.val().trim());
});

View File

@ -81,7 +81,11 @@ export default class PrometheusMetrics {
loadActiveMetrics() {
this.showMonitoringMetricsPanelState(PANEL_STATE.LOADING);
backOff((next, stop) => {
$.getJSON(this.activeMetricsEndpoint)
$.ajax({
url: this.activeMetricsEndpoint,
dataType: 'json',
global: false,
})
.done((res) => {
if (res && res.success) {
stop(res);

View File

@ -1,6 +1,5 @@
/* eslint-disable no-new */
/* global Flash */
import Flash from '../flash';
import ProtectedBranchAccessDropdown from './protected_branch_access_dropdown';
export default class ProtectedBranchEdit {
@ -57,7 +56,7 @@ export default class ProtectedBranchEdit {
},
},
error() {
new Flash('Failed to update branch!', null, $('.js-protected-branches-list'));
new Flash('Failed to update branch!', 'alert', document.querySelector('.js-protected-branches-list'));
},
}).always(() => {
this.$allowedToMergeDropdown.enable();

View File

@ -1,6 +1,5 @@
/* eslint-disable no-new */
/* global Flash */
import Flash from '../flash';
import ProtectedTagAccessDropdown from './protected_tag_access_dropdown';
export default class ProtectedTagEdit {
@ -43,7 +42,7 @@ export default class ProtectedTagEdit {
},
},
error() {
new Flash('Failed to update tag!', null, $('.js-protected-tags-list'));
new Flash('Failed to update tag!', 'alert', document.querySelector('.js-protected-tags-list'));
},
}).always(() => {
this.$allowedToCreateDropdownButton.enable();

View File

@ -1,5 +1,5 @@
<script>
/* global Flash */
import Flash from '../../flash';
import Store from '../stores/repo_store';
import RepoMixin from '../mixins/repo_mixin';
import Service from '../services/repo_service';

View File

@ -1,7 +1,6 @@
/* global Flash */
import Service from '../services/repo_service';
import Store from '../stores/repo_store';
import '../../flash';
import Flash from '../../flash';
const RepoHelper = {
monacoInstance: null,

View File

@ -1,4 +1,3 @@
/* global Flash */
import axios from 'axios';
import Store from '../stores/repo_store';
import Api from '../../api';

View File

@ -1,4 +1,3 @@
/* global Flash */
import Helper from '../helpers/repo_helper';
import Service from '../services/repo_service';

View File

@ -1,5 +1,5 @@
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, one-var, one-var-declaration-per-line, object-shorthand, prefer-arrow-callback, comma-dangle, prefer-template, quotes, no-else-return, max-len */
/* global Flash */
import Flash from './flash';
import Api from './api';
(function() {

View File

@ -1,5 +1,4 @@
/* global Flash */
import Flash from '../../../flash';
import AssigneeTitle from './assignee_title';
import Assignees from './assignees';

View File

@ -1,5 +1,5 @@
<script>
/* global Flash */
import Flash from '../../../flash';
import editForm from './edit_form.vue';
export default {

View File

@ -1,5 +1,3 @@
/* global Flash */
function isValidProjectId(id) {
return id > 0;
}
@ -38,7 +36,7 @@ class SidebarMoveIssue {
data: (searchTerm, callback) => {
this.mediator.fetchAutocompleteProjects(searchTerm)
.then(callback)
.catch(() => new Flash('An error occurred while fetching projects autocomplete.'));
.catch(() => new window.Flash('An error occurred while fetching projects autocomplete.'));
},
renderRow: project => `
<li>
@ -73,7 +71,7 @@ class SidebarMoveIssue {
this.mediator.moveIssue()
.catch(() => {
Flash('An error occurred while moving the issue.');
window.Flash('An error occurred while moving the issue.');
this.$confirmButton
.enable()
.removeClass('is-loading');

View File

@ -1,5 +1,4 @@
/* global Flash */
import Flash from '../flash';
import Service from './services/sidebar_service';
import Store from './stores/sidebar_store';

View File

@ -1,28 +1,29 @@
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-unused-vars, one-var, no-var, one-var-declaration-per-line, prefer-arrow-callback, no-new, max-len */
/* global Flash */
import Flash from './flash';
import { __, s__ } from './locale';
export default class Star {
constructor() {
$('.project-home-panel .toggle-star').on('ajax:success', function(e, data, status, xhr) {
var $starIcon, $starSpan, $this, toggleStar;
$this = $(this);
$starSpan = $this.find('span');
$starIcon = $this.find('i');
toggleStar = function(isStarred) {
$this.parent().find('.star-count').text(data.star_count);
if (isStarred) {
$starSpan.removeClass('starred').text(s__('StarProject|Star'));
$starIcon.removeClass('fa-star').addClass('fa-star-o');
} else {
$starSpan.addClass('starred').text(__('Unstar'));
$starIcon.removeClass('fa-star-o').addClass('fa-star');
$('.project-home-panel .toggle-star')
.on('ajax:success', function handleSuccess(e, data) {
const $this = $(this);
const $starSpan = $this.find('span');
const $starIcon = $this.find('i');
function toggleStar(isStarred) {
$this.parent().find('.star-count').text(data.star_count);
if (isStarred) {
$starSpan.removeClass('starred').text(s__('StarProject|Star'));
$starIcon.removeClass('fa-star').addClass('fa-star-o');
} else {
$starSpan.addClass('starred').text(__('Unstar'));
$starIcon.removeClass('fa-star-o').addClass('fa-star');
}
}
};
toggleStar($starSpan.hasClass('starred'));
}).on('ajax:error', function(e, xhr, status, error) {
new Flash('Star toggle failed. Try again later.', 'alert');
});
toggleStar($starSpan.hasClass('starred'));
})
.on('ajax:error', () => {
Flash('Star toggle failed. Try again later.', 'alert');
});
}
}

View File

@ -1,6 +1,5 @@
/* global Flash */
import 'deckar01-task_list';
import Flash from './flash';
export default class TaskList {
constructor(options = {}) {

View File

@ -1,4 +1,5 @@
/* global U2FRegister */
import U2FRegister from './u2f/register';
document.addEventListener('DOMContentLoaded', () => {
const twoFactorNode = document.querySelector('.js-two-factor-auth');
const skippable = twoFactorNode.dataset.twoFactorSkippable === 'true';

View File

@ -1,118 +1,108 @@
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, prefer-arrow-callback, no-else-return, quotes, quote-props, comma-dangle, one-var, one-var-declaration-per-line, max-len */
/* eslint-disable func-names, wrap-iife */
/* global u2f */
/* global U2FError */
/* global U2FUtil */
import _ from 'underscore';
import isU2FSupported from './util';
import U2FError from './error';
// Authenticate U2F (universal 2nd factor) devices for users to authenticate with.
//
// State Flow #1: setup -> in_progress -> authenticated -> POST to server
// State Flow #2: setup -> in_progress -> error -> setup
(function() {
const global = window.gl || (window.gl = {});
global.U2FAuthenticate = (function() {
function U2FAuthenticate(container, form, u2fParams, fallbackButton, fallbackUI) {
this.container = container;
this.renderNotSupported = this.renderNotSupported.bind(this);
this.renderAuthenticated = this.renderAuthenticated.bind(this);
this.renderError = this.renderError.bind(this);
this.renderInProgress = this.renderInProgress.bind(this);
this.renderTemplate = this.renderTemplate.bind(this);
this.authenticate = this.authenticate.bind(this);
this.start = this.start.bind(this);
this.appId = u2fParams.app_id;
this.challenge = u2fParams.challenge;
this.form = form;
this.fallbackButton = fallbackButton;
this.fallbackUI = fallbackUI;
if (this.fallbackButton) this.fallbackButton.addEventListener('click', this.switchToFallbackUI.bind(this));
this.signRequests = u2fParams.sign_requests.map(function(request) {
// The U2F Javascript API v1.1 requires a single challenge, with
// _no challenges per-request_. The U2F Javascript API v1.0 requires a
// challenge per-request, which is done by copying the single challenge
// into every request.
//
// In either case, we don't need the per-request challenges that the server
// has generated, so we can remove them.
//
// Note: The server library fixes this behaviour in (unreleased) version 1.0.0.
// This can be removed once we upgrade.
// https://github.com/castle/ruby-u2f/commit/103f428071a81cd3d5f80c2e77d522d5029946a4
return _(request).omit('challenge');
});
export default class U2FAuthenticate {
constructor(container, form, u2fParams, fallbackButton, fallbackUI) {
this.container = container;
this.renderNotSupported = this.renderNotSupported.bind(this);
this.renderAuthenticated = this.renderAuthenticated.bind(this);
this.renderError = this.renderError.bind(this);
this.renderInProgress = this.renderInProgress.bind(this);
this.renderTemplate = this.renderTemplate.bind(this);
this.authenticate = this.authenticate.bind(this);
this.start = this.start.bind(this);
this.appId = u2fParams.app_id;
this.challenge = u2fParams.challenge;
this.form = form;
this.fallbackButton = fallbackButton;
this.fallbackUI = fallbackUI;
if (this.fallbackButton) {
this.fallbackButton.addEventListener('click', this.switchToFallbackUI.bind(this));
}
U2FAuthenticate.prototype.start = function() {
if (U2FUtil.isU2FSupported()) {
return this.renderInProgress();
} else {
return this.renderNotSupported();
}
};
// The U2F Javascript API v1.1 requires a single challenge, with
// _no challenges per-request_. The U2F Javascript API v1.0 requires a
// challenge per-request, which is done by copying the single challenge
// into every request.
//
// In either case, we don't need the per-request challenges that the server
// has generated, so we can remove them.
//
// Note: The server library fixes this behaviour in (unreleased) version 1.0.0.
// This can be removed once we upgrade.
// https://github.com/castle/ruby-u2f/commit/103f428071a81cd3d5f80c2e77d522d5029946a4
this.signRequests = u2fParams.sign_requests.map(request => _(request).omit('challenge'));
U2FAuthenticate.prototype.authenticate = function() {
return u2f.sign(this.appId, this.challenge, this.signRequests, (function(_this) {
return function(response) {
var error;
if (response.errorCode) {
error = new U2FError(response.errorCode, 'authenticate');
return _this.renderError(error);
} else {
return _this.renderAuthenticated(JSON.stringify(response));
}
};
})(this), 10);
this.templates = {
notSupported: '#js-authenticate-u2f-not-supported',
setup: '#js-authenticate-u2f-setup',
inProgress: '#js-authenticate-u2f-in-progress',
error: '#js-authenticate-u2f-error',
authenticated: '#js-authenticate-u2f-authenticated',
};
}
// Rendering #
U2FAuthenticate.prototype.templates = {
"notSupported": "#js-authenticate-u2f-not-supported",
"setup": '#js-authenticate-u2f-setup',
"inProgress": '#js-authenticate-u2f-in-progress',
"error": '#js-authenticate-u2f-error',
"authenticated": '#js-authenticate-u2f-authenticated'
};
start() {
if (isU2FSupported()) {
return this.renderInProgress();
}
return this.renderNotSupported();
}
U2FAuthenticate.prototype.renderTemplate = function(name, params) {
var template, templateString;
templateString = $(this.templates[name]).html();
template = _.template(templateString);
return this.container.html(template(params));
};
authenticate() {
return u2f.sign(this.appId, this.challenge, this.signRequests, (function (_this) {
return function (response) {
if (response.errorCode) {
const error = new U2FError(response.errorCode, 'authenticate');
return _this.renderError(error);
}
return _this.renderAuthenticated(JSON.stringify(response));
};
})(this), 10);
}
U2FAuthenticate.prototype.renderInProgress = function() {
this.renderTemplate('inProgress');
return this.authenticate();
};
renderTemplate(name, params) {
const templateString = $(this.templates[name]).html();
const template = _.template(templateString);
return this.container.html(template(params));
}
U2FAuthenticate.prototype.renderError = function(error) {
this.renderTemplate('error', {
error_message: error.message(),
error_code: error.errorCode
});
return this.container.find('#js-u2f-try-again').on('click', this.renderInProgress);
};
renderInProgress() {
this.renderTemplate('inProgress');
return this.authenticate();
}
U2FAuthenticate.prototype.renderAuthenticated = function(deviceResponse) {
this.renderTemplate('authenticated');
const container = this.container[0];
container.querySelector('#js-device-response').value = deviceResponse;
container.querySelector(this.form).submit();
this.fallbackButton.classList.add('hidden');
};
renderError(error) {
this.renderTemplate('error', {
error_message: error.message(),
error_code: error.errorCode,
});
return this.container.find('#js-u2f-try-again').on('click', this.renderInProgress);
}
U2FAuthenticate.prototype.renderNotSupported = function() {
return this.renderTemplate('notSupported');
};
renderAuthenticated(deviceResponse) {
this.renderTemplate('authenticated');
const container = this.container[0];
container.querySelector('#js-device-response').value = deviceResponse;
container.querySelector(this.form).submit();
this.fallbackButton.classList.add('hidden');
}
U2FAuthenticate.prototype.switchToFallbackUI = function() {
this.fallbackButton.classList.add('hidden');
this.container[0].classList.add('hidden');
this.fallbackUI.classList.remove('hidden');
};
renderNotSupported() {
return this.renderTemplate('notSupported');
}
return U2FAuthenticate;
})();
})();
switchToFallbackUI() {
this.fallbackButton.classList.add('hidden');
this.container[0].classList.add('hidden');
this.fallbackUI.classList.remove('hidden');
}
}

View File

@ -1,25 +1,22 @@
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-console, quotes, prefer-template, max-len */
/* global u2f */
export default class U2FError {
constructor(errorCode, u2fFlowType) {
this.errorCode = errorCode;
this.message = this.message.bind(this);
this.httpsDisabled = window.location.protocol !== 'https:';
this.u2fFlowType = u2fFlowType;
}
(function() {
this.U2FError = (function() {
function U2FError(errorCode, u2fFlowType) {
this.errorCode = errorCode;
this.message = this.message.bind(this);
this.httpsDisabled = window.location.protocol !== 'https:';
this.u2fFlowType = u2fFlowType;
}
U2FError.prototype.message = function() {
if (this.errorCode === u2f.ErrorCodes.BAD_REQUEST && this.httpsDisabled) {
return 'U2F only works with HTTPS-enabled websites. Contact your administrator for more details.';
} else if (this.errorCode === u2f.ErrorCodes.DEVICE_INELIGIBLE) {
if (this.u2fFlowType === 'authenticate') return 'This device has not been registered with us.';
if (this.u2fFlowType === 'register') return 'This device has already been registered with us.';
message() {
if (this.errorCode === window.u2f.ErrorCodes.BAD_REQUEST && this.httpsDisabled) {
return 'U2F only works with HTTPS-enabled websites. Contact your administrator for more details.';
} else if (this.errorCode === window.u2f.ErrorCodes.DEVICE_INELIGIBLE) {
if (this.u2fFlowType === 'authenticate') {
return 'This device has not been registered with us.';
}
return "There was a problem communicating with your device.";
};
return U2FError;
})();
}).call(window);
if (this.u2fFlowType === 'register') {
return 'This device has already been registered with us.';
}
}
return 'There was a problem communicating with your device.';
}
}

View File

@ -1,98 +1,89 @@
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-else-return, quotes, quote-props, comma-dangle, one-var, one-var-declaration-per-line, max-len */
/* eslint-disable func-names, wrap-iife */
/* global u2f */
/* global U2FError */
/* global U2FUtil */
import _ from 'underscore';
import isU2FSupported from './util';
import U2FError from './error';
// Register U2F (universal 2nd factor) devices for users to authenticate with.
//
// State Flow #1: setup -> in_progress -> registered -> POST to server
// State Flow #2: setup -> in_progress -> error -> setup
(function() {
this.U2FRegister = (function() {
function U2FRegister(container, u2fParams) {
this.container = container;
this.renderNotSupported = this.renderNotSupported.bind(this);
this.renderRegistered = this.renderRegistered.bind(this);
this.renderError = this.renderError.bind(this);
this.renderInProgress = this.renderInProgress.bind(this);
this.renderSetup = this.renderSetup.bind(this);
this.renderTemplate = this.renderTemplate.bind(this);
this.register = this.register.bind(this);
this.start = this.start.bind(this);
this.appId = u2fParams.app_id;
this.registerRequests = u2fParams.register_requests;
this.signRequests = u2fParams.sign_requests;
export default class U2FRegister {
constructor(container, u2fParams) {
this.container = container;
this.renderNotSupported = this.renderNotSupported.bind(this);
this.renderRegistered = this.renderRegistered.bind(this);
this.renderError = this.renderError.bind(this);
this.renderInProgress = this.renderInProgress.bind(this);
this.renderSetup = this.renderSetup.bind(this);
this.renderTemplate = this.renderTemplate.bind(this);
this.register = this.register.bind(this);
this.start = this.start.bind(this);
this.appId = u2fParams.app_id;
this.registerRequests = u2fParams.register_requests;
this.signRequests = u2fParams.sign_requests;
this.templates = {
notSupported: '#js-register-u2f-not-supported',
setup: '#js-register-u2f-setup',
inProgress: '#js-register-u2f-in-progress',
error: '#js-register-u2f-error',
registered: '#js-register-u2f-registered',
};
}
start() {
if (isU2FSupported()) {
return this.renderSetup();
}
return this.renderNotSupported();
}
U2FRegister.prototype.start = function() {
if (U2FUtil.isU2FSupported()) {
return this.renderSetup();
} else {
return this.renderNotSupported();
}
};
register() {
return u2f.register(this.appId, this.registerRequests, this.signRequests, (function (_this) {
return function (response) {
if (response.errorCode) {
const error = new U2FError(response.errorCode, 'register');
return _this.renderError(error);
}
return _this.renderRegistered(JSON.stringify(response));
};
})(this), 10);
}
U2FRegister.prototype.register = function() {
return u2f.register(this.appId, this.registerRequests, this.signRequests, (function(_this) {
return function(response) {
var error;
if (response.errorCode) {
error = new U2FError(response.errorCode, 'register');
return _this.renderError(error);
} else {
return _this.renderRegistered(JSON.stringify(response));
}
};
})(this), 10);
};
renderTemplate(name, params) {
const templateString = $(this.templates[name]).html();
const template = _.template(templateString);
return this.container.html(template(params));
}
// Rendering #
U2FRegister.prototype.templates = {
"notSupported": "#js-register-u2f-not-supported",
"setup": '#js-register-u2f-setup',
"inProgress": '#js-register-u2f-in-progress',
"error": '#js-register-u2f-error',
"registered": '#js-register-u2f-registered'
};
renderSetup() {
this.renderTemplate('setup');
return this.container.find('#js-setup-u2f-device').on('click', this.renderInProgress);
}
U2FRegister.prototype.renderTemplate = function(name, params) {
var template, templateString;
templateString = $(this.templates[name]).html();
template = _.template(templateString);
return this.container.html(template(params));
};
renderInProgress() {
this.renderTemplate('inProgress');
return this.register();
}
U2FRegister.prototype.renderSetup = function() {
this.renderTemplate('setup');
return this.container.find('#js-setup-u2f-device').on('click', this.renderInProgress);
};
renderError(error) {
this.renderTemplate('error', {
error_message: error.message(),
error_code: error.errorCode,
});
return this.container.find('#js-u2f-try-again').on('click', this.renderSetup);
}
U2FRegister.prototype.renderInProgress = function() {
this.renderTemplate('inProgress');
return this.register();
};
renderRegistered(deviceResponse) {
this.renderTemplate('registered');
// Prefer to do this instead of interpolating using Underscore templates
// because of JSON escaping issues.
return this.container.find('#js-device-response').val(deviceResponse);
}
U2FRegister.prototype.renderError = function(error) {
this.renderTemplate('error', {
error_message: error.message(),
error_code: error.errorCode
});
return this.container.find('#js-u2f-try-again').on('click', this.renderSetup);
};
U2FRegister.prototype.renderRegistered = function(deviceResponse) {
this.renderTemplate('registered');
// Prefer to do this instead of interpolating using Underscore templates
// because of JSON escaping issues.
return this.container.find("#js-device-response").val(deviceResponse);
};
U2FRegister.prototype.renderNotSupported = function() {
return this.renderTemplate('notSupported');
};
return U2FRegister;
})();
}).call(window);
renderNotSupported() {
return this.renderTemplate('notSupported');
}
}

View File

@ -1,12 +1,3 @@
/* eslint-disable func-names, space-before-function-paren, wrap-iife */
(function() {
this.U2FUtil = (function() {
function U2FUtil() {}
U2FUtil.isU2FSupported = function() {
return window.u2f;
};
return U2FUtil;
})();
}).call(window);
export default function isU2FSupported() {
return window.u2f;
}

View File

@ -1,7 +1,7 @@
import Cookies from 'js-cookie';
import UserTabs from './user_tabs';
export default function initUserProfile(action) {
function initUserProfile(action) {
// place profile avatars to top
$('.profile-groups-avatars').tooltip({
placement: 'top',
@ -17,3 +17,9 @@ export default function initUserProfile(action) {
$(this).parents('.project-limit-message').remove();
});
}
document.addEventListener('DOMContentLoaded', () => {
const page = $('body').attr('data-page');
const action = page.split(':')[1];
initUserProfile(action);
});

View File

@ -424,7 +424,7 @@ function UsersSelect(currentUser, els) {
}
var isIssueIndex, isMRIndex, page, selected;
page = $('body').data('page');
page = $('body').attr('data-page');
isIssueIndex = page === 'projects:issues:index';
isMRIndex = (page === page && page === 'projects:merge_requests:index');
if ($dropdown.hasClass('js-filter-bulk-update') || $dropdown.hasClass('js-issuable-form-dropdown')) {

View File

@ -1,6 +1,5 @@
/* global Flash */
import '~/lib/utils/datetime_utility';
import Flash from '../../flash';
import MemoryUsage from './mr_widget_memory_usage';
import StatusIcon from './mr_widget_status_icon';
import MRWidgetService from '../services/mr_widget_service';

View File

@ -1,4 +1,4 @@
/* global Flash */
import Flash from '../../../flash';
import statusIcon from '../mr_widget_status_icon';
import MRWidgetAuthor from '../../components/mr_widget_author';
import eventHub from '../../event_hub';

View File

@ -1,5 +1,4 @@
/* global Flash */
import Flash from '../../../flash';
import mrWidgetAuthorTime from '../../components/mr_widget_author_time';
import tooltip from '../../../vue_shared/directives/tooltip';
import loadingIcon from '../../../vue_shared/components/loading_icon.vue';

View File

@ -1,7 +1,7 @@
/* global Flash */
import successSvg from 'icons/_icon_status_success.svg';
import warningSvg from 'icons/_icon_status_warning.svg';
import simplePoll from '~/lib/utils/simple_poll';
import Flash from '../../../flash';
import statusIcon from '../mr_widget_status_icon';
import eventHub from '../../event_hub';

View File

@ -1,4 +1,3 @@
/* global Flash */
import statusIcon from '../mr_widget_status_icon';
import tooltip from '../../../vue_shared/directives/tooltip';
import eventHub from '../../event_hub';
@ -27,12 +26,12 @@ export default {
.then(res => res.json())
.then((res) => {
eventHub.$emit('UpdateWidgetData', res);
new Flash('The merge request can now be merged.', 'notice'); // eslint-disable-line
new window.Flash('The merge request can now be merged.', 'notice'); // eslint-disable-line
$('.merge-request .detail-page-description .title').text(this.mr.title);
})
.catch(() => {
this.isMakingRequest = false;
new Flash('Something went wrong. Please try again.'); // eslint-disable-line
new window.Flash('Something went wrong. Please try again.'); // eslint-disable-line
});
},
},

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