Commit c8afe430 authored by Luke "Jared" Bennett's avatar Luke "Jared" Bennett

Merge branch 'master' into update-droplab-to-webpack-version

parents 8a6becca 37b5b7a5
{
"presets": [
["latest", { "es2015": { "modules": false } }],
"stage-2"
],
"env": {
"coverage": {
"plugins": [
["istanbul", {
"exclude": [
"app/assets/javascripts/droplab/**/*",
"spec/javascripts/**/*"
]
}],
["transform-define", {
"process.env.BABEL_ENV": "coverage"
}]
]
}
}
}
......@@ -19,7 +19,7 @@ before_script:
- source ./scripts/prepare_build.sh
- cp config/gitlab.yml.example config/gitlab.yml
- bundle --version
- '[ "$USE_BUNDLE_INSTALL" != "true" ] || retry bundle install --without postgres production --jobs $(nproc) $FLAGS'
- '[ "$USE_BUNDLE_INSTALL" != "true" ] || retry bundle install --without postgres production --jobs $(nproc) --clean $FLAGS'
- retry gem install knapsack
- '[ "$SETUP_DB" != "true" ] || bundle exec rake db:drop db:create db:schema:load db:migrate add_limits_mysql'
......@@ -206,10 +206,9 @@ rake ee_compat_check:
- /^[\d-]+-stable(-ee)?$/
allow_failure: yes
cache:
key: "ruby233-ee_compat_check_repo"
key: "ee_compat_check_repo"
paths:
- ee_compat_check/repo/
- vendor/ruby
- ee_compat_check/ee-repo/
artifacts:
name: "${CI_JOB_NAME}_${CI_COMIT_REF_NAME}_${CI_COMMIT_SHA}"
when: on_failure
......@@ -277,8 +276,11 @@ rake karma:
stage: test
<<: *use-db
<<: *dedicated-runner
variables:
BABEL_ENV: "coverage"
script:
- bundle exec rake karma
coverage: '/^Statements *: (\d+\.\d+%)/'
artifacts:
name: coverage-javascript
expire_in: 31d
......@@ -310,7 +312,7 @@ bundler:audit:
- master@gitlab/gitlabhq
- master@gitlab/gitlab-ee
script:
- "bundle exec bundle-audit check --update"
- "bundle exec bundle-audit check --update --ignore CVE-2016-4658"
migration paths:
stage: test
......@@ -331,6 +333,7 @@ migration paths:
- bundle install --without postgres production --jobs $(nproc) $FLAGS --retry=3
- bundle exec rake db:drop db:create db:schema:load db:seed_fu
- git checkout $CI_COMMIT_SHA
- bundle install --without postgres production --jobs $(nproc) $FLAGS --retry=3
- source scripts/prepare_build.sh
- bundle exec rake db:migrate
......@@ -343,6 +346,7 @@ coverage:
USE_BUNDLE_INSTALL: "true"
script:
- bundle exec scripts/merge-simplecov
coverage: '/LOC \((\d+\.\d+%)\) covered.$/'
artifacts:
name: coverage
expire_in: 31d
......@@ -389,9 +393,11 @@ trigger_docs:
cache: {}
artifacts: {}
script:
- "curl -X POST -F token=${DOCS_TRIGGER_TOKEN} -F ref=master -F variables[PROJECT]=ce https://gitlab.com/api/v3/projects/1794617/trigger/builds"
- "HTTP_STATUS=$(curl -X POST -F token=${DOCS_TRIGGER_TOKEN} -F ref=master -F variables[PROJECT]=${CI_PROJECT_NAME} --silent --output curl.log --write-out '%{http_code}' https://gitlab.com/api/v3/projects/1794617/trigger/builds)"
- if [ "${HTTP_STATUS}" -ne "201" ]; then echo "Error ${HTTP_STATUS}"; cat curl.log; echo; exit 1; fi
only:
- master@gitlab-org/gitlab-ce
- master@gitlab-org/gitlab-ee
# Notify slack in the end
notify:slack:
......
This diff is collapsed.
......@@ -82,7 +82,7 @@ If a contributor is no longer actively working on a submitted merge request
we can decide that the merge request will be finished by one of our
[Merge request coaches][team] or close the merge request. We make this decision
based on how important the change is for our product vision. If a Merge request
coach is going to finish the merge request we assign the
coach is going to finish the merge request we assign the
~"coach will finish" label.
## Helping others
......@@ -479,8 +479,7 @@ merge request:
1. [Rails](https://github.com/bbatsov/rails-style-guide)
1. [Newlines styleguide][newlines-styleguide]
1. [Testing](doc/development/testing.md)
1. [JavaScript (ES6)](https://github.com/airbnb/javascript)
1. [JavaScript (ES5)](https://github.com/airbnb/javascript/tree/es5-deprecated/es5)
1. [JavaScript styleguide][js-styleguide]
1. [SCSS styleguide][scss-styleguide]
1. [Shell commands](doc/development/shell_commands.md) created by GitLab
contributors to enhance security
......@@ -549,7 +548,8 @@ available at [http://contributor-covenant.org/version/1/1/0/](http://contributor
[rss-naming]: https://github.com/bbatsov/ruby-style-guide/blob/master/README.md#naming
[changelog]: doc/development/changelog.md "Generate a changelog entry"
[doc-styleguide]: doc/development/doc_styleguide.md "Documentation styleguide"
[scss-styleguide]: doc/development/scss_styleguide.md "SCSS styleguide"
[js-styleguide]: doc/development/fe_guide/style_guide_js.md "JavaScript styleguide"
[scss-styleguide]: doc/development/fe_guide/style_guide_scss.md "SCSS styleguide"
[newlines-styleguide]: doc/development/newlines_styleguide.md "Newlines styleguide"
[UX Guide for GitLab]: http://docs.gitlab.com/ce/development/ux_guide/
[license-finder-doc]: doc/development/licensing.md
......
......@@ -327,6 +327,7 @@ group :test do
gem 'test_after_commit', '~> 1.1'
gem 'sham_rack', '~> 1.3.6'
gem 'timecop', '~> 0.8.0'
gem 'concurrent-ruby', '~> 1.0.5'
end
gem 'octokit', '~> 4.6.2'
......
......@@ -128,7 +128,7 @@ GEM
execjs
coffee-script-source (1.10.0)
colorize (0.7.7)
concurrent-ruby (1.0.4)
concurrent-ruby (1.0.5)
connection_pool (2.2.1)
crack (0.4.3)
safe_yaml (~> 1.0.0)
......@@ -304,7 +304,7 @@ GEM
multi_json (~> 1.10)
retriable (~> 1.4)
signet (~> 0.6)
google-protobuf (3.2.0)
google-protobuf (3.2.0.2)
googleauth (0.5.1)
faraday (~> 0.9)
jwt (~> 1.4)
......@@ -868,6 +868,7 @@ DEPENDENCIES
chronic (~> 0.10.2)
chronic_duration (~> 0.10.6)
coffee-rails (~> 4.1.0)
concurrent-ruby (~> 1.0.5)
connection_pool (~> 2.0)
creole (~> 0.5.0)
d3_rails (~> 3.5.0)
......
# GitLab
[![Build status](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/build.svg)](https://gitlab.com/gitlab-org/gitlab-ce/commits/master)
[![CE coverage report](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](https://gitlab-org.gitlab.io/gitlab-ce/coverage-ruby)
[![Overall test coverage](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg)](https://gitlab.com/gitlab-org/gitlab-ce/pipelines)
[![Code Climate](https://codeclimate.com/github/gitlabhq/gitlabhq.svg)](https://codeclimate.com/github/gitlabhq/gitlabhq)
[![Core Infrastructure Initiative Best Practices](https://bestpractices.coreinfrastructure.org/projects/42/badge)](https://bestpractices.coreinfrastructure.org/projects/42)
## Test coverage
- [![Ruby coverage](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=coverage)](https://gitlab-org.gitlab.io/gitlab-ce/coverage-ruby) Ruby
- [![JavaScript coverage](https://gitlab.com/gitlab-org/gitlab-ce/badges/master/coverage.svg?job=rake+karma)](https://gitlab-org.gitlab.io/gitlab-ce/coverage-javascript) JavaScript
## Canonical source
The canonical source of GitLab Community Edition is [hosted on GitLab.com](https://gitlab.com/gitlab-org/gitlab-ce/).
......
<svg width="12" height="15" viewBox="0 0 12 15" xmlns="http://www.w3.org/2000/svg"><path d="M10.267 11.028V5.167c-.028-.728-.318-1.372-.878-1.923-.56-.55-1.194-.85-1.922-.877h-.934V.5l-2.8 2.8 2.8 2.8V4.233h.934a.976.976 0 0 1 .644.29.88.88 0 0 1 .289.644v5.861a1.86 1.86 0 0 0 .933 3.472 1.86 1.86 0 0 0 .934-3.472zM3.733 3.3a1.86 1.86 0 0 0-1.866-1.867 1.86 1.86 0 0 0-.934 3.472v6.123a1.86 1.86 0 0 0 .933 3.472 1.86 1.86 0 0 0 .934-3.472V4.905c.55-.317.933-.914.933-1.605z" fill-rule="nonzero"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><path d="m5 5.563v4.875c1.024.4 1.75 1.397 1.75 2.563 0 1.519-1.231 2.75-2.75 2.75-1.519 0-2.75-1.231-2.75-2.75 0-1.166.726-2.162 1.75-2.563v-4.875c-1.024-.4-1.75-1.397-1.75-2.563 0-1.519 1.231-2.75 2.75-2.75 1.519 0 2.75 1.231 2.75 2.75 0 1.166-.726 2.162-1.75 2.563m-1 8.687c.69 0 1.25-.56 1.25-1.25 0-.69-.56-1.25-1.25-1.25-.69 0-1.25.56-1.25 1.25 0 .69.56 1.25 1.25 1.25m0-10c.69 0 1.25-.56 1.25-1.25 0-.69-.56-1.25-1.25-1.25-.69 0-1.25.56-1.25 1.25 0 .69.56 1.25 1.25 1.25"/><path d="m10.501 2c1.381.001 2.499 1.125 2.499 2.506v5.931c1.024.4 1.75 1.397 1.75 2.563 0 1.519-1.231 2.75-2.75 2.75-1.519 0-2.75-1.231-2.75-2.75 0-1.166.726-2.162 1.75-2.563v-5.931c0-.279-.225-.506-.499-.506v.926c0 .346-.244.474-.569.271l-2.952-1.844c-.314-.196-.325-.507 0-.71l2.952-1.844c.314-.196.569-.081.569.271v.93m1.499 12.25c.69 0 1.25-.56 1.25-1.25 0-.69-.56-1.25-1.25-1.25-.69 0-1.25.56-1.25 1.25 0 .69.56 1.25 1.25 1.25"/></svg>
\ No newline at end of file
/* eslint-disable no-param-reassign, class-methods-use-this */
/* global Pager */
/* global Cookies */
import Cookies from 'js-cookie';
class Activities {
constructor() {
......
/* global Cookies */
import Cookies from 'js-cookie';
import emojiMap from 'emojis/digests.json';
import emojiAliases from 'emojis/aliases.json';
......
......@@ -24,7 +24,7 @@
$('body').on('click', '.js-toggle-button', function(e) {
toggleContainer($(this).closest('.js-toggle-container'));
const targetTag = e.target.tagName.toLowerCase();
const targetTag = e.currentTarget.tagName.toLowerCase();
if (targetTag === 'a' || targetTag === 'button') {
e.preventDefault();
}
......
/* eslint-disable no-param-reassign, comma-dangle */
/* global Api */
require('./template_selector');
((global) => {
class BlobCiYamlSelector extends gl.TemplateSelector {
requestFile(query) {
return Api.gitlabCiYml(query.name, this.requestFileSuccess.bind(this));
}
requestFileSuccess(file) {
return super.requestFileSuccess(file);
}
}
global.BlobCiYamlSelector = BlobCiYamlSelector;
class BlobCiYamlSelectors {
constructor({ editor, $dropdowns } = {}) {
this.editor = editor;
this.$dropdowns = $dropdowns || $('.js-gitlab-ci-yml-selector');
this.initSelectors();
}
initSelectors() {
const editor = this.editor;
this.$dropdowns.each((i, dropdown) => {
const $dropdown = $(dropdown);
return new BlobCiYamlSelector({
editor,
pattern: /(.gitlab-ci.yml)/,
data: $dropdown.data('data'),
wrapper: $dropdown.closest('.js-gitlab-ci-yml-selector-wrap'),
dropdown: $dropdown
});
});
}
}
global.BlobCiYamlSelectors = BlobCiYamlSelectors;
})(window.gl || (window.gl = {}));
/* global Api */
require('./template_selector');
(() => {
const global = window.gl || (window.gl = {});
class BlobDockerfileSelector extends gl.TemplateSelector {
requestFile(query) {
return Api.dockerfileYml(query.name, this.requestFileSuccess.bind(this));
}
requestFileSuccess(file) {
return super.requestFileSuccess(file);
}
}
global.BlobDockerfileSelector = BlobDockerfileSelector;
})();
(() => {
const global = window.gl || (window.gl = {});
class BlobDockerfileSelectors {
constructor({ editor, $dropdowns } = {}) {
this.editor = editor;
this.$dropdowns = $dropdowns || $('.js-dockerfile-selector');
this.initSelectors();
}
initSelectors() {
const editor = this.editor;
this.$dropdowns.each((i, dropdown) => {
const $dropdown = $(dropdown);
return new gl.BlobDockerfileSelector({
editor,
pattern: /(Dockerfile)/,
data: $dropdown.data('data'),
wrapper: $dropdown.closest('.js-dockerfile-selector-wrap'),
dropdown: $dropdown,
});
});
}
}
global.BlobDockerfileSelectors = BlobDockerfileSelectors;
})();
/* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, camelcase, object-shorthand, quotes, comma-dangle, prefer-arrow-callback, no-unused-vars, prefer-template, no-useless-escape, no-alert, max-len */
/* eslint-disable func-names, object-shorthand, prefer-arrow-callback */
/* global Dropzone */
(function() {
this.BlobFileDropzone = (function() {
function BlobFileDropzone(form, method) {
var dropzone, form_dropzone, submitButton;
form_dropzone = form.find('.dropzone');
Dropzone.autoDiscover = false;
dropzone = form_dropzone.dropzone({
autoDiscover: false,
autoProcessQueue: false,
url: form.attr('action'),
// Rails uses a hidden input field for PUT
// http://stackoverflow.com/questions/21056482/how-to-set-method-put-in-form-tag-in-rails
method: method,
clickable: true,
uploadMultiple: false,
paramName: "file",
maxFilesize: gon.max_file_size || 10,
parallelUploads: 1,
maxFiles: 1,
addRemoveLinks: true,
previewsContainer: '.dropzone-previews',
headers: {
"X-CSRF-Token": $("meta[name=\"csrf-token\"]").attr("content")
},
init: function() {
this.on('addedfile', function(file) {
$('.dropzone-alerts').html('').hide();
});
this.on('success', function(header, response) {
window.location.href = response.filePath;
});
this.on('maxfilesexceeded', function(file) {
this.removeFile(file);
});
return this.on('sending', function(file, xhr, formData) {
formData.append('target_branch', form.find('input[name="target_branch"]').val());
formData.append('create_merge_request', form.find('.js-create-merge-request').val());
formData.append('commit_message', form.find('.js-commit-message').val());
});
},
// Override behavior of adding error underneath preview
error: function(file, errorMessage) {
var stripped;
stripped = $("<div/>").html(errorMessage).text();
$('.dropzone-alerts').html('Error uploading file: \"' + stripped + '\"').show();
export default class BlobFileDropzone {
constructor(form, method) {
const formDropzone = form.find('.dropzone');
Dropzone.autoDiscover = false;
const dropzone = formDropzone.dropzone({
autoDiscover: false,
autoProcessQueue: false,
url: form.attr('action'),
// Rails uses a hidden input field for PUT
// http://stackoverflow.com/questions/21056482/how-to-set-method-put-in-form-tag-in-rails
method: method,
clickable: true,
uploadMultiple: false,
paramName: 'file',
maxFilesize: gon.max_file_size || 10,
parallelUploads: 1,
maxFiles: 1,
addRemoveLinks: true,
previewsContainer: '.dropzone-previews',
headers: {
'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content'),
},
init: function () {
this.on('addedfile', function () {
$('.dropzone-alerts').html('').hide();
});
this.on('success', function (header, response) {
window.location.href = response.filePath;
});
this.on('maxfilesexceeded', function (file) {
this.removeFile(file);
}
});
submitButton = form.find('#submit-all')[0];
submitButton.addEventListener('click', function(e) {
e.preventDefault();
e.stopPropagation();
if (dropzone[0].dropzone.getQueuedFiles().length === 0) {
alert("Please select a file");
}
dropzone[0].dropzone.processQueue();
return false;
});
}
});
this.on('sending', function (file, xhr, formData) {
formData.append('target_branch', form.find('input[name="target_branch"]').val());
formData.append('create_merge_request', form.find('.js-create-merge-request').val());
formData.append('commit_message', form.find('.js-commit-message').val());
});
},
// Override behavior of adding error underneath preview
error: function (file, errorMessage) {
const stripped = $('<div/>').html(errorMessage).text();
$('.dropzone-alerts').html(`Error uploading file: "${stripped}"`).show();
this.removeFile(file);
},
});
return BlobFileDropzone;
})();
}).call(window);
const submitButton = form.find('#submit-all')[0];
submitButton.addEventListener('click', function (e) {
e.preventDefault();
e.stopPropagation();
if (dropzone[0].dropzone.getQueuedFiles().length === 0) {
// eslint-disable-next-line no-alert
alert('Please select a file');
}
dropzone[0].dropzone.processQueue();
return false;
});
}
}
/* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-rest-params */
/* global Api */
require('./template_selector');
(function() {
var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
this.BlobGitignoreSelector = (function(superClass) {
extend(BlobGitignoreSelector, superClass);
function BlobGitignoreSelector() {
return BlobGitignoreSelector.__super__.constructor.apply(this, arguments);
}
BlobGitignoreSelector.prototype.requestFile = function(query) {
return Api.gitignoreText(query.name, this.requestFileSuccess.bind(this));
};
return BlobGitignoreSelector;
})(gl.TemplateSelector);
}).call(window);
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-unused-expressions, no-cond-assign, no-sequences, comma-dangle, max-len */
/* global BlobGitignoreSelector */
(function() {
this.BlobGitignoreSelectors = (function() {
function BlobGitignoreSelectors(opts) {
var ref;
this.$dropdowns = (ref = opts.$dropdowns) != null ? ref : $('.js-gitignore-selector'), this.editor = opts.editor;
this.$dropdowns.each((function(_this) {
return function(i, dropdown) {
var $dropdown;
$dropdown = $(dropdown);
return new BlobGitignoreSelector({
pattern: /(.gitignore)/,
data: $dropdown.data('data'),
wrapper: $dropdown.closest('.js-gitignore-selector-wrap'),
dropdown: $dropdown,
editor: _this.editor
});
};
})(this));
}
return BlobGitignoreSelectors;
})();
}).call(window);
/* eslint-disable func-names, space-before-function-paren, max-len, one-var, no-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, prefer-rest-params, comma-dangle */
/* global Api */
require('./template_selector');
(function() {
var extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
this.BlobLicenseSelector = (function(superClass) {
extend(BlobLicenseSelector, superClass);
function BlobLicenseSelector() {
return BlobLicenseSelector.__super__.constructor.apply(this, arguments);
}
BlobLicenseSelector.prototype.requestFile = function(query) {
var data;
data = {
project: this.dropdown.data('project'),
fullname: this.dropdown.data('fullname')
};
return Api.licenseText(query.id, data, this.requestFileSuccess.bind(this));
};
return BlobLicenseSelector;
})(gl.TemplateSelector);
}).call(window);
/* eslint-disable no-unused-vars, no-param-reassign */
/* global BlobLicenseSelector */
((global) => {
class BlobLicenseSelectors {
constructor({ $dropdowns, editor }) {
this.$dropdowns = $('.js-license-selector');
this.editor = editor;
this.$dropdowns.each((i, dropdown) => {
const $dropdown = $(dropdown);
return new BlobLicenseSelector({
editor,
pattern: /^(.+\/)?(licen[sc]e|copying)($|\.)/i,
data: $dropdown.data('data'),
wrapper: $dropdown.closest('.js-license-selector-wrap'),
dropdown: $dropdown,
});
});
}
}
global.BlobLicenseSelectors = BlobLicenseSelectors;
})(window.gl || (window.gl = {}));
/* eslint-disable comma-dangle, object-shorthand, func-names, space-before-function-paren, arrow-parens, no-unused-vars, class-methods-use-this, no-var, consistent-return, no-param-reassign, max-len */
((global) => {
class TemplateSelector {
constructor({ dropdown, data, pattern, wrapper, editor, fileEndpoint, $input } = {}) {
this.onClick = this.onClick.bind(this);
this.dropdown = dropdown;
this.data = data;
this.pattern = pattern;
this.wrapper = wrapper;
this.editor = editor;
this.fileEndpoint = fileEndpoint;
this.$input = $input || $('#file_name');
this.dropdownIcon = $('.fa-chevron-down', this.dropdown);
this.buildDropdown();
this.bindEvents();
this.onFilenameUpdate();
this.autosizeUpdateEvent = document.createEvent('Event');
this.autosizeUpdateEvent.initEvent('autosize:update', true, false);
}
buildDropdown() {
return this.dropdown.glDropdown({
data: this.data,
filterable: true,
selectable: true,
toggleLabel: this.toggleLabel,
search: {
fields: ['name']
},
clicked: this.onClick,
text: function(item) {
return item.name;
}
});
}
bindEvents() {
return this.$input.on('keyup blur', (e) => this.onFilenameUpdate());
}
toggleLabel(item) {
return item.name;
}
onFilenameUpdate() {
var filenameMatches;
if (!this.$input.length) {
return;
}
filenameMatches = this.pattern.test(this.$input.val().trim());
if (!filenameMatches) {
this.wrapper.addClass('hidden');
return;
}
return this.wrapper.removeClass('hidden');
}
onClick(item, el, e) {
e.preventDefault();
return this.requestFile(item);
}
requestFile(item) {
// This `requestFile` method is an abstract method that should
// be added by all subclasses.
}
// To be implemented on the extending class
// e.g.
// Api.gitignoreText item.name, @requestFileSuccess.bind(@)
requestFileSuccess(file, { skipFocus } = {}) {
if (!file) return;
const oldValue = this.editor.getValue();
const newValue = file.content;
this.editor.setValue(newValue, 1);
if (!skipFocus) this.editor.focus();
if (this.editor instanceof jQuery) {
this.editor.get(0).dispatchEvent(this.autosizeUpdateEvent);
}
}
startLoadingSpinner() {
this.dropdownIcon
.addClass('fa-spinner fa-spin')
.removeClass('fa-chevron-down');
}
stopLoadingSpinner() {
this.dropdownIcon
.addClass('fa-chevron-down')
.removeClass('fa-spinner fa-spin');
}
}
global.TemplateSelector = TemplateSelector;
})(window.gl || (window.gl = {}));
/* global Api */
import TemplateSelector from './template_selector';
export default class BlobCiYamlSelector extends TemplateSelector {
requestFile(query) {
return Api.gitlabCiYml(query.name, (file, config) => this.setEditorContent(file, config));
}
}
/* global Api */
import BlobCiYamlSelector from './blob_ci_yaml_selector';
export default class BlobCiYamlSelectors {
constructor({ editor, $dropdowns }) {
this.$dropdowns = $dropdowns || $('.js-gitlab-ci-yml-selector');
this.initSelectors(editor);
}
initSelectors(editor) {
this.$dropdowns.each((i, dropdown) => {
const $dropdown = $(dropdown);
return new BlobCiYamlSelector({
editor,
pattern: /(.gitlab-ci.yml)/,
data: $dropdown.data('data'),
wrapper: $dropdown.closest('.js-gitlab-ci-yml-selector-wrap'),
dropdown: $dropdown,
});
});
}
}
/* global Api */
import TemplateSelector from './template_selector';
export default class BlobDockerfileSelector extends TemplateSelector {
requestFile(query) {
return Api.dockerfileYml(query.name, (file, config) => this.setEditorContent(file, config));
}
}
import BlobDockerfileSelector from './blob_dockerfile_selector';
export default class BlobDockerfileSelectors {
constructor({ editor, $dropdowns }) {
this.editor = editor;
this.$dropdowns = $dropdowns || $('.js-dockerfile-selector');
this.initSelectors();
}
initSelectors() {
const editor = this.editor;
this.$dropdowns.each((i, dropdown) => {
const $dropdown = $(dropdown);
return new BlobDockerfileSelector({
editor,
pattern: /(Dockerfile)/,
data: $dropdown.data('data'),
wrapper: $dropdown.closest('.js-dockerfile-selector-wrap'),
dropdown: $dropdown,
});
});
}
}
/* global Api */
import TemplateSelector from './template_selector';
export default class BlobGitignoreSelector extends TemplateSelector {
requestFile(query) {
return Api.gitignoreText(query.name, (file, config) => this.setEditorContent(file, config));
}
}
import BlobGitignoreSelector from './blob_gitignore_selector';
export default class BlobGitignoreSelectors {
constructor({ editor, $dropdowns }) {
this.$dropdowns = $dropdowns || $('.js-gitignore-selector');
this.editor = editor;
this.initSelectors();
}
initSelectors() {
this.$dropdowns.each((i, dropdown) => {
const $dropdown = $(dropdown);
return new BlobGitignoreSelector({
pattern: /(.gitignore)/,
data: $dropdown.data('data'),
wrapper: $dropdown.closest('.js-gitignore-selector-wrap'),
dropdown: $dropdown,
editor: this.editor,
});
});
}
}
/* global Api */
import TemplateSelector from './template_selector';
export default class BlobLicenseSelector extends TemplateSelector {
requestFile(query) {
const data = {
project: this.dropdown.data('project'),
fullname: this.dropdown.data('fullname'),
};
return Api.licenseText(query.id, data, (file, config) => this.setEditorContent(file, config));
}
}
/* eslint-disable no-unused-vars, no-param-reassign */
import BlobLicenseSelector from './blob_license_selector';
export default class BlobLicenseSelectors {
constructor({ $dropdowns, editor }) {
this.$dropdowns = $dropdowns || $('.js-license-selector');
this.initSelectors(editor);
}
initSelectors(editor) {
this.$dropdowns.each((i, dropdown) => {
const $dropdown = $(dropdown);
return new BlobLicenseSelector({
editor,
pattern: /^(.+\/)?(licen[sc]e|copying)($|\.)/i,
data: $dropdown.data('data'),
wrapper: $dropdown.closest('.js-license-selector-wrap'),
dropdown: $dropdown,
});
});
}
}
/* eslint-disable class-methods-use-this, no-unused-vars */
export default class TemplateSelector {
constructor({ dropdown, data, pattern, wrapper, editor, $input } = {}) {
this.pattern = pattern;
this.editor = editor;
this.dropdown = dropdown;
this.$dropdownContainer = wrapper;
this.$filenameInput = $input || $('#file_name');
this.$dropdownIcon = $('.fa-chevron-down', dropdown);
this.initDropdown(dropdown, data);
this.listenForFilenameInput();
this.renderMatchedDropdown();
this.initAutosizeUpdateEvent();
}
initDropdown(dropdown, data) {
return $(dropdown).glDropdown({
data,
filterable: true,
selectable: true,
toggleLabel: item => item.name,
search: {
fields: ['name'],
},
clicked: (item, el, e) => this.fetchFileTemplate(item, el, e),
text: item => item.name,
});
}
initAutosizeUpdateEvent() {
this.autosizeUpdateEvent = document.createEvent('Event');
this.autosizeUpdateEvent.initEvent('autosize:update', true, false);
}
listenForFilenameInput() {
return this.$filenameInput.on('keyup blur', e => this.renderMatchedDropdown(e));
}
renderMatchedDropdown() {
if (!this.$filenameInput.length) {
return null;
}
const filenameMatches = this.pattern.test(this.$filenameInput.val().trim());
if (!filenameMatches) {
return this.$dropdownContainer.addClass('hidden');
}
return this.$dropdownContainer.removeClass('hidden');
}
fetchFileTemplate(item, el, e) {
e.preventDefault();
return this.requestFile(item);
}
requestFile(item) {
// This `requestFile` method is an abstract method that should
// be added by all subclasses.
}
// To be implemented on the extending class
// e.g. Api.gitlabCiYml(query.name, file => this.setEditorContent(file));
setEditorContent(file, { skipFocus } = {}) {
if (!file) return;
const newValue = file.content;
this.editor.setValue(newValue, 1);
if (!skipFocus) this.editor.focus();
if (this.editor instanceof jQuery) {
this.editor.get(0).dispatchEvent(this.autosizeUpdateEvent);
}
}
startLoadingSpinner() {
this.$dropdownIcon
.addClass('fa-spinner fa-spin')
.removeClass('fa-chevron-down');
}
stopLoadingSpinner() {
this.$dropdownIcon
.addClass('fa-chevron-down')
.removeClass('fa-spinner fa-spin');
}
}
/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, quotes, vars-on-top, no-unused-vars, no-new, max-len */
/* global EditBlob */
/* global NewCommitForm */
import EditBlob from './edit_blob';
import BlobFileDropzone from '../blob/blob_file_dropzone';
$(() => {
const editBlobForm = $('.js-edit-blob-form');
const uploadBlobForm = $('.js-upload-blob-form');
if (editBlobForm.length) {
const urlRoot = editBlobForm.data('relative-url-root');
const assetsPath = editBlobForm.data('assets-prefix');
const blobLanguage = editBlobForm.data('blob-language');
new EditBlob(`${urlRoot}${assetsPath}`, blobLanguage);
new NewCommitForm(editBlobForm);
}
if (uploadBlobForm.length) {
const method = uploadBlobForm.data('method');
new BlobFileDropzone(uploadBlobForm, method);
new NewCommitForm(uploadBlobForm);
window.gl.utils.disableButtonIfEmptyField(
uploadBlobForm.find('.js-commit-message'),
'.btn-upload-file',
);
}
});
/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, quotes, vars-on-top, no-unused-vars, no-new, max-len */
/* global EditBlob */
/* global NewCommitForm */
require('./edit_blob');
(function() {
$(function() {
var url = $(".js-edit-blob-form").data("relative-url-root");
url += $(".js-edit-blob-form").data("assets-prefix");
var blob = new EditBlob(url, $('.js-edit-blob-form').data('blob-language'));
new NewCommitForm($('.js-edit-blob-form'));
});
}).call(window);
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, camelcase, no-param-reassign, quotes, prefer-template, no-new, comma-dangle, one-var, one-var-declaration-per-line, prefer-arrow-callback, no-else-return, no-unused-vars, max-len */
/* global ace */
/* global BlobGitignoreSelectors */
(function() {
var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; };
this.EditBlob = (function() {
function EditBlob(assets_path, ace_mode) {
if (ace_mode == null) {
ace_mode = null;
}
this.editModeLinkClickHandler = bind(this.editModeLinkClickHandler, this);
ace.config.set("modePath", assets_path + "/ace");
ace.config.loadModule("ace/ext/searchbox");
this.editor = ace.edit("editor");
this.editor.focus();
if (ace_mode) {
this.editor.getSession().setMode("ace/mode/" + ace_mode);
}
$('form').submit((function(_this) {
return function() {
return $("#file-content").val(_this.editor.getValue());
};
// Before a form submission, move the content from the Ace editor into the
// submitted textarea
})(this));
this.initModePanesAndLinks();
this.initSoftWrap();
new gl.BlobLicenseSelectors({
editor: this.editor
});
import BlobLicenseSelectors from '../blob/template_selectors/blob_license_selectors';
import BlobGitignoreSelectors from '../blob/template_selectors/blob_gitignore_selectors';
import BlobCiYamlSelectors from '../blob/template_selectors/blob_ci_yaml_selectors';
import BlobDockerfileSelectors from '../blob/template_selectors/blob_dockerfile_selectors';
export default class EditBlob {
constructor(assetsPath, aceMode) {
this.configureAceEditor(aceMode, assetsPath);
this.prepFileContentForSubmit();
this.initModePanesAndLinks();
this.initSoftWrap();
this.initFileSelectors();
}
configureAceEditor(aceMode, assetsPath) {
ace.config.set('modePath', `${assetsPath}/ace`);
ace.config.loadModule('ace/ext/searchbox');
this.editor = ace.edit('editor');
this.editor.focus();
if (aceMode) {
this.editor.getSession().setMode(`ace/mode/${aceMode}`);
}
}
prepFileContentForSubmit() {
$('form').submit(() => {
$('#file-content').val(this.editor.getValue());
});
}
initFileSelectors() {
this.blobTemplateSelectors = [
new BlobLicenseSelectors({
editor: this.editor,
}),
new BlobGitignoreSelectors({
editor: this.editor
});
new gl.BlobCiYamlSelectors({
editor: this.editor
});
new gl.BlobDockerfileSelectors({
editor: this.editor
editor: this.editor,
}),
new BlobCiYamlSelectors({
editor: this.editor,
}),
new BlobDockerfileSelectors({
editor: this.editor,
}),
];
}
initModePanesAndLinks() {
this.$editModePanes = $('.js-edit-mode-pane');
this.$editModeLinks = $('.js-edit-mode a');
this.$editModeLinks.on('click', e => this.editModeLinkClickHandler(e));
}
editModeLinkClickHandler(e) {
e.preventDefault();
const currentLink = $(e.target);
const paneId = currentLink.attr('href');
const currentPane = this.$editModePanes.filter(paneId);
this.$editModeLinks.parent().removeClass('active hover');
currentLink.parent().addClass('active hover');
this.$editModePanes.hide();
currentPane.fadeIn(200);
if (paneId === '#preview') {
this.$toggleButton.hide();
return $.post(currentLink.data('preview-url'), {
content: this.editor.getValue(),
}, (response) => {
currentPane.empty().append(response);
return currentPane.renderGFM();
});
}
EditBlob.prototype.initModePanesAndLinks = function() {
this.$editModePanes = $(".js-edit-mode-pane");
this.$editModeLinks = $(".js-edit-mode a");
return this.$editModeLinks.click(this.editModeLinkClickHandler);
};
EditBlob.prototype.editModeLinkClickHandler = function(event) {
var currentLink, currentPane, paneId;
event.preventDefault();
currentLink = $(event.target);
paneId = currentLink.attr("href");
currentPane = this.$editModePanes.filter(paneId);
this.$editModeLinks.parent().removeClass("active hover");
currentLink.parent().addClass("active hover");
this.$editModePanes.hide();
currentPane.fadeIn(200);
if (paneId === "#preview") {
this.$toggleButton.hide();
return $.post(currentLink.data("preview-url"), {
content: this.editor.getValue()
}, function(response) {
currentPane.empty().append(response);
return currentPane.renderGFM();
});
} else {
this.$toggleButton.show();
return this.editor.focus();
}
};
EditBlob.prototype.initSoftWrap = function() {
this.isSoftWrapped = false;
this.$toggleButton = $('.soft-wrap-toggle');
this.$toggleButton.on('click', this.toggleSoftWrap.bind(this));
};
EditBlob.prototype.toggleSoftWrap = function(e) {
this.isSoftWrapped = !this.isSoftWrapped;
this.$toggleButton.toggleClass('soft-wrap-active', this.isSoftWrapped);
this.editor.getSession().setUseWrapMode(this.isSoftWrapped);
};
return EditBlob;
})();
}).call(window);
this.$toggleButton.show();
return this.editor.focus();
}
initSoftWrap() {
this.isSoftWrapped = false;
this.$toggleButton = $('.soft-wrap-toggle');
this.$toggleButton.on('click', () => this.toggleSoftWrap());
}
toggleSoftWrap() {
this.isSoftWrapped = !this.isSoftWrapped;
this.$toggleButton.toggleClass('soft-wrap-active', this.isSoftWrapped);
this.editor.getSession().setUseWrapMode(this.isSoftWrapped);
}
}
/* eslint-disable one-var, quote-props, comma-dangle, space-before-function-paren */
/* global Vue */
/* global BoardService */
import Vue from 'vue';
import VueResource from 'vue-resource';
import FilteredSearchBoards from './filtered_search_boards';
import eventHub from './eventhub';
window.Vue = require('vue');
window.Vue.use(require('vue-resource'));
require('./models/issue');
require('./models/label');
require('./models/list');
......@@ -24,6 +23,8 @@ require('./components/new_list_dropdown');
require('./components/modal/index');
require('../vue_shared/vue_resource_interceptor');
Vue.use(VueResource);
$(() => {
const $boardApp = document.getElementById('board-app');
const Store = gl.issueBoards.BoardsStore;
......
/* eslint-disable comma-dangle, space-before-function-paren, one-var */
/* global Vue */
/* global Sortable */
import Vue from 'vue';
import boardBlankState from './board_blank_state';
require('./board_delete');
......
/* global ListLabel */
/* global Cookies */
import Cookies from 'js-cookie';
const Store = gl.issueBoards.BoardsStore;
export default {
......
/* global Vue */
require('./issue_card_inner');
const Store = gl.issueBoards.BoardsStore;
......
/* eslint-disable comma-dangle, space-before-function-paren, no-alert */
/* global Vue */
import Vue from 'vue';
(() => {
window.gl = window.gl || {};
......
/* eslint-disable comma-dangle, space-before-function-paren, max-len */
/* global Vue */
/* global Sortable */
import Vue from 'vue';
import boardNewIssue from './board_new_issue';
import boardCard from './board_card';
......@@ -48,7 +48,7 @@ import boardCard from './board_card';
this.list.getIssues(false);
}
if (this.scrollHeight() > this.listHeight()) {
if (this.scrollHeight() > Math.ceil(this.listHeight())) {
this.showCount = true;
} else {
this.showCount = false;
......
/* eslint-disable comma-dangle, space-before-function-paren, no-new */
/* global Vue */
/* global IssuableContext */
/* global MilestoneSelect */
/* global LabelsSelect */
/* global Sidebar */
import Vue from 'vue';
require('./sidebar/remove_issue');
(() => {
......
/* global Vue */
import Vue from 'vue';
import eventHub from '../eventhub';
(() => {
......
/* global Vue */
import Vue from 'vue';
(() => {
const ModalStore = gl.issueBoards.ModalStore;
......@@ -30,7 +31,7 @@
if (this.activeTab === 'selected') {
obj.title = 'You haven\'t selected any issues yet';
obj.content = `
Go back to <strong>All issues</strong> and select some issues
Go back to <strong>Open issues</strong> and select some issues
to add to your board.
`;
}
......@@ -59,7 +60,7 @@
class="btn btn-default"
@click="changeTab('all')"
v-if="activeTab === 'selected'">
All issues
Open issues
</button>
</div>
</div>
......
......@@ -14,8 +14,10 @@ export default {
this.filteredSearch = new FilteredSearchBoards(this.store);
this.filteredSearch.removeTokens();
this.filteredSearch.handleInputPlaceholder();
this.filteredSearch.toggleClearSearchButton();
},
beforeDestroy() {
destroyed() {
this.filteredSearch.cleanup();
FilteredSearchContainer.container = document;
this.store.path = '';
......
/* eslint-disable no-new */
/* global Vue */
/* global Flash */
import Vue from 'vue';
require('./lists_dropdown');
(() => {
......
/* global Vue */
/* global ListIssue */
import Vue from 'vue';
import queryData from '../../utils/query_data';
require('./header');
......@@ -64,7 +65,15 @@ require('./empty_state');
},
filter: {
handler() {
this.loadIssues(true);
if (this.$el.tagName) {
this.page = 1;
this.filterLoading = true;
this.loadIssues(true)
.then(() => {
this.filterLoading = false;
});
}
},
deep: true,
},
......@@ -115,6 +124,9 @@ require('./empty_state');
return this.activeTab === 'selected' && this.selectedIssues.length === 0;
},
},
created() {
this.page = 1;
},
components: {
'modal-header': gl.issueBoards.ModalHeader,
'modal-list': gl.issueBoards.ModalList,
......@@ -135,14 +147,14 @@ require('./empty_state');
:image="blankStateImage"
:issue-link-base="issueLinkBase"
:root-path="rootPath"
v-if="!loading && showList"></modal-list>
v-if="!loading && showList && !filterLoading"></modal-list>
<empty-state
v-if="showEmptyState"
:image="blankStateImage"
:new-issue-path="newIssuePath"></empty-state>
<section
class="add-issues-list text-center"
v-if="loading">
v-if="loading || filterLoading">
<div class="add-issues-list-loading">
<i class="fa fa-spinner fa-spin"></i>
</div>
......
/* global Vue */
/* global ListIssue */
/* global bp */
import Vue from 'vue';
(() => {
const ModalStore = gl.issueBoards.ModalStore;
......
/* global Vue */
import Vue from 'vue';
(() => {
const ModalStore = gl.issueBoards.ModalStore;
......
/* global Vue */
import Vue from 'vue';
(() => {
const ModalStore = gl.issueBoards.ModalStore;
......@@ -23,7 +24,7 @@
href="#"
role="button"
@click.prevent="changeTab('all')">
All issues
Open issues
<span class="badge">
{{ issuesCount }}
</span>
......
/* eslint-disable no-new */
/* global Vue */
/* global Flash */
import Vue from 'vue';
(() => {
const Store = gl.issueBoards.BoardsStore;
......
......@@ -28,6 +28,8 @@ export default class FilteredSearchBoards extends gl.FilteredSearchManager {
[].forEach.call(tokens, (el) => {
el.parentNode.removeChild(el);
});
this.filteredSearchInput.value = '';
}
updateTokens() {
......
/* global Vue */
/* global dateFormat */
import Vue from 'vue';
Vue.filter('due-date', (value) => {
const date = new Date(value);
return dateFormat(date, 'mmm d, yyyy', true);
......
/* eslint-disable no-unused-vars, space-before-function-paren, arrow-body-style, arrow-parens, comma-dangle, max-len */
/* global Vue */
/* global ListLabel */
/* global ListMilestone */
/* global ListUser */
import Vue from 'vue';
class ListIssue {
constructor (obj) {
this.globalId = obj.id;
......
/* eslint-disable space-before-function-paren, comma-dangle, no-param-reassign, camelcase, max-len, no-unused-vars */
/* global Vue */
import Vue from 'vue';
class BoardService {
constructor (root, bulkUpdatePath, boardId) {
......
/* eslint-disable comma-dangle, space-before-function-paren, one-var, no-shadow, dot-notation, max-len */
/* global Cookies */
/* global List */
import Cookies from 'js-cookie';
(() => {
window.gl = window.gl || {};
window.gl.issueBoards = window.gl.issueBoards || {};
......
......@@ -15,6 +15,7 @@
searchTerm: '',
loading: false,
loadingNewPage: false,
filterLoading: false,
page: 1,
perPage: 50,
filter: {
......
/* eslint-disable no-param-reassign */
import Vue from 'vue';
import VueResource from 'vue-resource';
import CommitPipelinesTable from './pipelines_table';
window.Vue = require('vue');
window.Vue.use(require('vue-resource'));
Vue.use(VueResource);
/**
* Commits View > Pipelines Tab > Pipelines Table.
......
/* eslint-disable no-new*/
/* global Flash */
import Vue from 'vue';
import PipelinesTableComponent from '../../vue_shared/components/pipelines_table';
import PipelinesService from '../../vue_pipelines_index/services/pipelines_service';
import PipelineStore from '../../vue_pipelines_index/stores/pipelines_store';
import eventHub from '../../vue_pipelines_index/event_hub';
import EmptyState from '../../vue_pipelines_index/components/empty_state';
import ErrorState from '../../vue_pipelines_index/components/error_state';
import '../../lib/utils/common_utils';
import '../../vue_shared/vue_resource_interceptor';
......@@ -22,6 +22,8 @@ import '../../vue_shared/vue_resource_interceptor';
export default Vue.component('pipelines-table', {
components: {
'pipelines-table-component': PipelinesTableComponent,
'error-state': ErrorState,
'empty-state': EmptyState,
},
/**
......@@ -36,12 +38,24 @@ export default Vue.component('pipelines-table', {
return {
endpoint: pipelinesTableData.endpoint,
helpPagePath: pipelinesTableData.helpPagePath,
store,
state: store.state,
isLoading: false,
hasError: false,
};
},
computed: {
shouldRenderErrorState() {
return this.hasError && !this.isLoading;
},
shouldRenderEmptyState() {
return !this.state.pipelines.length && !this.isLoading;
},
},
/**
* When the component is about to be mounted, tell the service to fetch the data
*
......@@ -80,26 +94,25 @@ export default Vue.component('pipelines-table', {
this.isLoading = false;
})
.catch(() => {
this.hasError = true;
this.isLoading = false;
new Flash('An error occurred while fetching the pipelines, please reload the page again.');
});
},
},
template: `
<div class="pipelines">
<div class="content-list pipelines">
<div class="realtime-loading" v-if="isLoading">
<i class="fa fa-spinner fa-spin"></i>
</div>
<div class="blank-state blank-state-no-icon"
v-if="!isLoading && state.pipelines.length === 0">
<h2 class="blank-state-title js-blank-state-title">
No pipelines to show
</h2>
</div>
<empty-state
v-if="shouldRenderEmptyState"
:help-page-path="helpPagePath" />
<error-state v-if="shouldRenderErrorState" />
<div class="table-holder pipelines"
<div class="table-holder"
v-if="!isLoading && state.pipelines.length > 0">
<pipelines-table-component
:pipelines="state.pipelines"
......
// ECMAScript polyfills
import 'core-js/fn/array/find';
import 'core-js/fn/array/from';
import 'core-js/fn/object/assign';
import 'core-js/fn/promise';
import 'core-js/fn/string/code-point-at';
import 'core-js/fn/string/from-code-point';
import 'core-js/fn/symbol';
// Browser polyfills
import './polyfills/custom_event';
......
/* eslint-disable no-param-reassign */
/* global Vue */
import Vue from 'vue';
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
......
/* eslint-disable no-param-reassign */
/* global Vue */
import Vue from 'vue';
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
......
/* eslint-disable no-param-reassign */
/* global Vue */
import Vue from 'vue';
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
......
/* eslint-disable no-param-reassign */
/* global Vue */
import Vue from 'vue';
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
......
/* eslint-disable no-param-reassign */
/* global Vue */
import Vue from 'vue';
((global) => {
global.cycleAnalytics = global.cycleAnalytics || {};
......
/* global Vue */
/* global Cookies */
/* global Flash */
window.Vue = require('vue');
window.Cookies = require('js-cookie');
import Vue from 'vue';
import Cookies from 'js-cookie';
require('./components/stage_code_component');
require('./components/stage_issue_component');
require('./components/stage_plan_component');
......
......@@ -33,11 +33,7 @@ class Diff {
handleClickUnfold(e) {
const $target = $(e.target);
// current babel config relies on iterators implementation, so we cannot simply do:
// const [oldLineNumber, newLineNumber] = this.lineNumbers($target.parent());
const ref = this.lineNumbers($target.parent());
const oldLineNumber = ref[0];
const newLineNumber = ref[1];
const [oldLineNumber, newLineNumber] = this.lineNumbers($target.parent());
const offset = newLineNumber - oldLineNumber;
const bottom = $target.hasClass('js-unfold-bottom');
let since;
......@@ -105,10 +101,11 @@ class Diff {
}
lineNumbers(line) {
if (!line.children().length) {
const children = line.find('.diff-line-num').toArray();
if (children.length !== 2) {
return [0, 0];
}
return line.find('.diff-line-num').map((i, elm) => parseInt($(elm).data('linenumber'), 10));
return children.map(elm => parseInt($(elm).data('linenumber'), 10) || 0);
}
highlightSelectedLine() {
......
/* eslint-disable comma-dangle, object-shorthand, func-names, no-else-return, quotes, no-lonely-if, max-len */
/* global CommentsStore */
const Vue = require('vue');
import Vue from 'vue';
(() => {
const CommentAndResolveBtn = Vue.extend({
......
/* global CommentsStore Cookies notes */
/* global CommentsStore */
/* global notes */
import Vue from 'vue';
import collapseIcon from '../icons/collapse_icon.svg';
......
/* eslint-disable comma-dangle, object-shorthand, func-names, no-else-return, guard-for-in, no-restricted-syntax, one-var, space-before-function-paren, no-lonely-if, no-continue, brace-style, max-len, quotes */
/* global DiscussionMixins */
/* global CommentsStore */
const Vue = require('vue');
import Vue from 'vue';
(() => {
const JumpToDiscussion = Vue.extend({
......
/* global Vue */
/* global CommentsStore */
import Vue from 'vue';
(() => {
const NewIssueForDiscussion = Vue.extend({
props: {
......
......@@ -2,7 +2,8 @@
/* global CommentsStore */
/* global ResolveService */
/* global Flash */
const Vue = require('vue');
import Vue from 'vue';
(() => {
const ResolveBtn = Vue.extend({
......
/* eslint-disable comma-dangle, object-shorthand, func-names, no-param-reassign */
/* global DiscussionMixins */
/* global CommentsStore */
const Vue = require('vue');
import Vue from 'vue';
((w) => {
w.ResolveCount = Vue.extend({
......
......@@ -2,7 +2,7 @@
/* global CommentsStore */
/* global ResolveService */
const Vue = require('vue');
import Vue from 'vue';
(() => {
const ResolveDiscussionBtn = Vue.extend({
......
/* eslint-disable func-names, comma-dangle, new-cap, no-new, max-len */
/* global Vue */
/* global ResolveCount */
const Vue = require('vue');
import Vue from 'vue';
require('./models/discussion');
require('./models/note');
require('./stores/comments');
......
/* eslint-disable space-before-function-paren, camelcase, guard-for-in, no-restricted-syntax, no-unused-vars, max-len */
/* global Vue */
/* global NoteModel */
import Vue from 'vue';
class DiscussionModel {
constructor (discussionId) {
this.id = discussionId;
......
......@@ -2,10 +2,13 @@
/* global Flash */
/* global CommentsStore */
const Vue = window.Vue = require('vue');
window.Vue.use(require('vue-resource'));
import Vue from 'vue';
import VueResource from 'vue-resource';
require('../../vue_shared/vue_resource_interceptor');
Vue.use(VueResource);
(() => {
window.gl = window.gl || {};
......
/* eslint-disable object-shorthand, func-names, camelcase, no-restricted-syntax, guard-for-in, comma-dangle, max-len, no-param-reassign */
/* global Vue */
/* global DiscussionModel */
import Vue from 'vue';
((w) => {
w.CommentsStore = {
state: {},
......
import PrometheusGraph from './monitoring/prometheus_graph'; // TODO: Maybe Make this a bundle
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-arrow-callback, wrap-iife, no-shadow, consistent-return, one-var, one-var-declaration-per-line, camelcase, default-case, no-new, quotes, no-duplicate-case, no-case-declarations, no-fallthrough, max-len */
/* global UsernameValidator */
/* global ActiveTabMemoizer */
......@@ -42,9 +41,9 @@ import GroupsList from './groups_list';
import ProjectsList from './projects_list';
import MiniPipelineGraph from './mini_pipeline_graph_dropdown';
import BlobLinePermalinkUpdater from './blob/blob_line_permalink_updater';
import UserCallout from './user_callout';
const ShortcutsBlob = require('./shortcuts_blob');
const UserCallout = require('./user_callout');
(function() {
var Dispatcher;
......@@ -329,8 +328,6 @@ const UserCallout = require('./user_callout');
case 'ci:lints:show':
new gl.CILintEditor();
break;
case 'projects:environments:metrics':
new PrometheusGraph();
case 'users:show':
new UserCallout();
break;
......
......@@ -132,7 +132,7 @@ class DueDateSelect {
const selectedDateValue = this.datePayload[this.abilityName].due_date;
const displayedDateStyle = this.displayedDate !== 'No due date' ? 'bold' : 'no-value';
this.$loading.fadeIn();
this.$loading.removeClass('hidden').fadeIn();
if (isDropdown) {
this.$dropdown.trigger('loading.gl.dropdown');
......
......@@ -14,6 +14,7 @@ export default {
class="btn external_url"
:href="externalUrl"
target="_blank"
rel="noopener noreferrer"
title="Environment external URL">
<i class="fa fa-external-link" aria-hidden="true"></i>
</a>
......
......@@ -38,6 +38,7 @@
gl.FilteredSearchDropdownManager.addWordToInput(this.filter, value, true);
}
this.resetFilters();
this.dismissDropdown();
this.dispatchInputEvent();
}
......@@ -107,7 +108,7 @@
const hook = this.getCurrentHook();
if (hook) {
const data = hook.list.data;
const data = hook.list.data || [];
const results = data.map((o) => {
const updated = o;
updated.droplab_hidden = false;
......
......@@ -40,6 +40,8 @@ import FilteredSearchContainer from './container';
this.unselectEditTokensWrapper = this.unselectEditTokens.bind(this);
this.editTokenWrapper = this.editToken.bind(this);
this.tokenChange = this.tokenChange.bind(this);
this.addInputContainerFocusWrapper = this.addInputContainerFocus.bind(this);
this.removeInputContainerFocusWrapper = this.removeInputContainerFocus.bind(this);
this.filteredSearchInputForm = this.filteredSearchInput.form;
this.filteredSearchInputForm.addEventListener('submit', this.handleFormSubmit);
......@@ -51,11 +53,13 @@ import FilteredSearchContainer from './container';
this.filteredSearchInput.addEventListener('keyup', this.checkForBackspaceWrapper);
this.filteredSearchInput.addEventListener('click', this.tokenChange);
this.filteredSearchInput.addEventListener('keyup', this.tokenChange);
this.filteredSearchInput.addEventListener('focus', this.addInputContainerFocusWrapper);
this.tokensContainer.addEventListener('click', FilteredSearchManager.selectToken);
this.tokensContainer.addEventListener('dblclick', this.editTokenWrapper);
this.clearSearchButton.addEventListener('click', this.clearSearchWrapper);
document.addEventListener('click', gl.FilteredSearchVisualTokens.unselectTokens);
document.addEventListener('click', this.unselectEditTokensWrapper);
document.addEventListener('click', this.removeInputContainerFocusWrapper);
document.addEventListener('keydown', this.removeSelectedTokenWrapper);
}
......@@ -69,11 +73,13 @@ import FilteredSearchContainer from './container';
this.filteredSearchInput.removeEventListener('keyup', this.checkForBackspaceWrapper);
this.filteredSearchInput.removeEventListener('click', this.tokenChange);
this.filteredSearchInput.removeEventListener('keyup', this.tokenChange);
this.filteredSearchInput.removeEventListener('focus', this.addInputContainerFocusWrapper);
this.tokensContainer.removeEventListener('click', FilteredSearchManager.selectToken);
this.tokensContainer.removeEventListener('dblclick', this.editTokenWrapper);
this.clearSearchButton.removeEventListener('click', this.clearSearchWrapper);
document.removeEventListener('click', gl.FilteredSearchVisualTokens.unselectTokens);
document.removeEventListener('click', this.unselectEditTokensWrapper);
document.removeEventListener('click', this.removeInputContainerFocusWrapper);
document.removeEventListener('keydown', this.removeSelectedTokenWrapper);
}
......@@ -124,6 +130,26 @@ import FilteredSearchContainer from './container';
}
}
addInputContainerFocus() {
const inputContainer = this.filteredSearchInput.closest('.filtered-search-input-container');
if (inputContainer) {
inputContainer.classList.add('focus');
}
}
removeInputContainerFocus(e) {
const inputContainer = this.filteredSearchInput.closest('.filtered-search-input-container');
const isElementInFilteredSearch = inputContainer && inputContainer.contains(e.target);
const isElementInDynamicFilterDropdown = e.target.closest('.filter-dropdown') !== null;
const isElementInStaticFilterDropdown = e.target.closest('ul[data-dropdown]') !== null;
if (!isElementInFilteredSearch && !isElementInDynamicFilterDropdown &&
!isElementInStaticFilterDropdown && inputContainer) {
inputContainer.classList.remove('focus');
}
}
static selectToken(e) {
const button = e.target.closest('.selectable');
......@@ -358,7 +384,7 @@ import FilteredSearchContainer from './container';
paths.push(`search=${sanitized}`);
}
const parameterizedUrl = `?scope=all&utf8=&${paths.join('&')}`;
const parameterizedUrl = `?scope=all&utf8=%E2%9C%93&${paths.join('&')}`;
if (this.updateObject) {
this.updateObject(parameterizedUrl);
......
/* global Vue */
import Vue from 'vue';
import stopwatchSvg from 'icons/_icon_stopwatch.svg';
require('../../../lib/utils/pretty_time');
......
/* global Vue */
import Vue from 'vue';
require('../../../lib/utils/pretty_time');
(() => {
......
/* global Vue */
import Vue from 'vue';
(() => {
Vue.component('time-tracking-estimate-only-pane', {
name: 'time-tracking-estimate-only-pane',
......
/* global Vue */
import Vue from 'vue';
(() => {
Vue.component('time-tracking-help-state', {
name: 'time-tracking-help-state',
......
/* global Vue */
import Vue from 'vue';
(() => {
Vue.component('time-tracking-no-tracking-pane', {
name: 'time-tracking-no-tracking-pane',
......
/* global Vue */
import Vue from 'vue';
(() => {
Vue.component('time-tracking-spent-only-pane', {
name: 'time-tracking-spent-only-pane',
......
/* global Vue */
import Vue from 'vue';
require('./help_state');
require('./collapsed_state');
......
/* global Vue */
import Vue from 'vue';
import VueResource from 'vue-resource';
window.Vue = require('vue');
window.Vue.use(require('vue-resource'));
require('./components/time_tracker');
require('../../smart_interval');
require('../../subbable_resource');
Vue.use(VueResource);
(() => {
/* This Vue instance represents what will become the parent instance for the
* sidebar. It will be responsible for managing `issuable` state and propagating
......
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-new, comma-dangle, quotes, prefer-arrow-callback, consistent-return, one-var, no-var, one-var-declaration-per-line, no-underscore-dangle, max-len */
/* global UsersSelect */
/* global Cookies */
/* global bp */
import Cookies from 'js-cookie';
(function() {
this.IssuableContext = (function() {
function IssuableContext(currentUser) {
......
......@@ -2,6 +2,7 @@
/* global Flash */
require('./flash');
require('~/lib/utils/text_utility');
require('vendor/jquery.waitforimages');
require('./task_list');
......@@ -50,20 +51,21 @@ class Issue {
success: function(data, textStatus, jqXHR) {
if ('id' in data) {
$(document).trigger('issuable:change');
const currentTotal = Number($('.issue_counter').text());
let total = Number($('.issue_counter').text().replace(/[^\d]/, ''));
if (isClose) {
$('a.btn-close').addClass('hidden');
$('a.btn-reopen').removeClass('hidden');
$('div.status-box-closed').removeClass('hidden');
$('div.status-box-open').addClass('hidden');
$('.issue_counter').text(currentTotal - 1);
total -= 1;
} else {
$('a.btn-reopen').addClass('hidden');
$('a.btn-close').removeClass('hidden');
$('div.status-box-closed').addClass('hidden');
$('div.status-box-open').removeClass('hidden');
$('.issue_counter').text(currentTotal + 1);
total += 1;
}
$('.issue_counter').text(gl.text.addDelimiter(total));
} else {
new Flash(issueFailMessage, 'alert');
}
......
......@@ -76,7 +76,7 @@
if (!selected.length) {
data[abilityName].label_ids = [''];
}
$loading.fadeIn();
$loading.removeClass('hidden').fadeIn();
$dropdown.trigger('loading.gl.dropdown');
return $.ajax({
type: 'PUT',
......
import httpStatusCodes from './http_status';
/**
* Polling utility for handling realtime updates.
* Service for vue resouce and method need to be provided as props
*
* @example
* new poll({
* resource: resource,
* method: 'name',
* data: {page: 1, scope: 'all'},
* successCallback: () => {},
* errorCallback: () => {},
* }).makeRequest();
*
* this.service = new BoardsService(endpoint);
* new poll({
* resource: this.service,
* method: 'get',
* data: {page: 1, scope: 'all'},
* successCallback: () => {},
* errorCallback: () => {},
* }).makeRequest();
*
*
* 1. Checks for response and headers before start polling
* 2. Interval is provided by `Poll-Interval` header.
* 3. If `Poll-Interval` is -1, we stop polling
* 4. If HTTP response is 200, we poll.
* 5. If HTTP response is different from 200, we stop polling.
*
*/
export default class Poll {
constructor(options = {}) {
this.options = options;
this.options.data = options.data || {};
this.intervalHeader = 'POLL-INTERVAL';
this.timeoutID = null;
this.canPoll = true;
}
checkConditions(response) {
const headers = gl.utils.normalizeHeaders(response.headers);
const pollInterval = headers[this.intervalHeader];
if (pollInterval > 0 && response.status === httpStatusCodes.OK && this.canPoll) {
this.timeoutID = setTimeout(() => {
this.makeRequest();
}, pollInterval);
}
this.options.successCallback(response);
}
makeRequest() {
const { resource, method, data, errorCallback } = this.options;
return resource[method](data)
.then(response => this.checkConditions(response))
.catch(error => errorCallback(error));
}
/**
* Stops the polling recursive chain
* and guarantees if the timeout is already running it won't make another request by
* cancelling the previously established timeout.
*/
stop() {
this.canPoll = false;
clearTimeout(this.timeoutID);
}
}
/* 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 bp */
/* global Cookies */
/* global Flash */
/* global ConfirmDangerModal */
/* global Aside */
......@@ -24,7 +23,6 @@ import './extensions/array';
window.jQuery = jQuery;
window.$ = jQuery;
window._ = _;
window.Cookies = Cookies;
window.Pikaday = Pikaday;
window.Dropzone = Dropzone;
window.Sortable = Sortable;
......@@ -49,15 +47,6 @@ import { installGlEmojiElement } from './behaviors/gl_emoji';
installGlEmojiElement();
// blob
import './blob/blob_ci_yaml';
import './blob/blob_dockerfile_selector';
import './blob/blob_dockerfile_selectors';
import './blob/blob_file_dropzone';
import './blob/blob_gitignore_selector';
import './blob/blob_gitignore_selectors';
import './blob/blob_license_selector';
import './blob/blob_license_selectors';
import './blob/template_selector';
import './blob/create_branch_dropdown';
import './blob/target_branch_dropdown';
......
/* eslint-disable comma-dangle, quote-props, no-useless-computed-key, object-shorthand, no-new, no-param-reassign, max-len */
/* global Vue */
/* global ace */
/* global Flash */
import Vue from 'vue';
((global) => {
global.mergeConflicts = global.mergeConflicts || {};
......
/* eslint-disable no-param-reassign, comma-dangle */
/* global Vue */
import Vue from 'vue';
((global) => {
global.mergeConflicts = global.mergeConflicts || {};
......
/* eslint-disable no-param-reassign, comma-dangle */
/* global Vue */
import Vue from 'vue';
((global) => {
global.mergeConflicts = global.mergeConflicts || {};
......
/* eslint-disable comma-dangle, object-shorthand, no-param-reassign, camelcase, no-nested-ternary, no-continue, max-len */
/* global Cookies */
/* global Vue */
import Vue from 'vue';
import Cookies from 'js-cookie';
((global) => {
global.mergeConflicts = global.mergeConflicts || {};
......
/* eslint-disable new-cap, comma-dangle, no-new */
/* global Vue */
/* global Flash */
window.Vue = require('vue');
import Vue from 'vue';
require('./merge_conflict_store');
require('./merge_conflict_service');
require('./mixins/line_conflict_utils');
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment