Merge branch 'master' of gitlab.com:gitlab-org/gitlab-ce
This commit is contained in:
commit
3f01f05bde
|
@ -1,7 +1,9 @@
|
|||
/builds/
|
||||
/coverage/
|
||||
/coverage-javascript/
|
||||
/node_modules/
|
||||
/public/
|
||||
/tmp/
|
||||
/vendor/
|
||||
/builds/
|
||||
karma.config.js
|
||||
webpack.config.js
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
],
|
||||
"rules": {
|
||||
"filenames/match-regex": [2, "^[a-z0-9_]+(.js)?$"],
|
||||
"no-multiple-empty-lines": ["error", { "max": 1 }]
|
||||
"no-multiple-empty-lines": ["error", { "max": 1 }],
|
||||
"import/no-extraneous-dependencies": "off",
|
||||
"import/no-unresolved": "off"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -107,11 +107,13 @@ setup-test-env:
|
|||
<<: *dedicated-runner
|
||||
stage: prepare
|
||||
script:
|
||||
- bundle exec rake gitlab:assets:compile 2>/dev/null
|
||||
- npm install
|
||||
- bundle exec rake gitlab:assets:compile
|
||||
- bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init'
|
||||
artifacts:
|
||||
expire_in: 7d
|
||||
paths:
|
||||
- node_modules
|
||||
- public/assets
|
||||
- tmp/tests
|
||||
|
||||
|
@ -232,7 +234,7 @@ spinach 9 10 ruby21: *spinach-knapsack-ruby21
|
|||
script:
|
||||
- bundle exec $CI_BUILD_NAME
|
||||
|
||||
rubocop:
|
||||
rubocop:
|
||||
<<: *ruby-static-analysis
|
||||
<<: *dedicated-runner
|
||||
stage: test
|
||||
|
@ -291,18 +293,17 @@ rake db:seed_fu:
|
|||
paths:
|
||||
- log/development.log
|
||||
|
||||
teaspoon:
|
||||
karma:
|
||||
cache:
|
||||
paths:
|
||||
- vendor/ruby
|
||||
- node_modules/
|
||||
- node_modules
|
||||
stage: test
|
||||
<<: *use-db
|
||||
<<: *dedicated-runner
|
||||
script:
|
||||
- npm install
|
||||
- npm link istanbul
|
||||
- bundle exec rake teaspoon
|
||||
- bundle exec rake karma
|
||||
artifacts:
|
||||
name: coverage-javascript
|
||||
expire_in: 31d
|
||||
|
@ -444,7 +445,7 @@ pages:
|
|||
<<: *dedicated-runner
|
||||
dependencies:
|
||||
- coverage
|
||||
- teaspoon
|
||||
- karma
|
||||
- lint:javascript:report
|
||||
script:
|
||||
- mv public/ .public/
|
||||
|
|
|
@ -17,6 +17,7 @@ AllCops:
|
|||
# Exclude some GitLab files
|
||||
Exclude:
|
||||
- 'vendor/**/*'
|
||||
- 'node_modules/**/*'
|
||||
- 'db/*'
|
||||
- 'db/fixtures/**/*'
|
||||
- 'tmp/**/*'
|
||||
|
|
|
@ -88,6 +88,27 @@ contributing to GitLab.
|
|||
|
||||
Please see the [UX Guide for GitLab].
|
||||
|
||||
## Release retrospective and kickoff
|
||||
|
||||
### Retrospective
|
||||
|
||||
After each release (usually on the 22nd of each month), we have a retrospective
|
||||
call where we discuss what went well, what went wrong, and what we can improve
|
||||
for the next release. The [retrospective notes] are public and you are invited
|
||||
to comment them.
|
||||
If you're interested, you can even join the [retrospective call][retro-kickoff-call].
|
||||
|
||||
### Kickoff
|
||||
|
||||
Before working on the next release (usually on the 8th of each month), we have a
|
||||
kickoff call to explain what we expect to ship in the next release. The
|
||||
[kickoff notes] are public and you are invited to comment them.
|
||||
If you're interested, you can even join the [kickoff call][retro-kickoff-call].
|
||||
|
||||
[retrospective notes]: https://docs.google.com/document/d/1nEkM_7Dj4bT21GJy0Ut3By76FZqCfLBmFQNVThmW2TY/edit?usp=sharing
|
||||
[kickoff notes]: https://docs.google.com/document/d/1ElPkZ90A8ey_iOkTvUs_ByMlwKK6NAB2VOK5835wYK0/edit?usp=sharing
|
||||
[retro-kickoff-call]: https://gitlab.zoom.us/j/918821206
|
||||
|
||||
## Issue tracker
|
||||
|
||||
To get support for your particular problem please use the
|
||||
|
|
11
Gemfile
11
Gemfile
|
@ -7,7 +7,6 @@ gem 'rails-deprecated_sanitizer', '~> 1.0.3'
|
|||
gem 'responders', '~> 2.0'
|
||||
|
||||
gem 'sprockets', '~> 3.7.0'
|
||||
gem 'sprockets-es6', '~> 0.9.2'
|
||||
|
||||
# Default values for AR models
|
||||
gem 'default_value_for', '~> 3.0.0'
|
||||
|
@ -109,7 +108,7 @@ gem 'org-ruby', '~> 0.9.12'
|
|||
gem 'creole', '~> 0.5.0'
|
||||
gem 'wikicloth', '0.8.1'
|
||||
gem 'asciidoctor', '~> 1.5.2'
|
||||
gem 'asciidoctor-plantuml', '0.0.6'
|
||||
gem 'asciidoctor-plantuml', '0.0.7'
|
||||
gem 'rouge', '~> 2.0'
|
||||
gem 'truncato', '~> 0.7.8'
|
||||
|
||||
|
@ -219,10 +218,12 @@ gem 'oj', '~> 2.17.4'
|
|||
gem 'chronic', '~> 0.10.2'
|
||||
gem 'chronic_duration', '~> 0.10.6'
|
||||
|
||||
gem 'webpack-rails', '~> 0.9.9'
|
||||
gem 'rack-proxy', '~> 0.6.0'
|
||||
|
||||
gem 'sass-rails', '~> 5.0.6'
|
||||
gem 'coffee-rails', '~> 4.1.0'
|
||||
gem 'uglifier', '~> 2.7.2'
|
||||
gem 'gitlab-turbolinks-classic', '~> 2.5', '>= 2.5.6'
|
||||
|
||||
gem 'addressable', '~> 2.3.8'
|
||||
gem 'bootstrap-sass', '~> 3.3.0'
|
||||
|
@ -292,13 +293,9 @@ group :development, :test do
|
|||
gem 'capybara-screenshot', '~> 1.0.0'
|
||||
gem 'poltergeist', '~> 1.9.0'
|
||||
|
||||
gem 'teaspoon', '~> 1.1.0'
|
||||
gem 'teaspoon-jasmine', '~> 2.2.0'
|
||||
|
||||
gem 'spring', '~> 1.7.0'
|
||||
gem 'spring-commands-rspec', '~> 1.0.4'
|
||||
gem 'spring-commands-spinach', '~> 1.1.0'
|
||||
gem 'spring-commands-teaspoon', '~> 0.0.2'
|
||||
|
||||
gem 'rubocop', '~> 0.46.0', require: false
|
||||
gem 'rubocop-rspec', '~> 1.9.1', require: false
|
||||
|
|
31
Gemfile.lock
31
Gemfile.lock
|
@ -54,7 +54,7 @@ GEM
|
|||
faraday_middleware-multi_json (~> 0.0)
|
||||
oauth2 (~> 1.0)
|
||||
asciidoctor (1.5.3)
|
||||
asciidoctor-plantuml (0.0.6)
|
||||
asciidoctor-plantuml (0.0.7)
|
||||
asciidoctor (~> 1.5)
|
||||
ast (2.3.0)
|
||||
attr_encrypted (3.0.3)
|
||||
|
@ -72,10 +72,6 @@ GEM
|
|||
descendants_tracker (~> 0.0.4)
|
||||
ice_nine (~> 0.11.0)
|
||||
thread_safe (~> 0.3, >= 0.3.1)
|
||||
babel-source (5.8.35)
|
||||
babel-transpiler (0.7.0)
|
||||
babel-source (>= 4.0, < 6)
|
||||
execjs (~> 2.0)
|
||||
babosa (1.0.2)
|
||||
base32 (0.3.2)
|
||||
bcrypt (3.1.11)
|
||||
|
@ -266,8 +262,6 @@ GEM
|
|||
mime-types (>= 1.16, < 3)
|
||||
posix-spawn (~> 0.3)
|
||||
gitlab-markup (1.5.1)
|
||||
gitlab-turbolinks-classic (2.5.6)
|
||||
coffee-rails
|
||||
gitlab_omniauth-ldap (1.2.1)
|
||||
net-ldap (~> 0.9)
|
||||
omniauth (~> 1.0)
|
||||
|
@ -548,6 +542,8 @@ GEM
|
|||
rack (>= 1.1)
|
||||
rack-protection (1.5.3)
|
||||
rack
|
||||
rack-proxy (0.6.0)
|
||||
rack
|
||||
rack-test (0.6.3)
|
||||
rack (>= 1.0)
|
||||
rails (4.2.7.1)
|
||||
|
@ -735,15 +731,9 @@ GEM
|
|||
spring (>= 0.9.1)
|
||||
spring-commands-spinach (1.1.0)
|
||||
spring (>= 0.9.1)
|
||||
spring-commands-teaspoon (0.0.2)
|
||||
spring (>= 0.9.1)
|
||||
sprockets (3.7.0)
|
||||
concurrent-ruby (~> 1.0)
|
||||
rack (> 1, < 3)
|
||||
sprockets-es6 (0.9.2)
|
||||
babel-source (>= 5.8.11)
|
||||
babel-transpiler
|
||||
sprockets (>= 3.0.0)
|
||||
sprockets-rails (3.1.1)
|
||||
actionpack (>= 4.0)
|
||||
activesupport (>= 4.0)
|
||||
|
@ -761,10 +751,6 @@ GEM
|
|||
sys-filesystem (1.1.6)
|
||||
ffi
|
||||
sysexits (1.2.0)
|
||||
teaspoon (1.1.5)
|
||||
railties (>= 3.2.5, < 6)
|
||||
teaspoon-jasmine (2.2.0)
|
||||
teaspoon (>= 1.0.0)
|
||||
temple (0.7.7)
|
||||
test_after_commit (1.1.0)
|
||||
activerecord (>= 3.2)
|
||||
|
@ -816,6 +802,8 @@ GEM
|
|||
webmock (1.21.0)
|
||||
addressable (>= 2.3.6)
|
||||
crack (>= 0.3.2)
|
||||
webpack-rails (0.9.9)
|
||||
rails (>= 3.2.0)
|
||||
websocket-driver (0.6.3)
|
||||
websocket-extensions (>= 0.1.0)
|
||||
websocket-extensions (0.1.2)
|
||||
|
@ -841,7 +829,7 @@ DEPENDENCIES
|
|||
allocations (~> 1.0)
|
||||
asana (~> 0.4.0)
|
||||
asciidoctor (~> 1.5.2)
|
||||
asciidoctor-plantuml (= 0.0.6)
|
||||
asciidoctor-plantuml (= 0.0.7)
|
||||
attr_encrypted (~> 3.0.0)
|
||||
awesome_print (~> 1.2.0)
|
||||
babosa (~> 1.0.2)
|
||||
|
@ -891,7 +879,6 @@ DEPENDENCIES
|
|||
github-linguist (~> 4.7.0)
|
||||
gitlab-flowdock-git-hook (~> 1.0.1)
|
||||
gitlab-markup (~> 1.5.1)
|
||||
gitlab-turbolinks-classic (~> 2.5, >= 2.5.6)
|
||||
gitlab_omniauth-ldap (~> 1.2.1)
|
||||
gollum-lib (~> 4.2)
|
||||
gollum-rugged_adapter (~> 0.4.2)
|
||||
|
@ -955,6 +942,7 @@ DEPENDENCIES
|
|||
rack-attack (~> 4.4.1)
|
||||
rack-cors (~> 0.4.0)
|
||||
rack-oauth2 (~> 1.2.1)
|
||||
rack-proxy (~> 0.6.0)
|
||||
rails (= 4.2.7.1)
|
||||
rails-deprecated_sanitizer (~> 1.0.3)
|
||||
rainbow (~> 2.1.0)
|
||||
|
@ -996,14 +984,10 @@ DEPENDENCIES
|
|||
spring (~> 1.7.0)
|
||||
spring-commands-rspec (~> 1.0.4)
|
||||
spring-commands-spinach (~> 1.1.0)
|
||||
spring-commands-teaspoon (~> 0.0.2)
|
||||
sprockets (~> 3.7.0)
|
||||
sprockets-es6 (~> 0.9.2)
|
||||
stackprof (~> 0.2.10)
|
||||
state_machines-activerecord (~> 0.4.0)
|
||||
sys-filesystem (~> 1.1.6)
|
||||
teaspoon (~> 1.1.0)
|
||||
teaspoon-jasmine (~> 2.2.0)
|
||||
test_after_commit (~> 1.1)
|
||||
thin (~> 1.7.0)
|
||||
timecop (~> 0.8.0)
|
||||
|
@ -1019,6 +1003,7 @@ DEPENDENCIES
|
|||
vmstat (~> 2.3.0)
|
||||
web-console (~> 2.0)
|
||||
webmock (~> 1.21.0)
|
||||
webpack-rails (~> 0.9.9)
|
||||
wikicloth (= 0.8.1)
|
||||
|
||||
BUNDLED WITH
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, wrap-iife, one-var, no-var, one-var-declaration-per-line, no-unused-vars, no-else-return, prefer-arrow-callback, camelcase, quotes, comma-dangle, max-len */
|
||||
/* global Turbolinks */
|
||||
|
||||
(function() {
|
||||
this.Admin = (function() {
|
||||
|
@ -42,10 +41,10 @@
|
|||
return $('.change-owner-link').show();
|
||||
});
|
||||
$('li.project_member').bind('ajax:success', function() {
|
||||
return Turbolinks.visit(location.href);
|
||||
return gl.utils.refreshCurrentPage();
|
||||
});
|
||||
$('li.group_member').bind('ajax:success', function() {
|
||||
return Turbolinks.visit(location.href);
|
||||
return gl.utils.refreshCurrentPage();
|
||||
});
|
||||
showBlacklistType = function() {
|
||||
if ($("input[name='blacklist_type']:checked").val() === 'file') {
|
||||
|
|
|
@ -1,4 +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 */
|
||||
/* 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 */
|
||||
/* global bp */
|
||||
/* global Cookies */
|
||||
/* global Flash */
|
||||
|
@ -6,65 +6,60 @@
|
|||
/* global AwardsHandler */
|
||||
/* global Aside */
|
||||
|
||||
// This is a manifest file that'll be compiled into including all the files listed below.
|
||||
// Add new JavaScript code in separate files in this directory and they'll automatically
|
||||
// be included in the compiled file accessible from http://example.com/assets/application.js
|
||||
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
||||
// the compiled file.
|
||||
//
|
||||
/*= require jquery2 */
|
||||
/*= require jquery-ui/autocomplete */
|
||||
/*= require jquery-ui/datepicker */
|
||||
/*= require jquery-ui/draggable */
|
||||
/*= require jquery-ui/effect-highlight */
|
||||
/*= require jquery-ui/sortable */
|
||||
/*= require jquery_ujs */
|
||||
/*= require jquery.endless-scroll */
|
||||
/*= require jquery.highlight */
|
||||
/*= require jquery.waitforimages */
|
||||
/*= require jquery.atwho */
|
||||
/*= require jquery.scrollTo */
|
||||
/*= require jquery.turbolinks */
|
||||
/*= require js.cookie */
|
||||
/*= require turbolinks */
|
||||
/*= require autosave */
|
||||
/*= require bootstrap/affix */
|
||||
/*= require bootstrap/alert */
|
||||
/*= require bootstrap/button */
|
||||
/*= require bootstrap/collapse */
|
||||
/*= require bootstrap/dropdown */
|
||||
/*= require bootstrap/modal */
|
||||
/*= require bootstrap/scrollspy */
|
||||
/*= require bootstrap/tab */
|
||||
/*= require bootstrap/transition */
|
||||
/*= require bootstrap/tooltip */
|
||||
/*= require bootstrap/popover */
|
||||
/*= require select2 */
|
||||
/*= require underscore */
|
||||
/*= require dropzone */
|
||||
/*= require mousetrap */
|
||||
/*= require mousetrap/pause */
|
||||
/*= require shortcuts */
|
||||
/*= require shortcuts_navigation */
|
||||
/*= require shortcuts_dashboard_navigation */
|
||||
/*= require shortcuts_issuable */
|
||||
/*= require shortcuts_network */
|
||||
/*= require jquery.nicescroll */
|
||||
/*= require date.format */
|
||||
/*= require_directory ./behaviors */
|
||||
/*= require_directory ./blob */
|
||||
/*= require_directory ./templates */
|
||||
/*= require_directory ./commit */
|
||||
/*= require_directory ./extensions */
|
||||
/*= require_directory ./lib/utils */
|
||||
/*= require_directory ./u2f */
|
||||
/*= require_directory ./droplab */
|
||||
/*= require_directory . */
|
||||
/*= require fuzzaldrin-plus */
|
||||
/*= require es6-promise.auto */
|
||||
function requireAll(context) { return context.keys().map(context); }
|
||||
|
||||
window.$ = window.jQuery = require('jquery');
|
||||
require('jquery-ui/ui/autocomplete');
|
||||
require('jquery-ui/ui/datepicker');
|
||||
require('jquery-ui/ui/draggable');
|
||||
require('jquery-ui/ui/effect-highlight');
|
||||
require('jquery-ui/ui/sortable');
|
||||
require('jquery-ujs');
|
||||
require('vendor/jquery.endless-scroll');
|
||||
require('vendor/jquery.highlight');
|
||||
require('vendor/jquery.waitforimages');
|
||||
require('vendor/jquery.caret');
|
||||
require('vendor/jquery.atwho');
|
||||
require('vendor/jquery.scrollTo');
|
||||
window.Cookies = require('vendor/js.cookie');
|
||||
require('./autosave');
|
||||
require('bootstrap/js/affix');
|
||||
require('bootstrap/js/alert');
|
||||
require('bootstrap/js/button');
|
||||
require('bootstrap/js/collapse');
|
||||
require('bootstrap/js/dropdown');
|
||||
require('bootstrap/js/modal');
|
||||
require('bootstrap/js/scrollspy');
|
||||
require('bootstrap/js/tab');
|
||||
require('bootstrap/js/transition');
|
||||
require('bootstrap/js/tooltip');
|
||||
require('bootstrap/js/popover');
|
||||
require('select2/select2.js');
|
||||
window._ = require('underscore');
|
||||
window.Dropzone = require('dropzone');
|
||||
require('mousetrap');
|
||||
require('mousetrap/plugins/pause/mousetrap-pause');
|
||||
require('./shortcuts');
|
||||
require('./shortcuts_navigation');
|
||||
require('./shortcuts_dashboard_navigation');
|
||||
require('./shortcuts_issuable');
|
||||
require('./shortcuts_network');
|
||||
require('vendor/jquery.nicescroll');
|
||||
requireAll(require.context('./behaviors', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./blob', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./templates', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./commit', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./extensions', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./lib/utils', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./u2f', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./droplab', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('.', false, /^\.\/(?!application\.js).*\.(js|es6)$/));
|
||||
require('vendor/fuzzaldrin-plus');
|
||||
window.ES6Promise = require('vendor/es6-promise.auto');
|
||||
window.ES6Promise.polyfill();
|
||||
|
||||
(function () {
|
||||
document.addEventListener('page:fetch', function () {
|
||||
document.addEventListener('beforeunload', function () {
|
||||
// Unbind scroll events
|
||||
$(document).off('scroll');
|
||||
// Close any open tooltips
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, no-var, prefer-arrow-callback, consistent-return, one-var, one-var-declaration-per-line, no-unused-vars, no-else-return, prefer-template, quotes, comma-dangle, no-param-reassign, no-void, brace-style, no-underscore-dangle, no-return-assign, camelcase */
|
||||
/* global Cookies */
|
||||
|
||||
var emojiAliases = require('emoji-aliases');
|
||||
|
||||
(function() {
|
||||
this.AwardsHandler = (function() {
|
||||
var FROM_SENTENCE_REGEX = /(?:, and | and |, )/; // For separating lists produced by ruby's Array#toSentence
|
||||
function AwardsHandler() {
|
||||
this.aliases = gl.emojiAliases();
|
||||
this.aliases = emojiAliases;
|
||||
$(document).off('click', '.js-add-award').on('click', '.js-add-award', (function(_this) {
|
||||
return function(e) {
|
||||
e.stopPropagation();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, consistent-return, max-len */
|
||||
/* global autosize */
|
||||
|
||||
/*= require autosize */
|
||||
var autosize = require('vendor/autosize');
|
||||
|
||||
(function() {
|
||||
$(function() {
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
// "Meta+Enter" (Mac) or "Ctrl+Enter" (Linux/Windows) key combination, the form
|
||||
// is submitted.
|
||||
//
|
||||
/*= require extensions/jquery */
|
||||
require('../extensions/jquery');
|
||||
|
||||
//
|
||||
// ### Example Markup
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
// When called on a form with input fields with the `required` attribute, the
|
||||
// form's submit button will be disabled until all required fields have values.
|
||||
//
|
||||
/*= require extensions/jquery */
|
||||
require('../extensions/jquery');
|
||||
|
||||
//
|
||||
// ### Example Markup
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
/* eslint-disable no-param-reassign, comma-dangle */
|
||||
/* global Api */
|
||||
|
||||
/*= require blob/template_selector */
|
||||
require('./template_selector');
|
||||
|
||||
((global) => {
|
||||
class BlobCiYamlSelector extends gl.TemplateSelector {
|
||||
requestFile(query) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* global Api */
|
||||
/*= require blob/template_selector */
|
||||
|
||||
require('./template_selector');
|
||||
|
||||
(() => {
|
||||
const global = window.gl || (window.gl = {});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* 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 blob/template_selector */
|
||||
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; },
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* 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 blob/template_selector */
|
||||
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; },
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/* global EditBlob */
|
||||
/* global NewCommitForm */
|
||||
|
||||
/*= require_tree . */
|
||||
require('./edit_blob');
|
||||
|
||||
(function() {
|
||||
$(function() {
|
||||
|
|
|
@ -1,23 +1,27 @@
|
|||
/* eslint-disable one-var, quote-props, comma-dangle, space-before-function-paren */
|
||||
/* eslint-disable one-var, quote-props, comma-dangle, space-before-function-paren, import/newline-after-import, no-multi-spaces, max-len */
|
||||
/* global Vue */
|
||||
/* global BoardService */
|
||||
|
||||
//= require vue
|
||||
//= require vue-resource
|
||||
//= require Sortable
|
||||
//= require_tree ./models
|
||||
//= require_tree ./stores
|
||||
//= require_tree ./services
|
||||
//= require_tree ./mixins
|
||||
//= require_tree ./filters
|
||||
//= require ./components/board
|
||||
//= require ./components/board_sidebar
|
||||
//= require ./components/new_list_dropdown
|
||||
//= require ./vue_resource_interceptor
|
||||
function requireAll(context) { return context.keys().map(context); }
|
||||
|
||||
window.Vue = require('vue');
|
||||
window.Vue.use(require('vue-resource'));
|
||||
window.Sortable = require('vendor/Sortable');
|
||||
requireAll(require.context('./models', true, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./stores', true, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./services', true, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./mixins', true, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./filters', true, /^\.\/.*\.(js|es6)$/));
|
||||
require('./components/board');
|
||||
require('./components/board_sidebar');
|
||||
require('./components/new_list_dropdown');
|
||||
require('./components/modal/index');
|
||||
require('./vue_resource_interceptor');
|
||||
|
||||
$(() => {
|
||||
const $boardApp = document.getElementById('board-app');
|
||||
const Store = gl.issueBoards.BoardsStore;
|
||||
const ModalStore = gl.issueBoards.ModalStore;
|
||||
|
||||
window.gl = window.gl || {};
|
||||
|
||||
|
@ -31,7 +35,8 @@ $(() => {
|
|||
el: $boardApp,
|
||||
components: {
|
||||
'board': gl.issueBoards.Board,
|
||||
'board-sidebar': gl.issueBoards.BoardSidebar
|
||||
'board-sidebar': gl.issueBoards.BoardSidebar,
|
||||
'board-add-issues-modal': gl.issueBoards.IssuesModal,
|
||||
},
|
||||
data: {
|
||||
state: Store.state,
|
||||
|
@ -40,6 +45,8 @@ $(() => {
|
|||
boardId: $boardApp.dataset.boardId,
|
||||
disabled: $boardApp.dataset.disabled === 'true',
|
||||
issueLinkBase: $boardApp.dataset.issueLinkBase,
|
||||
rootPath: $boardApp.dataset.rootPath,
|
||||
bulkUpdatePath: $boardApp.dataset.bulkUpdatePath,
|
||||
detailIssue: Store.detail
|
||||
},
|
||||
computed: {
|
||||
|
@ -48,7 +55,7 @@ $(() => {
|
|||
},
|
||||
},
|
||||
created () {
|
||||
gl.boardService = new BoardService(this.endpoint, this.boardId);
|
||||
gl.boardService = new BoardService(this.endpoint, this.bulkUpdatePath, this.boardId);
|
||||
},
|
||||
mounted () {
|
||||
Store.disabled = this.disabled;
|
||||
|
@ -59,8 +66,6 @@ $(() => {
|
|||
|
||||
if (list.type === 'done') {
|
||||
list.position = Infinity;
|
||||
} else if (list.type === 'backlog') {
|
||||
list.position = -1;
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -73,7 +78,7 @@ $(() => {
|
|||
});
|
||||
|
||||
gl.IssueBoardsSearch = new Vue({
|
||||
el: '#js-boards-search',
|
||||
el: document.getElementById('js-boards-search'),
|
||||
data: {
|
||||
filters: Store.state.filters
|
||||
},
|
||||
|
@ -81,4 +86,27 @@ $(() => {
|
|||
gl.issueBoards.newListDropdownInit();
|
||||
}
|
||||
});
|
||||
|
||||
gl.IssueBoardsModalAddBtn = new Vue({
|
||||
mixins: [gl.issueBoards.ModalMixins],
|
||||
el: document.getElementById('js-add-issues-btn'),
|
||||
data: {
|
||||
modal: ModalStore.store,
|
||||
store: Store.state,
|
||||
},
|
||||
computed: {
|
||||
disabled() {
|
||||
return Store.shouldAddBlankState();
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<button
|
||||
class="btn btn-create pull-right prepend-left-10 has-tooltip"
|
||||
type="button"
|
||||
:disabled="disabled"
|
||||
@click="toggleModal(true)">
|
||||
Add issues
|
||||
</button>
|
||||
`,
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,9 +2,9 @@
|
|||
/* global Vue */
|
||||
/* global Sortable */
|
||||
|
||||
//= require ./board_blank_state
|
||||
//= require ./board_delete
|
||||
//= require ./board_list
|
||||
require('./board_blank_state');
|
||||
require('./board_delete');
|
||||
require('./board_list');
|
||||
|
||||
(() => {
|
||||
const Store = gl.issueBoards.BoardsStore;
|
||||
|
@ -22,7 +22,8 @@
|
|||
props: {
|
||||
list: Object,
|
||||
disabled: Boolean,
|
||||
issueLinkBase: String
|
||||
issueLinkBase: String,
|
||||
rootPath: String,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
/* eslint-disable comma-dangle, space-before-function-paren, dot-notation */
|
||||
/* global Vue */
|
||||
|
||||
require('./issue_card_inner');
|
||||
|
||||
(() => {
|
||||
const Store = gl.issueBoards.BoardsStore;
|
||||
|
||||
|
@ -9,12 +11,16 @@
|
|||
|
||||
gl.issueBoards.BoardCard = Vue.extend({
|
||||
template: '#js-board-list-card',
|
||||
components: {
|
||||
'issue-card-inner': gl.issueBoards.IssueCardInner,
|
||||
},
|
||||
props: {
|
||||
list: Object,
|
||||
issue: Object,
|
||||
issueLinkBase: String,
|
||||
disabled: Boolean,
|
||||
index: Number
|
||||
index: Number,
|
||||
rootPath: String,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
@ -28,31 +34,6 @@
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
filterByLabel (label, e) {
|
||||
let labelToggleText = label.title;
|
||||
const labelIndex = Store.state.filters['label_name'].indexOf(label.title);
|
||||
$(e.target).tooltip('hide');
|
||||
|
||||
if (labelIndex === -1) {
|
||||
Store.state.filters['label_name'].push(label.title);
|
||||
$('.labels-filter').prepend(`<input type="hidden" name="label_name[]" value="${label.title}" />`);
|
||||
} else {
|
||||
Store.state.filters['label_name'].splice(labelIndex, 1);
|
||||
labelToggleText = Store.state.filters['label_name'][0];
|
||||
$(`.labels-filter input[name="label_name[]"][value="${label.title}"]`).remove();
|
||||
}
|
||||
|
||||
const selectedLabels = Store.state.filters['label_name'];
|
||||
if (selectedLabels.length === 0) {
|
||||
labelToggleText = 'Label';
|
||||
} else if (selectedLabels.length > 1) {
|
||||
labelToggleText = `${selectedLabels[0]} + ${selectedLabels.length - 1} more`;
|
||||
}
|
||||
|
||||
$('.labels-filter .dropdown-toggle-text').text(labelToggleText);
|
||||
|
||||
Store.updateFiltersUrl();
|
||||
},
|
||||
mouseDown () {
|
||||
this.showDetail = true;
|
||||
},
|
||||
|
@ -71,6 +52,7 @@
|
|||
Store.detail.issue = {};
|
||||
} else {
|
||||
Store.detail.issue = this.issue;
|
||||
Store.detail.list = this.list;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
/* global Vue */
|
||||
/* global Sortable */
|
||||
|
||||
//= require ./board_card
|
||||
//= require ./board_new_issue
|
||||
require('./board_card');
|
||||
require('./board_new_issue');
|
||||
|
||||
(() => {
|
||||
const Store = gl.issueBoards.BoardsStore;
|
||||
|
@ -23,6 +23,7 @@
|
|||
issues: Array,
|
||||
loading: Boolean,
|
||||
issueLinkBase: String,
|
||||
rootPath: String,
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
$(this.$refs.submitButton).enable();
|
||||
|
||||
Store.detail.issue = issue;
|
||||
Store.detail.list = this.list;
|
||||
})
|
||||
.catch(() => {
|
||||
// Need this because our jQuery very kindly disables buttons on ALL form submissions
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
/* global LabelsSelect */
|
||||
/* global Sidebar */
|
||||
|
||||
require('./sidebar/remove_issue');
|
||||
|
||||
(() => {
|
||||
const Store = gl.issueBoards.BoardsStore;
|
||||
|
||||
|
@ -18,7 +20,8 @@
|
|||
data() {
|
||||
return {
|
||||
detail: Store.detail,
|
||||
issue: {}
|
||||
issue: {},
|
||||
list: {},
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -36,6 +39,7 @@
|
|||
}
|
||||
|
||||
this.issue = this.detail.issue;
|
||||
this.list = this.detail.list;
|
||||
},
|
||||
deep: true
|
||||
},
|
||||
|
@ -60,6 +64,9 @@
|
|||
new LabelsSelect();
|
||||
new Sidebar();
|
||||
gl.Subscription.bindAll('.subscription');
|
||||
}
|
||||
},
|
||||
components: {
|
||||
removeBtn: gl.issueBoards.RemoveIssueBtn,
|
||||
},
|
||||
});
|
||||
})();
|
||||
|
|
|
@ -0,0 +1,111 @@
|
|||
/* global Vue */
|
||||
(() => {
|
||||
const Store = gl.issueBoards.BoardsStore;
|
||||
|
||||
window.gl = window.gl || {};
|
||||
window.gl.issueBoards = window.gl.issueBoards || {};
|
||||
|
||||
gl.issueBoards.IssueCardInner = Vue.extend({
|
||||
props: {
|
||||
issue: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
issueLinkBase: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
list: {
|
||||
type: Object,
|
||||
required: false,
|
||||
},
|
||||
rootPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
showLabel(label) {
|
||||
if (!this.list) return true;
|
||||
|
||||
return !this.list.label || label.id !== this.list.label.id;
|
||||
},
|
||||
filterByLabel(label, e) {
|
||||
let labelToggleText = label.title;
|
||||
const labelIndex = Store.state.filters.label_name.indexOf(label.title);
|
||||
$(e.currentTarget).tooltip('hide');
|
||||
|
||||
if (labelIndex === -1) {
|
||||
Store.state.filters.label_name.push(label.title);
|
||||
$('.labels-filter').prepend(`<input type="hidden" name="label_name[]" value="${label.title}" />`);
|
||||
} else {
|
||||
Store.state.filters.label_name.splice(labelIndex, 1);
|
||||
labelToggleText = Store.state.filters.label_name[0];
|
||||
$(`.labels-filter input[name="label_name[]"][value="${label.title}"]`).remove();
|
||||
}
|
||||
|
||||
const selectedLabels = Store.state.filters.label_name;
|
||||
if (selectedLabels.length === 0) {
|
||||
labelToggleText = 'Label';
|
||||
} else if (selectedLabels.length > 1) {
|
||||
labelToggleText = `${selectedLabels[0]} + ${selectedLabels.length - 1} more`;
|
||||
}
|
||||
|
||||
$('.labels-filter .dropdown-toggle-text').text(labelToggleText);
|
||||
|
||||
Store.updateFiltersUrl();
|
||||
},
|
||||
labelStyle(label) {
|
||||
return {
|
||||
backgroundColor: label.color,
|
||||
color: label.textColor,
|
||||
};
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<div>
|
||||
<h4 class="card-title">
|
||||
<i
|
||||
class="fa fa-eye-slash confidential-icon"
|
||||
v-if="issue.confidential"></i>
|
||||
<a
|
||||
:href="issueLinkBase + '/' + issue.id"
|
||||
:title="issue.title">
|
||||
{{ issue.title }}
|
||||
</a>
|
||||
</h4>
|
||||
<div class="card-footer">
|
||||
<span
|
||||
class="card-number"
|
||||
v-if="issue.id">
|
||||
#{{ issue.id }}
|
||||
</span>
|
||||
<a
|
||||
class="card-assignee has-tooltip"
|
||||
:href="rootPath + issue.assignee.username"
|
||||
:title="'Assigned to ' + issue.assignee.name"
|
||||
v-if="issue.assignee"
|
||||
data-container="body">
|
||||
<img
|
||||
class="avatar avatar-inline s20"
|
||||
:src="issue.assignee.avatar"
|
||||
width="20"
|
||||
height="20"
|
||||
:alt="'Avatar for ' + issue.assignee.name" />
|
||||
</a>
|
||||
<button
|
||||
class="label color-label has-tooltip"
|
||||
v-for="label in issue.labels"
|
||||
type="button"
|
||||
v-if="showLabel(label)"
|
||||
@click="filterByLabel(label, $event)"
|
||||
:style="labelStyle(label)"
|
||||
:title="label.description"
|
||||
data-container="body">
|
||||
{{ label.title }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,70 @@
|
|||
/* global Vue */
|
||||
(() => {
|
||||
const ModalStore = gl.issueBoards.ModalStore;
|
||||
|
||||
gl.issueBoards.ModalEmptyState = Vue.extend({
|
||||
mixins: [gl.issueBoards.ModalMixins],
|
||||
data() {
|
||||
return ModalStore.store;
|
||||
},
|
||||
props: {
|
||||
image: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
newIssuePath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
contents() {
|
||||
const obj = {
|
||||
title: 'You haven\'t added any issues to your project yet',
|
||||
content: `
|
||||
An issue can be a bug, a todo or a feature request that needs to be
|
||||
discussed in a project. Besides, issues are searchable and filterable.
|
||||
`,
|
||||
};
|
||||
|
||||
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
|
||||
to add to your board.
|
||||
`;
|
||||
}
|
||||
|
||||
return obj;
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<section class="empty-state">
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-sm-6 col-sm-push-6">
|
||||
<aside class="svg-content" v-html="image"></aside>
|
||||
</div>
|
||||
<div class="col-xs-12 col-sm-6 col-sm-pull-6">
|
||||
<div class="text-content">
|
||||
<h4>{{ contents.title }}</h4>
|
||||
<p v-html="contents.content"></p>
|
||||
<a
|
||||
:href="newIssuePath"
|
||||
class="btn btn-success btn-inverted"
|
||||
v-if="activeTab === 'all'">
|
||||
New issue
|
||||
</a>
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-default"
|
||||
@click="changeTab('all')"
|
||||
v-if="activeTab === 'selected'">
|
||||
All issues
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
`,
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,83 @@
|
|||
/* eslint-disable no-new */
|
||||
/* global Vue */
|
||||
/* global Flash */
|
||||
|
||||
require('./lists_dropdown');
|
||||
|
||||
(() => {
|
||||
const ModalStore = gl.issueBoards.ModalStore;
|
||||
|
||||
gl.issueBoards.ModalFooter = Vue.extend({
|
||||
mixins: [gl.issueBoards.ModalMixins],
|
||||
data() {
|
||||
return {
|
||||
modal: ModalStore.store,
|
||||
state: gl.issueBoards.BoardsStore.state,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
submitDisabled() {
|
||||
return !ModalStore.selectedCount();
|
||||
},
|
||||
submitText() {
|
||||
const count = ModalStore.selectedCount();
|
||||
|
||||
return `Add ${count > 0 ? count : ''} ${gl.text.pluralize('issue', count)}`;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
addIssues() {
|
||||
const list = this.modal.selectedList || this.state.lists[0];
|
||||
const selectedIssues = ModalStore.getSelectedIssues();
|
||||
const issueIds = selectedIssues.map(issue => issue.globalId);
|
||||
|
||||
// Post the data to the backend
|
||||
gl.boardService.bulkUpdate(issueIds, {
|
||||
add_label_ids: [list.label.id],
|
||||
}).catch(() => {
|
||||
new Flash('Failed to update issues, please try again.', 'alert');
|
||||
|
||||
selectedIssues.forEach((issue) => {
|
||||
list.removeIssue(issue);
|
||||
list.issuesSize -= 1;
|
||||
});
|
||||
});
|
||||
|
||||
// Add the issues on the frontend
|
||||
selectedIssues.forEach((issue) => {
|
||||
list.addIssue(issue);
|
||||
list.issuesSize += 1;
|
||||
});
|
||||
|
||||
this.toggleModal(false);
|
||||
},
|
||||
},
|
||||
components: {
|
||||
'lists-dropdown': gl.issueBoards.ModalFooterListsDropdown,
|
||||
},
|
||||
template: `
|
||||
<footer
|
||||
class="form-actions add-issues-footer">
|
||||
<div class="pull-left">
|
||||
<button
|
||||
class="btn btn-success"
|
||||
type="button"
|
||||
:disabled="submitDisabled"
|
||||
@click="addIssues">
|
||||
{{ submitText }}
|
||||
</button>
|
||||
<span class="inline add-issues-footer-to-list">
|
||||
to list
|
||||
</span>
|
||||
<lists-dropdown></lists-dropdown>
|
||||
</div>
|
||||
<button
|
||||
class="btn btn-default pull-right"
|
||||
type="button"
|
||||
@click="toggleModal(false)">
|
||||
Cancel
|
||||
</button>
|
||||
</footer>
|
||||
`,
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,70 @@
|
|||
/* global Vue */
|
||||
|
||||
require('./tabs');
|
||||
|
||||
(() => {
|
||||
const ModalStore = gl.issueBoards.ModalStore;
|
||||
|
||||
gl.issueBoards.ModalHeader = Vue.extend({
|
||||
mixins: [gl.issueBoards.ModalMixins],
|
||||
data() {
|
||||
return ModalStore.store;
|
||||
},
|
||||
computed: {
|
||||
selectAllText() {
|
||||
if (ModalStore.selectedCount() !== this.issues.length || this.issues.length === 0) {
|
||||
return 'Select all';
|
||||
}
|
||||
|
||||
return 'Deselect all';
|
||||
},
|
||||
showSearch() {
|
||||
return this.activeTab === 'all' && !this.loading && this.issuesCount > 0;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
toggleAll() {
|
||||
this.$refs.selectAllBtn.blur();
|
||||
|
||||
ModalStore.toggleAll();
|
||||
},
|
||||
},
|
||||
components: {
|
||||
'modal-tabs': gl.issueBoards.ModalTabs,
|
||||
},
|
||||
template: `
|
||||
<div>
|
||||
<header class="add-issues-header form-actions">
|
||||
<h2>
|
||||
Add issues
|
||||
<button
|
||||
type="button"
|
||||
class="close"
|
||||
data-dismiss="modal"
|
||||
aria-label="Close"
|
||||
@click="toggleModal(false)">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</h2>
|
||||
</header>
|
||||
<modal-tabs v-if="!loading && issuesCount > 0"></modal-tabs>
|
||||
<div
|
||||
class="add-issues-search append-bottom-10"
|
||||
v-if="showSearch">
|
||||
<input
|
||||
placeholder="Search issues..."
|
||||
class="form-control"
|
||||
type="search"
|
||||
v-model="searchTerm" />
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-success btn-inverted prepend-left-10"
|
||||
ref="selectAllBtn"
|
||||
@click="toggleAll">
|
||||
{{ selectAllText }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,136 @@
|
|||
/* global Vue */
|
||||
/* global ListIssue */
|
||||
|
||||
require('./header');
|
||||
require('./list');
|
||||
require('./footer');
|
||||
require('./empty_state');
|
||||
|
||||
(() => {
|
||||
const ModalStore = gl.issueBoards.ModalStore;
|
||||
|
||||
gl.issueBoards.IssuesModal = Vue.extend({
|
||||
props: {
|
||||
blankStateImage: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
newIssuePath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
issueLinkBase: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
rootPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return ModalStore.store;
|
||||
},
|
||||
watch: {
|
||||
page() {
|
||||
this.loadIssues();
|
||||
},
|
||||
searchTerm() {
|
||||
this.searchOperation();
|
||||
},
|
||||
showAddIssuesModal() {
|
||||
if (this.showAddIssuesModal && !this.issues.length) {
|
||||
this.loading = true;
|
||||
|
||||
this.loadIssues()
|
||||
.then(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
} else if (!this.showAddIssuesModal) {
|
||||
this.issues = [];
|
||||
this.selectedIssues = [];
|
||||
this.issuesCount = false;
|
||||
}
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
searchOperation: _.debounce(function searchOperationDebounce() {
|
||||
this.loadIssues(true);
|
||||
}, 500),
|
||||
loadIssues(clearIssues = false) {
|
||||
return gl.boardService.getBacklog({
|
||||
search: this.searchTerm,
|
||||
page: this.page,
|
||||
per: this.perPage,
|
||||
}).then((res) => {
|
||||
const data = res.json();
|
||||
|
||||
if (clearIssues) {
|
||||
this.issues = [];
|
||||
}
|
||||
|
||||
data.issues.forEach((issueObj) => {
|
||||
const issue = new ListIssue(issueObj);
|
||||
const foundSelectedIssue = ModalStore.findSelectedIssue(issue);
|
||||
issue.selected = !!foundSelectedIssue;
|
||||
|
||||
this.issues.push(issue);
|
||||
});
|
||||
|
||||
this.loadingNewPage = false;
|
||||
|
||||
if (!this.issuesCount) {
|
||||
this.issuesCount = data.size;
|
||||
}
|
||||
});
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
showList() {
|
||||
if (this.activeTab === 'selected') {
|
||||
return this.selectedIssues.length > 0;
|
||||
}
|
||||
|
||||
return this.issuesCount > 0;
|
||||
},
|
||||
showEmptyState() {
|
||||
if (!this.loading && this.issuesCount === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.activeTab === 'selected' && this.selectedIssues.length === 0;
|
||||
},
|
||||
},
|
||||
components: {
|
||||
'modal-header': gl.issueBoards.ModalHeader,
|
||||
'modal-list': gl.issueBoards.ModalList,
|
||||
'modal-footer': gl.issueBoards.ModalFooter,
|
||||
'empty-state': gl.issueBoards.ModalEmptyState,
|
||||
},
|
||||
template: `
|
||||
<div
|
||||
class="add-issues-modal"
|
||||
v-if="showAddIssuesModal">
|
||||
<div class="add-issues-container">
|
||||
<modal-header></modal-header>
|
||||
<modal-list
|
||||
:issue-link-base="issueLinkBase"
|
||||
:root-path="rootPath"
|
||||
v-if="!loading && showList"></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">
|
||||
<div class="add-issues-list-loading">
|
||||
<i class="fa fa-spinner fa-spin"></i>
|
||||
</div>
|
||||
</section>
|
||||
<modal-footer></modal-footer>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,142 @@
|
|||
/* global Vue */
|
||||
/* global ListIssue */
|
||||
/* global bp */
|
||||
(() => {
|
||||
const ModalStore = gl.issueBoards.ModalStore;
|
||||
|
||||
gl.issueBoards.ModalList = Vue.extend({
|
||||
props: {
|
||||
issueLinkBase: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
rootPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return ModalStore.store;
|
||||
},
|
||||
watch: {
|
||||
activeTab() {
|
||||
if (this.activeTab === 'all') {
|
||||
ModalStore.purgeUnselectedIssues();
|
||||
}
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
loopIssues() {
|
||||
if (this.activeTab === 'all') {
|
||||
return this.issues;
|
||||
}
|
||||
|
||||
return this.selectedIssues;
|
||||
},
|
||||
groupedIssues() {
|
||||
const groups = [];
|
||||
this.loopIssues.forEach((issue, i) => {
|
||||
const index = i % this.columns;
|
||||
|
||||
if (!groups[index]) {
|
||||
groups.push([]);
|
||||
}
|
||||
|
||||
groups[index].push(issue);
|
||||
});
|
||||
|
||||
return groups;
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
scrollHandler() {
|
||||
const currentPage = Math.floor(this.issues.length / this.perPage);
|
||||
|
||||
if ((this.scrollTop() > this.scrollHeight() - 100) && !this.loadingNewPage
|
||||
&& currentPage === this.page) {
|
||||
this.loadingNewPage = true;
|
||||
this.page += 1;
|
||||
}
|
||||
},
|
||||
toggleIssue(e, issue) {
|
||||
if (e.target.tagName !== 'A') {
|
||||
ModalStore.toggleIssue(issue);
|
||||
}
|
||||
},
|
||||
listHeight() {
|
||||
return this.$refs.list.getBoundingClientRect().height;
|
||||
},
|
||||
scrollHeight() {
|
||||
return this.$refs.list.scrollHeight;
|
||||
},
|
||||
scrollTop() {
|
||||
return this.$refs.list.scrollTop + this.listHeight();
|
||||
},
|
||||
showIssue(issue) {
|
||||
if (this.activeTab === 'all') return true;
|
||||
|
||||
const index = ModalStore.selectedIssueIndex(issue);
|
||||
|
||||
return index !== -1;
|
||||
},
|
||||
setColumnCount() {
|
||||
const breakpoint = bp.getBreakpointSize();
|
||||
|
||||
if (breakpoint === 'lg' || breakpoint === 'md') {
|
||||
this.columns = 3;
|
||||
} else if (breakpoint === 'sm') {
|
||||
this.columns = 2;
|
||||
} else {
|
||||
this.columns = 1;
|
||||
}
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
this.scrollHandlerWrapper = this.scrollHandler.bind(this);
|
||||
this.setColumnCountWrapper = this.setColumnCount.bind(this);
|
||||
this.setColumnCount();
|
||||
|
||||
this.$refs.list.addEventListener('scroll', this.scrollHandlerWrapper);
|
||||
window.addEventListener('resize', this.setColumnCountWrapper);
|
||||
},
|
||||
beforeDestroy() {
|
||||
this.$refs.list.removeEventListener('scroll', this.scrollHandlerWrapper);
|
||||
window.removeEventListener('resize', this.setColumnCountWrapper);
|
||||
},
|
||||
components: {
|
||||
'issue-card-inner': gl.issueBoards.IssueCardInner,
|
||||
},
|
||||
template: `
|
||||
<section
|
||||
class="add-issues-list add-issues-list-columns"
|
||||
ref="list">
|
||||
<div
|
||||
v-for="group in groupedIssues"
|
||||
class="add-issues-list-column">
|
||||
<div
|
||||
v-for="issue in group"
|
||||
v-if="showIssue(issue)"
|
||||
class="card-parent">
|
||||
<div
|
||||
class="card"
|
||||
:class="{ 'is-active': issue.selected }"
|
||||
@click="toggleIssue($event, issue)">
|
||||
<issue-card-inner
|
||||
:issue="issue"
|
||||
:issue-link-base="issueLinkBase"
|
||||
:root-path="rootPath">
|
||||
</issue-card-inner>
|
||||
<span
|
||||
:aria-label="'Issue #' + issue.id + ' selected'"
|
||||
aria-checked="true"
|
||||
v-if="issue.selected"
|
||||
class="issue-card-selected text-center">
|
||||
<i class="fa fa-check"></i>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
`,
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,56 @@
|
|||
/* global Vue */
|
||||
(() => {
|
||||
const ModalStore = gl.issueBoards.ModalStore;
|
||||
|
||||
gl.issueBoards.ModalFooterListsDropdown = Vue.extend({
|
||||
data() {
|
||||
return {
|
||||
modal: ModalStore.store,
|
||||
state: gl.issueBoards.BoardsStore.state,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
selected() {
|
||||
return this.modal.selectedList || this.state.lists[0];
|
||||
},
|
||||
},
|
||||
destroyed() {
|
||||
this.modal.selectedList = null;
|
||||
},
|
||||
template: `
|
||||
<div class="dropdown inline">
|
||||
<button
|
||||
class="dropdown-menu-toggle"
|
||||
type="button"
|
||||
data-toggle="dropdown"
|
||||
aria-expanded="false">
|
||||
<span
|
||||
class="dropdown-label-box"
|
||||
:style="{ backgroundColor: selected.label.color }">
|
||||
</span>
|
||||
{{ selected.title }}
|
||||
<i class="fa fa-chevron-down"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-selectable dropdown-menu-drop-up">
|
||||
<ul>
|
||||
<li
|
||||
v-for="list in state.lists"
|
||||
v-if="list.type == 'label'">
|
||||
<a
|
||||
href="#"
|
||||
role="button"
|
||||
:class="{ 'is-active': list.id == selected.id }"
|
||||
@click.prevent="modal.selectedList = list">
|
||||
<span
|
||||
class="dropdown-label-box"
|
||||
:style="{ backgroundColor: list.label.color }">
|
||||
</span>
|
||||
{{ list.title }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
`,
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,47 @@
|
|||
/* global Vue */
|
||||
(() => {
|
||||
const ModalStore = gl.issueBoards.ModalStore;
|
||||
|
||||
gl.issueBoards.ModalTabs = Vue.extend({
|
||||
mixins: [gl.issueBoards.ModalMixins],
|
||||
data() {
|
||||
return ModalStore.store;
|
||||
},
|
||||
computed: {
|
||||
selectedCount() {
|
||||
return ModalStore.selectedCount();
|
||||
},
|
||||
},
|
||||
destroyed() {
|
||||
this.activeTab = 'all';
|
||||
},
|
||||
template: `
|
||||
<div class="top-area prepend-top-10 append-bottom-10">
|
||||
<ul class="nav-links issues-state-filters">
|
||||
<li :class="{ 'active': activeTab == 'all' }">
|
||||
<a
|
||||
href="#"
|
||||
role="button"
|
||||
@click.prevent="changeTab('all')">
|
||||
All issues
|
||||
<span class="badge">
|
||||
{{ issuesCount }}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
<li :class="{ 'active': activeTab == 'selected' }">
|
||||
<a
|
||||
href="#"
|
||||
role="button"
|
||||
@click.prevent="changeTab('selected')">
|
||||
Selected issues
|
||||
<span class="badge">
|
||||
{{ selectedCount }}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
`,
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,59 @@
|
|||
/* eslint-disable no-new */
|
||||
/* global Vue */
|
||||
/* global Flash */
|
||||
(() => {
|
||||
const Store = gl.issueBoards.BoardsStore;
|
||||
|
||||
window.gl = window.gl || {};
|
||||
window.gl.issueBoards = window.gl.issueBoards || {};
|
||||
|
||||
gl.issueBoards.RemoveIssueBtn = Vue.extend({
|
||||
props: {
|
||||
issue: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
list: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
removeIssue() {
|
||||
const issue = this.issue;
|
||||
const lists = issue.getLists();
|
||||
const labelIds = lists.map(list => list.label.id);
|
||||
|
||||
// Post the remove data
|
||||
gl.boardService.bulkUpdate([issue.globalId], {
|
||||
remove_label_ids: labelIds,
|
||||
}).catch(() => {
|
||||
new Flash('Failed to remove issue from board, please try again.', 'alert');
|
||||
|
||||
lists.forEach((list) => {
|
||||
list.addIssue(issue);
|
||||
});
|
||||
});
|
||||
|
||||
// Remove from the frontend store
|
||||
lists.forEach((list) => {
|
||||
list.removeIssue(issue);
|
||||
});
|
||||
|
||||
Store.detail.issue = {};
|
||||
},
|
||||
},
|
||||
template: `
|
||||
<div
|
||||
class="block list"
|
||||
v-if="list.type !== 'done'">
|
||||
<button
|
||||
class="btn btn-default btn-block"
|
||||
type="button"
|
||||
@click="removeIssue">
|
||||
Remove from board
|
||||
</button>
|
||||
</div>
|
||||
`,
|
||||
});
|
||||
})();
|
|
@ -0,0 +1,14 @@
|
|||
(() => {
|
||||
const ModalStore = gl.issueBoards.ModalStore;
|
||||
|
||||
gl.issueBoards.ModalMixins = {
|
||||
methods: {
|
||||
toggleModal(toggle) {
|
||||
ModalStore.store.showAddIssuesModal = toggle;
|
||||
},
|
||||
changeTab(tab) {
|
||||
ModalStore.store.activeTab = tab;
|
||||
},
|
||||
},
|
||||
};
|
||||
})();
|
|
@ -6,12 +6,15 @@
|
|||
|
||||
class ListIssue {
|
||||
constructor (obj) {
|
||||
this.globalId = obj.id;
|
||||
this.id = obj.iid;
|
||||
this.title = obj.title;
|
||||
this.confidential = obj.confidential;
|
||||
this.dueDate = obj.due_date;
|
||||
this.subscribed = obj.subscribed;
|
||||
this.labels = [];
|
||||
this.selected = false;
|
||||
this.assignee = false;
|
||||
|
||||
if (obj.assignee) {
|
||||
this.assignee = new ListUser(obj.assignee);
|
||||
|
|
|
@ -9,7 +9,7 @@ class List {
|
|||
this.position = obj.position;
|
||||
this.title = obj.title;
|
||||
this.type = obj.list_type;
|
||||
this.preset = ['backlog', 'done', 'blank'].indexOf(this.type) > -1;
|
||||
this.preset = ['done', 'blank'].indexOf(this.type) > -1;
|
||||
this.filters = gl.issueBoards.BoardsStore.state.filters;
|
||||
this.page = 1;
|
||||
this.loading = true;
|
||||
|
|
|
@ -2,7 +2,13 @@
|
|||
/* global Vue */
|
||||
|
||||
class BoardService {
|
||||
constructor (root, boardId) {
|
||||
constructor (root, bulkUpdatePath, boardId) {
|
||||
this.boards = Vue.resource(`${root}{/id}.json`, {}, {
|
||||
issues: {
|
||||
method: 'GET',
|
||||
url: `${root}/${boardId}/issues.json`
|
||||
}
|
||||
});
|
||||
this.lists = Vue.resource(`${root}/${boardId}/lists{/id}`, {}, {
|
||||
generate: {
|
||||
method: 'POST',
|
||||
|
@ -10,7 +16,12 @@ class BoardService {
|
|||
}
|
||||
});
|
||||
this.issue = Vue.resource(`${root}/${boardId}/issues{/id}`, {});
|
||||
this.issues = Vue.resource(`${root}/${boardId}/lists{/id}/issues`, {});
|
||||
this.issues = Vue.resource(`${root}/${boardId}/lists{/id}/issues`, {}, {
|
||||
bulkUpdate: {
|
||||
method: 'POST',
|
||||
url: bulkUpdatePath,
|
||||
},
|
||||
});
|
||||
|
||||
Vue.http.interceptors.push((request, next) => {
|
||||
request.headers['X-CSRF-Token'] = $.rails.csrfToken();
|
||||
|
@ -65,6 +76,20 @@ class BoardService {
|
|||
issue
|
||||
});
|
||||
}
|
||||
|
||||
getBacklog(data) {
|
||||
return this.boards.issues(data);
|
||||
}
|
||||
|
||||
bulkUpdate(issueIds, extraData = {}) {
|
||||
const data = {
|
||||
update: Object.assign(extraData, {
|
||||
issuable_ids: issueIds.join(','),
|
||||
}),
|
||||
};
|
||||
|
||||
return this.issues.bulkUpdate(data);
|
||||
}
|
||||
}
|
||||
|
||||
window.BoardService = BoardService;
|
||||
|
|
|
@ -34,15 +34,10 @@
|
|||
},
|
||||
new (listObj) {
|
||||
const list = this.addList(listObj);
|
||||
const backlogList = this.findList('type', 'backlog', 'backlog');
|
||||
|
||||
list
|
||||
.save()
|
||||
.then(() => {
|
||||
// Remove any new issues from the backlog
|
||||
// as they will be visible in the new list
|
||||
list.issues.forEach(backlogList.removeIssue.bind(backlogList));
|
||||
|
||||
this.state.lists = _.sortBy(this.state.lists, 'position');
|
||||
});
|
||||
this.removeBlankState();
|
||||
|
@ -52,7 +47,7 @@
|
|||
},
|
||||
shouldAddBlankState () {
|
||||
// Decide whether to add the blank state
|
||||
return !(this.state.lists.filter(list => list.type !== 'backlog' && list.type !== 'done')[0]);
|
||||
return !(this.state.lists.filter(list => list.type !== 'done')[0]);
|
||||
},
|
||||
addBlankState () {
|
||||
if (!this.shouldAddBlankState() || this.welcomeIsHidden() || this.disabled) return;
|
||||
|
@ -102,7 +97,7 @@
|
|||
listTo.addIssue(issue, listFrom, newIndex);
|
||||
}
|
||||
|
||||
if (listTo.type === 'done' && listFrom.type !== 'backlog') {
|
||||
if (listTo.type === 'done') {
|
||||
issueLists.forEach((list) => {
|
||||
list.removeIssue(issue);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
(() => {
|
||||
window.gl = window.gl || {};
|
||||
window.gl.issueBoards = window.gl.issueBoards || {};
|
||||
|
||||
class ModalStore {
|
||||
constructor() {
|
||||
this.store = {
|
||||
columns: 3,
|
||||
issues: [],
|
||||
issuesCount: false,
|
||||
selectedIssues: [],
|
||||
showAddIssuesModal: false,
|
||||
activeTab: 'all',
|
||||
selectedList: null,
|
||||
searchTerm: '',
|
||||
loading: false,
|
||||
loadingNewPage: false,
|
||||
page: 1,
|
||||
perPage: 50,
|
||||
};
|
||||
}
|
||||
|
||||
selectedCount() {
|
||||
return this.getSelectedIssues().length;
|
||||
}
|
||||
|
||||
toggleIssue(issueObj) {
|
||||
const issue = issueObj;
|
||||
const selected = issue.selected;
|
||||
|
||||
issue.selected = !selected;
|
||||
|
||||
if (!selected) {
|
||||
this.addSelectedIssue(issue);
|
||||
} else {
|
||||
this.removeSelectedIssue(issue);
|
||||
}
|
||||
}
|
||||
|
||||
toggleAll() {
|
||||
const select = this.selectedCount() !== this.store.issues.length;
|
||||
|
||||
this.store.issues.forEach((issue) => {
|
||||
const issueUpdate = issue;
|
||||
|
||||
if (issueUpdate.selected !== select) {
|
||||
issueUpdate.selected = select;
|
||||
|
||||
if (select) {
|
||||
this.addSelectedIssue(issue);
|
||||
} else {
|
||||
this.removeSelectedIssue(issue);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getSelectedIssues() {
|
||||
return this.store.selectedIssues.filter(issue => issue.selected);
|
||||
}
|
||||
|
||||
addSelectedIssue(issue) {
|
||||
const index = this.selectedIssueIndex(issue);
|
||||
|
||||
if (index === -1) {
|
||||
this.store.selectedIssues.push(issue);
|
||||
}
|
||||
}
|
||||
|
||||
removeSelectedIssue(issue, forcePurge = false) {
|
||||
if (this.store.activeTab === 'all' || forcePurge) {
|
||||
this.store.selectedIssues = this.store.selectedIssues
|
||||
.filter(fIssue => fIssue.id !== issue.id);
|
||||
}
|
||||
}
|
||||
|
||||
purgeUnselectedIssues() {
|
||||
this.store.selectedIssues.forEach((issue) => {
|
||||
if (!issue.selected) {
|
||||
this.removeSelectedIssue(issue, true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
selectedIssueIndex(issue) {
|
||||
return this.store.selectedIssues.indexOf(issue);
|
||||
}
|
||||
|
||||
findSelectedIssue(issue) {
|
||||
return this.store.selectedIssues
|
||||
.filter(filteredIssue => filteredIssue.id === issue.id)[0];
|
||||
}
|
||||
}
|
||||
|
||||
gl.issueBoards.ModalStore = new ModalStore();
|
||||
})();
|
|
@ -43,6 +43,7 @@
|
|||
BreakpointInstance.prototype.getBreakpointSize = function() {
|
||||
var $visibleDevice;
|
||||
$visibleDevice = this.visibleDevice;
|
||||
// TODO: Consider refactoring in light of turbolinks removal.
|
||||
// the page refreshed via turbolinks
|
||||
if (!$visibleDevice().length) {
|
||||
this.setup();
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-use-before-define, no-param-reassign, quotes, yoda, no-else-return, consistent-return, comma-dangle, object-shorthand, prefer-template, one-var, one-var-declaration-per-line, no-unused-vars, max-len, vars-on-top */
|
||||
/* global Breakpoints */
|
||||
/* global Turbolinks */
|
||||
|
||||
(function() {
|
||||
var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; };
|
||||
|
@ -127,7 +126,7 @@
|
|||
pageUrl += DOWN_BUILD_TRACE;
|
||||
}
|
||||
|
||||
return Turbolinks.visit(pageUrl);
|
||||
return gl.utils.visitUrl(pageUrl);
|
||||
}
|
||||
};
|
||||
})(this)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable class-methods-use-this, object-shorthand, no-unused-vars, no-use-before-define, no-new, max-len, no-restricted-syntax, guard-for-in, no-continue */
|
||||
/* jshint esversion: 6 */
|
||||
|
||||
/*= require lib/utils/common_utils */
|
||||
require('./lib/utils/common_utils');
|
||||
|
||||
(() => {
|
||||
const gfmRules = {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, one-var, no-var, one-var-declaration-per-line, prefer-template, quotes, no-unused-vars, prefer-arrow-callback, max-len */
|
||||
/* global Clipboard */
|
||||
|
||||
/*= require clipboard */
|
||||
window.Clipboard = require('vendor/clipboard');
|
||||
|
||||
(function() {
|
||||
var genericError, genericSuccess, showTooltip;
|
||||
|
|
|
@ -2,9 +2,12 @@
|
|||
/* global Cookies */
|
||||
/* global Flash */
|
||||
|
||||
//= require vue
|
||||
//= require_tree ./svg
|
||||
//= require_tree .
|
||||
window.Vue = require('vue');
|
||||
window.Cookies = require('vendor/js.cookie');
|
||||
|
||||
function requireAll(context) { return context.keys().map(context); }
|
||||
requireAll(require.context('./svg', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('.', true, /^\.\/(?!cycle_analytics_bundle).*\.(js|es6)$/));
|
||||
|
||||
$(() => {
|
||||
const OVERVIEW_DIALOG_COOKIE = 'cycle_analytics_help_dismissed';
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
/* eslint-disable class-methods-use-this */
|
||||
|
||||
//= require lib/utils/url_utility */
|
||||
require('./lib/utils/url_utility');
|
||||
|
||||
(() => {
|
||||
const UNFOLD_COUNT = 20;
|
||||
let isBound = false;
|
||||
|
||||
class Diff {
|
||||
constructor() {
|
||||
|
@ -17,10 +18,12 @@
|
|||
$('.content-wrapper .container-fluid').removeClass('container-limited');
|
||||
}
|
||||
|
||||
$(document)
|
||||
.off('click', '.js-unfold, .diff-line-num a')
|
||||
.on('click', '.js-unfold', this.handleClickUnfold.bind(this))
|
||||
.on('click', '.diff-line-num a', this.handleClickLineNum.bind(this));
|
||||
if (!isBound) {
|
||||
$(document)
|
||||
.on('click', '.js-unfold', this.handleClickUnfold.bind(this))
|
||||
.on('click', '.diff-line-num a', this.handleClickLineNum.bind(this));
|
||||
isBound = true;
|
||||
}
|
||||
|
||||
this.openAnchoredDiff();
|
||||
}
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
/* eslint-disable func-names, comma-dangle, new-cap, no-new */
|
||||
/* eslint-disable func-names, comma-dangle, new-cap, no-new, import/newline-after-import, no-multi-spaces, max-len */
|
||||
/* global Vue */
|
||||
/* global ResolveCount */
|
||||
|
||||
//= require_directory ./models
|
||||
//= require_directory ./stores
|
||||
//= require_directory ./services
|
||||
//= require_directory ./mixins
|
||||
//= require_directory ./components
|
||||
function requireAll(context) { return context.keys().map(context); }
|
||||
requireAll(require.context('./models', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./stores', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./services', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./mixins', false, /^\.\/.*\.(js|es6)$/));
|
||||
requireAll(require.context('./components', false, /^\.\/.*\.(js|es6)$/));
|
||||
|
||||
$(() => {
|
||||
const COMPONENT_SELECTOR = 'resolve-btn, resolve-discussion-btn, jump-to-discussion, comment-and-resolve-btn';
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, one-var, no-var, one-var-declaration-per-line, no-unused-vars, camelcase, quotes, no-useless-concat, prefer-template, quote-props, comma-dangle, object-shorthand, consistent-return, prefer-arrow-callback */
|
||||
/* global Dropzone */
|
||||
|
||||
/*= require preview_markdown */
|
||||
require('./preview_markdown');
|
||||
|
||||
(function() {
|
||||
this.DropzoneInput = (function() {
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
/* global EnvironmentsService */
|
||||
/* global Flash */
|
||||
|
||||
//= require vue
|
||||
//= require vue-resource
|
||||
//= require_tree ../services/
|
||||
//= require ./environment_item
|
||||
window.Vue = require('vue');
|
||||
window.Vue.use(require('vue-resource'));
|
||||
require('../services/environments_service');
|
||||
require('./environment_item');
|
||||
|
||||
(() => {
|
||||
window.gl = window.gl || {};
|
||||
|
@ -180,7 +180,7 @@
|
|||
<tr>
|
||||
<th class="environments-name">Environment</th>
|
||||
<th class="environments-deploy">Last deployment</th>
|
||||
<th class="environments-build">Build</th>
|
||||
<th class="environments-build">Job</th>
|
||||
<th class="environments-commit">Commit</th>
|
||||
<th class="environments-date">Updated</th>
|
||||
<th class="hidden-xs environments-actions"></th>
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*= require vue */
|
||||
/* global Vue */
|
||||
|
||||
window.Vue = require('vue');
|
||||
|
||||
(() => {
|
||||
window.gl = window.gl || {};
|
||||
window.gl.environmentsList = window.gl.environmentsList || {};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*= require vue */
|
||||
/* global Vue */
|
||||
|
||||
window.Vue = require('vue');
|
||||
|
||||
(() => {
|
||||
window.gl = window.gl || {};
|
||||
window.gl.environmentsList = window.gl.environmentsList || {};
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
/* global Vue */
|
||||
/* global timeago */
|
||||
|
||||
/*= require timeago */
|
||||
/*= require lib/utils/text_utility */
|
||||
/*= require vue_common_component/commit */
|
||||
/*= require ./environment_actions */
|
||||
/*= require ./environment_external_url */
|
||||
/*= require ./environment_stop */
|
||||
/*= require ./environment_rollback */
|
||||
/*= require ./environment_terminal_button */
|
||||
window.Vue = require('vue');
|
||||
window.timeago = require('vendor/timeago');
|
||||
require('../../lib/utils/text_utility');
|
||||
require('../../vue_common_component/commit');
|
||||
require('./environment_actions');
|
||||
require('./environment_external_url');
|
||||
require('./environment_stop');
|
||||
require('./environment_rollback');
|
||||
require('./environment_terminal_button');
|
||||
|
||||
(() => {
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*= require vue */
|
||||
/* global Vue */
|
||||
|
||||
window.Vue = require('vue');
|
||||
|
||||
(() => {
|
||||
window.gl = window.gl || {};
|
||||
window.gl.environmentsList = window.gl.environmentsList || {};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*= require vue */
|
||||
/* global Vue */
|
||||
|
||||
window.Vue = require('vue');
|
||||
|
||||
(() => {
|
||||
window.gl = window.gl || {};
|
||||
window.gl.environmentsList = window.gl.environmentsList || {};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/*= require vue */
|
||||
/* global Vue */
|
||||
|
||||
window.Vue = require('vue');
|
||||
|
||||
(() => {
|
||||
window.gl = window.gl || {};
|
||||
window.gl.environmentsList = window.gl.environmentsList || {};
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
//= require vue
|
||||
//= require_tree ./stores/
|
||||
//= require ./components/environment
|
||||
//= require ./vue_resource_interceptor
|
||||
window.Vue = require('vue');
|
||||
|
||||
require('./stores/environments_store');
|
||||
require('./components/environment');
|
||||
require('./vue_resource_interceptor');
|
||||
|
||||
$(() => {
|
||||
window.gl = window.gl || {};
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* globals Vue */
|
||||
/* eslint-disable no-unused-vars, no-param-reassign */
|
||||
|
||||
class EnvironmentsService {
|
||||
|
||||
constructor(root) {
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
/* eslint-disable no-extend-native, func-names, space-before-function-paren, space-infix-ops, max-len */
|
||||
/* eslint-disable no-extend-native, func-names, space-before-function-paren, space-infix-ops, strict, max-len */
|
||||
|
||||
'use strict';
|
||||
|
||||
Array.prototype.first = function() {
|
||||
return this[0];
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*= require filtered_search/filtered_search_dropdown */
|
||||
require('./filtered_search_dropdown');
|
||||
|
||||
/* global droplabFilter */
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*= require filtered_search/filtered_search_dropdown */
|
||||
require('./filtered_search_dropdown');
|
||||
|
||||
/* global droplabAjax */
|
||||
/* global droplabFilter */
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
/*= require filtered_search/filtered_search_dropdown */
|
||||
require('./filtered_search_dropdown');
|
||||
|
||||
/* global droplabAjaxFilter */
|
||||
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
// This is a manifest file that'll be compiled into including all the files listed below.
|
||||
// Add new JavaScript code in separate files in this directory and they'll automatically
|
||||
// be included in the compiled file accessible from http://example.com/assets/application.js
|
||||
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
||||
// the compiled file.
|
||||
//
|
||||
/*= require_tree . */
|
||||
function requireAll(context) { return context.keys().map(context); }
|
||||
|
||||
requireAll(require.context('./', true, /^\.\/(?!filtered_search_bundle).*\.(js|es6)$/));
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
this.setupMapping();
|
||||
|
||||
this.cleanupWrapper = this.cleanup.bind(this);
|
||||
document.addEventListener('page:fetch', this.cleanupWrapper);
|
||||
document.addEventListener('beforeunload', this.cleanupWrapper);
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
|
@ -20,7 +20,7 @@
|
|||
|
||||
this.setupMapping();
|
||||
|
||||
document.removeEventListener('page:fetch', this.cleanupWrapper);
|
||||
document.removeEventListener('beforeunload', this.cleanupWrapper);
|
||||
}
|
||||
|
||||
setupMapping() {
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
/* global Turbolinks */
|
||||
|
||||
(() => {
|
||||
class FilteredSearchManager {
|
||||
constructor() {
|
||||
|
@ -15,13 +13,13 @@
|
|||
this.dropdownManager.setDropdown();
|
||||
|
||||
this.cleanupWrapper = this.cleanup.bind(this);
|
||||
document.addEventListener('page:fetch', this.cleanupWrapper);
|
||||
document.addEventListener('beforeunload', this.cleanupWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
this.unbindEvents();
|
||||
document.removeEventListener('page:fetch', this.cleanupWrapper);
|
||||
document.removeEventListener('beforeunload', this.cleanupWrapper);
|
||||
}
|
||||
|
||||
bindEvents() {
|
||||
|
@ -200,7 +198,9 @@
|
|||
paths.push(`search=${sanitized}`);
|
||||
}
|
||||
|
||||
Turbolinks.visit(`?scope=all&utf8=✓&${paths.join('&')}`);
|
||||
const parameterizedUrl = `?scope=all&utf8=✓&${paths.join('&')}`;
|
||||
|
||||
gl.utils.visitUrl(parameterizedUrl);
|
||||
}
|
||||
|
||||
getUsernameParams() {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, no-var, one-var, one-var-declaration-per-line, prefer-rest-params, max-len, vars-on-top, wrap-iife, no-unused-vars, quotes, no-shadow, no-cond-assign, prefer-arrow-callback, no-return-assign, no-else-return, camelcase, comma-dangle, no-lonely-if, guard-for-in, no-restricted-syntax, consistent-return, prefer-template, no-param-reassign, no-loop-func, no-mixed-operators */
|
||||
/* global fuzzaldrinPlus */
|
||||
/* global Turbolinks */
|
||||
|
||||
(function() {
|
||||
var GitLabDropdown, GitLabDropdownFilter, GitLabDropdownRemote,
|
||||
|
@ -249,7 +248,7 @@
|
|||
_this.fullData = data;
|
||||
_this.parseData(_this.fullData);
|
||||
_this.focusTextInput();
|
||||
if (_this.options.filterable && _this.filter && _this.filter.input && _this.filter.input.val().trim() !== '') {
|
||||
if (_this.options.filterable && _this.filter && _this.filter.input && _this.filter.input.val() && _this.filter.input.val().trim() !== '') {
|
||||
return _this.filter.input.trigger('input');
|
||||
}
|
||||
};
|
||||
|
@ -723,7 +722,7 @@
|
|||
if ($el.length) {
|
||||
var href = $el.attr('href');
|
||||
if (href && href !== '#') {
|
||||
Turbolinks.visit(href);
|
||||
gl.utils.visitUrl(href);
|
||||
} else {
|
||||
$el.first().trigger('click');
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* eslint-disable comma-dangle, class-methods-use-this, max-len, space-before-function-paren, arrow-parens, no-param-reassign */
|
||||
|
||||
//= require gl_field_error
|
||||
require('./gl_field_error');
|
||||
|
||||
((global) => {
|
||||
const customValidationFlag = 'gl-field-error-ignore';
|
||||
|
|
|
@ -1,12 +1,3 @@
|
|||
/* eslint-disable func-names, space-before-function-paren */
|
||||
// This is a manifest file that'll be compiled into including all the files listed below.
|
||||
// Add new JavaScript code in separate files in this directory and they'll automatically
|
||||
// be included in the compiled file accessible from http://example.com/assets/application.js
|
||||
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
||||
// the compiled file.
|
||||
//
|
||||
/*= require_tree . */
|
||||
|
||||
(function() {
|
||||
|
||||
}).call(this);
|
||||
// require everything else in this directory
|
||||
function requireAll(context) { return context.keys().map(context); }
|
||||
requireAll(require.context('.', false, /^\.\/(?!graphs_bundle).*\.(js|es6)$/));
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
/* global ContributorsStatGraphUtil */
|
||||
/* global d3 */
|
||||
|
||||
/*= require d3 */
|
||||
window.d3 = require('d3');
|
||||
|
||||
(function() {
|
||||
this.ContributorsStatGraph = (function() {
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
/* global d3 */
|
||||
/* global ContributorsGraph */
|
||||
|
||||
/*= require d3 */
|
||||
window.d3 = require('d3');
|
||||
|
||||
(function() {
|
||||
var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; },
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* eslint-disable no-param-reassign, func-names, no-var, camelcase, no-unused-vars, object-shorthand, space-before-function-paren, no-return-assign, comma-dangle, consistent-return, one-var, one-var-declaration-per-line, quotes, prefer-template, prefer-arrow-callback, wrap-iife, max-len */
|
||||
/* global Issuable */
|
||||
/* global Turbolinks */
|
||||
|
||||
((global) => {
|
||||
var issuable_created;
|
||||
|
@ -119,7 +118,7 @@
|
|||
issuesUrl = formAction;
|
||||
issuesUrl += "" + (formAction.indexOf('?') < 0 ? '?' : '&');
|
||||
issuesUrl += formData;
|
||||
return Turbolinks.visit(issuesUrl);
|
||||
return gl.utils.visitUrl(issuesUrl);
|
||||
};
|
||||
})(this),
|
||||
initResetFilters: function() {
|
||||
|
@ -130,7 +129,7 @@
|
|||
const baseIssuesUrl = target.href;
|
||||
|
||||
$form.attr('action', baseIssuesUrl);
|
||||
Turbolinks.visit(baseIssuesUrl);
|
||||
gl.utils.visitUrl(baseIssuesUrl);
|
||||
});
|
||||
},
|
||||
initChecks: function() {
|
||||
|
|
|
@ -1 +1 @@
|
|||
//= require ./time_tracking/time_tracking_bundle
|
||||
require('./time_tracking/time_tracking_bundle');
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* global Vue */
|
||||
//= require lib/utils/pretty_time
|
||||
require('../../../lib/utils/pretty_time');
|
||||
|
||||
(() => {
|
||||
Vue.component('time-tracking-collapsed-state', {
|
||||
|
@ -39,4 +39,3 @@
|
|||
`,
|
||||
});
|
||||
})();
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/* global Vue */
|
||||
//= require lib/utils/pretty_time
|
||||
require('../../../lib/utils/pretty_time');
|
||||
|
||||
(() => {
|
||||
const prettyTime = gl.utils.prettyTime;
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
/* global Vue */
|
||||
//= require ./help_state
|
||||
//= require ./collapsed_state
|
||||
//= require ./spent_only_pane
|
||||
//= require ./no_tracking_pane
|
||||
//= require ./estimate_only_pane
|
||||
//= require ./comparison_pane
|
||||
|
||||
require('./help_state');
|
||||
require('./collapsed_state');
|
||||
require('./spent_only_pane');
|
||||
require('./no_tracking_pane');
|
||||
require('./estimate_only_pane');
|
||||
require('./comparison_pane');
|
||||
|
||||
(() => {
|
||||
Vue.component('issuable-time-tracker', {
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
/* global Vue */
|
||||
//= require ./components/time_tracker
|
||||
//= require smart_interval
|
||||
//= require subbable_resource
|
||||
|
||||
require('./components/time_tracker');
|
||||
require('../../smart_interval');
|
||||
require('../../subbable_resource');
|
||||
|
||||
(() => {
|
||||
/* This Vue instance represents what will become the parent instance for the
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/* 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 */
|
||||
|
||||
/*= require flash */
|
||||
/*= require jquery.waitforimages */
|
||||
/*= require task_list */
|
||||
require('./flash');
|
||||
require('vendor/jquery.waitforimages');
|
||||
require('vendor/task_list');
|
||||
|
||||
(function() {
|
||||
var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; };
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
/* eslint-disable func-names, space-before-function-paren */
|
||||
|
||||
/*= require Chart */
|
||||
|
||||
(function() {
|
||||
|
||||
}).call(this);
|
||||
window.Chart = require('vendor/Chart');
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
/* eslint-disable func-names, space-before-function-paren */
|
||||
|
||||
/*= require d3 */
|
||||
|
||||
(function() {
|
||||
|
||||
}).call(this);
|
||||
window.d3 = require('d3');
|
||||
|
|
|
@ -95,7 +95,6 @@
|
|||
const newState = `${copySource}${this.currentLocation.search}${this.currentLocation.hash}`;
|
||||
|
||||
history.replaceState({
|
||||
turbolinks: true,
|
||||
url: newState,
|
||||
}, document.title, newState);
|
||||
return newState;
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
/* global timeago */
|
||||
/* global dateFormat */
|
||||
|
||||
/*= require timeago */
|
||||
/*= require date.format */
|
||||
window.timeago = require('vendor/timeago');
|
||||
window.dateFormat = require('vendor/date.format');
|
||||
|
||||
(function() {
|
||||
(function(w) {
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
(function() {
|
||||
gl.emojiAliases = function() {
|
||||
return JSON.parse('<%= Gitlab::AwardEmoji.aliases.to_json %>');
|
||||
};
|
||||
|
||||
}).call(this);
|
|
@ -161,6 +161,9 @@
|
|||
gl.text.humanize = function(string) {
|
||||
return string.charAt(0).toUpperCase() + string.replace(/_/g, ' ').slice(1);
|
||||
};
|
||||
gl.text.pluralize = function(str, count) {
|
||||
return str + (count > 1 || count === 0 ? 's' : '');
|
||||
};
|
||||
return gl.text.truncate = function(string, maxLength) {
|
||||
return string.substr(0, (maxLength - 3)) + '...';
|
||||
};
|
||||
|
|
|
@ -76,5 +76,11 @@
|
|||
hashIndex = url.indexOf('#');
|
||||
return hashIndex === -1 ? null : url.substring(hashIndex + 1);
|
||||
};
|
||||
|
||||
w.gl.utils.refreshCurrentPage = () => gl.utils.visitUrl(document.location.href);
|
||||
|
||||
w.gl.utils.visitUrl = (url) => {
|
||||
document.location.href = url;
|
||||
};
|
||||
})(window);
|
||||
}).call(this);
|
|
@ -1,2 +1,2 @@
|
|||
//= require vue
|
||||
//= require vue-resource
|
||||
window.Vue = require('vue');
|
||||
window.Vue.use(require('vue-resource'));
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
//
|
||||
// Handles single- and multi-line selection and highlight for blob views.
|
||||
//
|
||||
/*= require jquery.scrollTo */
|
||||
require('vendor/jquery.scrollTo');
|
||||
|
||||
//
|
||||
// ### Example Markup
|
||||
|
@ -171,7 +171,6 @@
|
|||
// This method is stubbed in tests.
|
||||
LineHighlighter.prototype.__setLocationHash__ = function(value) {
|
||||
return history.pushState({
|
||||
turbolinks: false,
|
||||
url: value
|
||||
// We're using pushState instead of assigning location.hash directly to
|
||||
// prevent the page from scrolling on the hashchange event
|
||||
|
|
|
@ -1,14 +1,7 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback */
|
||||
/* global Turbolinks */
|
||||
|
||||
(function() {
|
||||
Turbolinks.enableProgressBar();
|
||||
|
||||
$(document).on('page:fetch', function() {
|
||||
window.addEventListener('beforeunload', function() {
|
||||
$('.tanuki-logo').addClass('animate');
|
||||
});
|
||||
|
||||
$(document).on('page:change', function() {
|
||||
$('.tanuki-logo').removeClass('animate');
|
||||
});
|
||||
}).call(this);
|
||||
|
|
|
@ -2,14 +2,14 @@
|
|||
/* global Vue */
|
||||
/* global Flash */
|
||||
|
||||
//= require vue
|
||||
//= require ./merge_conflict_store
|
||||
//= require ./merge_conflict_service
|
||||
//= require ./mixins/line_conflict_utils
|
||||
//= require ./mixins/line_conflict_actions
|
||||
//= require ./components/diff_file_editor
|
||||
//= require ./components/inline_conflict_lines
|
||||
//= require ./components/parallel_conflict_lines
|
||||
window.Vue = require('vue');
|
||||
require('./merge_conflict_store');
|
||||
require('./merge_conflict_service');
|
||||
require('./mixins/line_conflict_utils');
|
||||
require('./mixins/line_conflict_actions');
|
||||
require('./components/diff_file_editor');
|
||||
require('./components/inline_conflict_lines');
|
||||
require('./components/parallel_conflict_lines');
|
||||
|
||||
$(() => {
|
||||
const INTERACTIVE_RESOLVE_MODE = 'interactive';
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, quotes, no-underscore-dangle, one-var, one-var-declaration-per-line, consistent-return, dot-notation, quote-props, comma-dangle, object-shorthand, max-len, prefer-arrow-callback */
|
||||
/* global MergeRequestTabs */
|
||||
|
||||
/*= require jquery.waitforimages */
|
||||
/*= require task_list */
|
||||
/*= require merge_request_tabs */
|
||||
require('vendor/jquery.waitforimages');
|
||||
require('vendor/task_list');
|
||||
require('./merge_request_tabs');
|
||||
|
||||
(function() {
|
||||
var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; };
|
||||
|
@ -110,9 +110,8 @@
|
|||
};
|
||||
|
||||
MergeRequest.prototype.initCommitMessageListeners = function() {
|
||||
var textarea = $('textarea.js-commit-message');
|
||||
|
||||
$('a.js-with-description-link').on('click', function(e) {
|
||||
$(document).on('click', 'a.js-with-description-link', function(e) {
|
||||
var textarea = $('textarea.js-commit-message');
|
||||
e.preventDefault();
|
||||
|
||||
textarea.val(textarea.data('messageWithDescription'));
|
||||
|
@ -120,7 +119,8 @@
|
|||
$('p.js-without-description-hint').show();
|
||||
});
|
||||
|
||||
$('a.js-without-description-link').on('click', function(e) {
|
||||
$(document).on('click', 'a.js-without-description-link', function(e) {
|
||||
var textarea = $('textarea.js-commit-message');
|
||||
e.preventDefault();
|
||||
|
||||
textarea.val(textarea.data('messageWithoutDescription'));
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/* eslint-disable no-new, class-methods-use-this */
|
||||
/* global Breakpoints */
|
||||
/* global Cookies */
|
||||
/* global DiffNotesApp */
|
||||
/* global Flash */
|
||||
|
||||
/*= require js.cookie */
|
||||
/*= require breakpoints */
|
||||
require('./breakpoints');
|
||||
window.Cookies = require('vendor/js.cookie');
|
||||
require('./flash');
|
||||
|
||||
/* eslint-disable max-len */
|
||||
// MergeRequestTabs
|
||||
|
@ -184,12 +184,13 @@
|
|||
// Ensure parameters and hash come along for the ride
|
||||
newState += location.search + location.hash;
|
||||
|
||||
// TODO: Consider refactoring in light of turbolinks removal.
|
||||
|
||||
// Replace the current history state with the new one without breaking
|
||||
// Turbolinks' history.
|
||||
//
|
||||
// See https://github.com/rails/turbolinks/issues/363
|
||||
window.history.replaceState({
|
||||
turbolinks: true,
|
||||
url: newState,
|
||||
}, document.title, newState);
|
||||
|
||||
|
|
|
@ -2,7 +2,8 @@
|
|||
/* global notify */
|
||||
/* global notifyPermissions */
|
||||
/* global merge_request_widget */
|
||||
/* global Turbolinks */
|
||||
|
||||
require('./smart_interval');
|
||||
|
||||
((global) => {
|
||||
var indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i += 1) { if (i in this && this[i] === item) return i; } return -1; };
|
||||
|
@ -69,13 +70,13 @@
|
|||
}
|
||||
|
||||
MergeRequestWidget.prototype.clearEventListeners = function() {
|
||||
return $(document).off('page:change.merge_request');
|
||||
return $(document).off('DOMContentLoaded');
|
||||
};
|
||||
|
||||
MergeRequestWidget.prototype.addEventListeners = function() {
|
||||
var allowedPages;
|
||||
allowedPages = ['show', 'commits', 'pipelines', 'changes'];
|
||||
$(document).on('page:change.merge_request', (function(_this) {
|
||||
$(document).on('DOMContentLoaded', (function(_this) {
|
||||
return function() {
|
||||
var page;
|
||||
page = $('body').data('page').split(':').last();
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
$('.js-rebase-button').html("<i class='fa fa-spinner fa-spin'></i> Rebase in progress");
|
||||
});
|
||||
} else {
|
||||
merge_request_widget.getMergeStatus();
|
||||
setTimeout(() => merge_request_widget.getMergeStatus(), 200);
|
||||
}
|
||||
});
|
||||
})();
|
||||
|
|
|
@ -2,13 +2,9 @@
|
|||
/* global Network */
|
||||
/* global ShortcutsNetwork */
|
||||
|
||||
// This is a manifest file that'll be compiled into including all the files listed below.
|
||||
// Add new JavaScript code in separate files in this directory and they'll automatically
|
||||
// be included in the compiled file accessible from http://example.com/assets/application.js
|
||||
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
|
||||
// the compiled file.
|
||||
//
|
||||
/*= require_tree . */
|
||||
// require everything else in this directory
|
||||
function requireAll(context) { return context.keys().map(context); }
|
||||
requireAll(require.context('.', false, /^\.\/(?!network_bundle).*\.(js|es6)$/));
|
||||
|
||||
(function() {
|
||||
$(function() {
|
||||
|
|
|
@ -4,13 +4,14 @@
|
|||
/* global ResolveService */
|
||||
/* global mrRefreshWidgetUrl */
|
||||
|
||||
/*= require autosave */
|
||||
/*= require autosize */
|
||||
/*= require dropzone */
|
||||
/*= require dropzone_input */
|
||||
/*= require gfm_auto_complete */
|
||||
/*= require jquery.atwho */
|
||||
/*= require task_list */
|
||||
require('./autosave');
|
||||
window.autosize = require('vendor/autosize');
|
||||
window.Dropzone = require('dropzone');
|
||||
require('./dropzone_input');
|
||||
require('./gfm_auto_complete');
|
||||
require('vendor/jquery.caret'); // required by jquery.atwho
|
||||
require('vendor/jquery.atwho');
|
||||
require('vendor/task_list');
|
||||
|
||||
(function() {
|
||||
var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; };
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* eslint-disable no-new, guard-for-in, no-restricted-syntax, no-continue, no-param-reassign, max-len */
|
||||
|
||||
//= require lib/utils/bootstrap_linked_tabs
|
||||
require('./lib/utils/bootstrap_linked_tabs');
|
||||
|
||||
((global) => {
|
||||
class Pipelines {
|
||||
|
|
|
@ -1,7 +1,3 @@
|
|||
/* eslint-disable func-names, space-before-function-paren */
|
||||
|
||||
/*= require_tree . */
|
||||
|
||||
(function() {
|
||||
|
||||
}).call(this);
|
||||
// require everything else in this directory
|
||||
function requireAll(context) { return context.keys().map(context); }
|
||||
requireAll(require.context('.', false, /^\.\/(?!profile_bundle).*\.(js|es6)$/));
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, quotes, consistent-return, no-new, prefer-arrow-callback, no-return-assign, one-var, one-var-declaration-per-line, object-shorthand, comma-dangle, no-else-return, newline-per-chained-call, no-shadow, vars-on-top, prefer-template, max-len */
|
||||
/* global Cookies */
|
||||
/* global Turbolinks */
|
||||
/* global ProjectSelect */
|
||||
|
||||
(function() {
|
||||
|
@ -58,6 +57,11 @@
|
|||
};
|
||||
|
||||
Project.prototype.initRefSwitcher = function() {
|
||||
var refListItem = document.createElement('li');
|
||||
var refLink = document.createElement('a');
|
||||
|
||||
refLink.href = '#';
|
||||
|
||||
return $('.js-project-refs-dropdown').each(function() {
|
||||
var $dropdown, selected;
|
||||
$dropdown = $(this);
|
||||
|
@ -67,7 +71,8 @@
|
|||
return $.ajax({
|
||||
url: $dropdown.data('refs-url'),
|
||||
data: {
|
||||
ref: $dropdown.data('ref')
|
||||
ref: $dropdown.data('ref'),
|
||||
search: term
|
||||
},
|
||||
dataType: "json"
|
||||
}).done(function(refs) {
|
||||
|
@ -76,16 +81,29 @@
|
|||
},
|
||||
selectable: true,
|
||||
filterable: true,
|
||||
filterRemote: true,
|
||||
filterByText: true,
|
||||
fieldName: $dropdown.data('field-name'),
|
||||
renderRow: function(ref) {
|
||||
var link;
|
||||
var li = refListItem.cloneNode(false);
|
||||
|
||||
if (ref.header != null) {
|
||||
return $('<li />').addClass('dropdown-header').text(ref.header);
|
||||
li.className = 'dropdown-header';
|
||||
li.textContent = ref.header;
|
||||
} else {
|
||||
link = $('<a />').attr('href', '#').addClass(ref === selected ? 'is-active' : '').text(ref).attr('data-ref', ref);
|
||||
return $('<li />').append(link);
|
||||
var link = refLink.cloneNode(false);
|
||||
|
||||
if (ref === selected) {
|
||||
link.className = 'is-active';
|
||||
}
|
||||
|
||||
link.textContent = ref;
|
||||
link.dataset.ref = ref;
|
||||
|
||||
li.appendChild(link);
|
||||
}
|
||||
|
||||
return li;
|
||||
},
|
||||
id: function(obj, $el) {
|
||||
return $el.attr('data-ref');
|
||||
|
@ -99,7 +117,7 @@
|
|||
var $form = $dropdown.closest('form');
|
||||
var action = $form.attr('action');
|
||||
var divider = action.indexOf('?') < 0 ? '?' : '&';
|
||||
Turbolinks.visit(action + '' + divider + '' + $form.serialize());
|
||||
gl.utils.visitUrl(action + '' + divider + '' + $form.serialize());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, wrap-iife, prefer-arrow-callback, max-len */
|
||||
/* global Turbolinks */
|
||||
|
||||
(function() {
|
||||
this.ProjectImport = (function() {
|
||||
function ProjectImport() {
|
||||
setTimeout(function() {
|
||||
return Turbolinks.visit(location.href);
|
||||
return gl.utils.visitUrl(location.href);
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ class ProtectedBranchDropdown {
|
|||
onClickCreateWildcard() {
|
||||
// Refresh the dropdown's data, which ends up calling `getProtectedBranches`
|
||||
this.$dropdown.data('glDropdown').remote.execute();
|
||||
this.$dropdown.data('glDropdown').selectRowAtIndex(0);
|
||||
this.$dropdown.data('glDropdown').selectRowAtIndex();
|
||||
}
|
||||
|
||||
getProtectedBranches(term, callback) {
|
||||
|
|
|
@ -1 +1,3 @@
|
|||
/*= require_tree . */
|
||||
// require everything else in this directory
|
||||
function requireAll(context) { return context.keys().map(context); }
|
||||
requireAll(require.context('.', false, /^\.\/(?!protected_branches_bundle).*\.(js|es6)$/));
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
this.find('.js-render-math').renderMath();
|
||||
};
|
||||
|
||||
$(document).on('ready page:load', function() {
|
||||
$(document).on('ready load', function() {
|
||||
return $('body').renderGFM();
|
||||
});
|
||||
}).call(this);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
/* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, quotes, prefer-arrow-callback, consistent-return, object-shorthand, no-unused-vars, one-var, one-var-declaration-per-line, no-else-return, comma-dangle, max-len */
|
||||
/* global Mousetrap */
|
||||
/* global Turbolinks */
|
||||
/* global findFileURL */
|
||||
|
||||
(function() {
|
||||
|
@ -23,7 +22,7 @@
|
|||
Mousetrap.bind(['ctrl+shift+p', 'command+shift+p'], this.toggleMarkdownPreview);
|
||||
if (typeof findFileURL !== "undefined" && findFileURL !== null) {
|
||||
Mousetrap.bind('t', function() {
|
||||
return Turbolinks.visit(findFileURL);
|
||||
return gl.utils.visitUrl(findFileURL);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue