From 4c5ff1d08ef5ddb7db432b864e18dd7674fbc116 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Tue, 18 Oct 2016 17:46:48 -0500 Subject: add webpack, webpack-rails, and webpack-dev-server along with a simple hello world test Add the following line to GDK Procfile to play with it: webpack: exec support/exec-cd gitlab npm run dev-server --- .eslintignore | 3 +- Gemfile | 2 ++ Gemfile.lock | 3 ++ Procfile | 1 + app/assets/javascripts/webpack/bundle.js | 1 + app/assets/javascripts/webpack/hello_world.js | 3 ++ app/views/layouts/_head.html.haml | 1 + config/application.rb | 5 +++ config/webpack.config.js | 46 +++++++++++++++++++++++++++ package.json | 6 ++++ 10 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/webpack/bundle.js create mode 100644 app/assets/javascripts/webpack/hello_world.js create mode 100644 config/webpack.config.js diff --git a/.eslintignore b/.eslintignore index b4bfa5a1f7a..a9d27a6765e 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,7 +1,8 @@ +/builds/ /coverage/ /coverage-javascript/ /node_modules/ /public/ /tmp/ /vendor/ -/builds/ +webpack.config.js diff --git a/Gemfile b/Gemfile index 2e8ad75fd71..27e415966df 100644 --- a/Gemfile +++ b/Gemfile @@ -214,6 +214,8 @@ gem 'oj', '~> 2.17.4' gem 'chronic', '~> 0.10.2' gem 'chronic_duration', '~> 0.10.6' +gem 'webpack-rails', '~> 0.9.9' + gem 'sass-rails', '~> 5.0.6' gem 'coffee-rails', '~> 4.1.0' gem 'uglifier', '~> 2.7.2' diff --git a/Gemfile.lock b/Gemfile.lock index c99313163a4..b88f51a7a43 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -779,6 +779,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) @@ -980,6 +982,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 diff --git a/Procfile b/Procfile index cad738d4292..5e8f4a962ab 100644 --- a/Procfile +++ b/Procfile @@ -4,4 +4,5 @@ # web: RAILS_ENV=development bin/web start_foreground worker: RAILS_ENV=development bin/background_jobs start_foreground +webpack: npm run dev-server # mail_room: bundle exec mail_room -q -c config/mail_room.yml diff --git a/app/assets/javascripts/webpack/bundle.js b/app/assets/javascripts/webpack/bundle.js new file mode 100644 index 00000000000..6c841b25771 --- /dev/null +++ b/app/assets/javascripts/webpack/bundle.js @@ -0,0 +1 @@ +require('./hello_world'); diff --git a/app/assets/javascripts/webpack/hello_world.js b/app/assets/javascripts/webpack/hello_world.js new file mode 100644 index 00000000000..5be69b187fd --- /dev/null +++ b/app/assets/javascripts/webpack/hello_world.js @@ -0,0 +1,3 @@ +/* eslint-disable no-console */ + +console.log('hello world!'); diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index 3096f0ee19e..87aadfb1bf5 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -29,6 +29,7 @@ = stylesheet_link_tag "print", media: "print" = javascript_include_tag "application" + = javascript_include_tag *webpack_asset_paths("bundle") - if content_for?(:page_specific_javascripts) = yield :page_specific_javascripts diff --git a/config/application.rb b/config/application.rb index d36c6d5c92e..02839dba1ed 100644 --- a/config/application.rb +++ b/config/application.rb @@ -80,6 +80,11 @@ module Gitlab # like if you have constraints or database-specific column types # config.active_record.schema_format = :sql + # Configure webpack + config.webpack.config_file = "config/webpack.config.js" + config.webpack.output_dir = "public/assets/webpack" + config.webpack.public_path = "assets/webpack" + # Enable the asset pipeline config.assets.enabled = true config.assets.paths << Gemojione.images_path diff --git a/config/webpack.config.js b/config/webpack.config.js new file mode 100644 index 00000000000..ea51c9d1af7 --- /dev/null +++ b/config/webpack.config.js @@ -0,0 +1,46 @@ +'use strict'; + +var path = require('path'); +var webpack = require('webpack'); +var StatsPlugin = require('stats-webpack-plugin'); + +var IS_PRODUCTION = process.env.NODE_ENV === 'production'; +var ROOT_PATH = path.resolve(__dirname, '..'); + +// must match config.webpack.dev_server.port +var DEV_SERVER_PORT = 3808; + +var config = { + context: ROOT_PATH, + entry: { + bundle: './app/assets/javascripts/webpack/bundle.js' + }, + + output: { + path: path.join(ROOT_PATH, 'public/assets/webpack'), + publicPath: '/assets/webpack/', + filename: IS_PRODUCTION ? '[name]-[chunkhash].js' : '[name].js' + }, + + plugins: [ + // manifest filename must match config.webpack.manifest_filename + // webpack-rails only needs assetsByChunkName to function properly + new StatsPlugin('manifest.json', { + chunkModules: false, + source: false, + chunks: false, + modules: false, + assets: true + }) + ] +} + +if (!IS_PRODUCTION) { + config.devServer = { + port: DEV_SERVER_PORT, + headers: { 'Access-Control-Allow-Origin': '*' } + }; + config.output.publicPath = '//localhost:' + DEV_SERVER_PORT + config.output.publicPath; +} + +module.exports = config; diff --git a/package.json b/package.json index 49b8210e427..de199c269db 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,16 @@ { "private": true, "scripts": { + "dev-server": "node_modules/.bin/webpack-dev-server --config config/webpack.config.js", "eslint": "eslint --max-warnings 0 --ext .js,.js.es6 .", "eslint-fix": "npm run eslint -- --fix", "eslint-report": "npm run eslint -- --format html --output-file ./eslint-report.html" }, + "dependencies": { + "stats-webpack-plugin": "^0.4.2", + "webpack": "^1.13.2", + "webpack-dev-server": "^1.16.2" + }, "devDependencies": { "eslint": "^3.10.1", "eslint-config-airbnb-base": "^10.0.1", -- cgit v1.2.1 From df72d65a025fe2cd6778e560541b7784d5bed6ef Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Wed, 19 Oct 2016 14:29:43 -0500 Subject: compile es6/es2015 with babel --- app/assets/javascripts/webpack/bundle.js | 5 ++++- app/assets/javascripts/webpack/hello_world.js | 3 --- app/assets/javascripts/webpack/hello_world.js.es6 | 11 +++++++++++ config/webpack.config.js | 19 ++++++++++++++++++- package.json | 3 +++ 5 files changed, 36 insertions(+), 5 deletions(-) delete mode 100644 app/assets/javascripts/webpack/hello_world.js create mode 100644 app/assets/javascripts/webpack/hello_world.js.es6 diff --git a/app/assets/javascripts/webpack/bundle.js b/app/assets/javascripts/webpack/bundle.js index 6c841b25771..b8e38151e5f 100644 --- a/app/assets/javascripts/webpack/bundle.js +++ b/app/assets/javascripts/webpack/bundle.js @@ -1 +1,4 @@ -require('./hello_world'); +var HelloWorld = require('./hello_world').default; + +var message = new HelloWorld('webpack'); +message.sayHello(); diff --git a/app/assets/javascripts/webpack/hello_world.js b/app/assets/javascripts/webpack/hello_world.js deleted file mode 100644 index 5be69b187fd..00000000000 --- a/app/assets/javascripts/webpack/hello_world.js +++ /dev/null @@ -1,3 +0,0 @@ -/* eslint-disable no-console */ - -console.log('hello world!'); diff --git a/app/assets/javascripts/webpack/hello_world.js.es6 b/app/assets/javascripts/webpack/hello_world.js.es6 new file mode 100644 index 00000000000..b3d7c9dd4d4 --- /dev/null +++ b/app/assets/javascripts/webpack/hello_world.js.es6 @@ -0,0 +1,11 @@ +/* eslint-disable no-undef, no-alert */ + +export default class HelloWorld { + constructor(name) { + this.message = `Hello ${name}!`; + } + + sayHello() { + alert(this.message); + } +} diff --git a/config/webpack.config.js b/config/webpack.config.js index ea51c9d1af7..b4892a11ad0 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -22,6 +22,19 @@ var config = { filename: IS_PRODUCTION ? '[name]-[chunkhash].js' : '[name].js' }, + module: { + loaders: [ + { + test: /\.es6$/, + exclude: /node_modules/, + loader: 'babel-loader', + query: { + presets: ['es2015'] + } + } + ] + }, + plugins: [ // manifest filename must match config.webpack.manifest_filename // webpack-rails only needs assetsByChunkName to function properly @@ -32,7 +45,11 @@ var config = { modules: false, assets: true }) - ] + ], + + resolve: { + extensions: ['', '.js', '.es6', '.js.es6'] + } } if (!IS_PRODUCTION) { diff --git a/package.json b/package.json index de199c269db..526a3c34e01 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,9 @@ "eslint-report": "npm run eslint -- --format html --output-file ./eslint-report.html" }, "dependencies": { + "babel-core": "^6.17.0", + "babel-loader": "^6.2.5", + "babel-preset-es2015": "^6.16.0", "stats-webpack-plugin": "^0.4.2", "webpack": "^1.13.2", "webpack-dev-server": "^1.16.2" -- cgit v1.2.1 From 61ca496b3227b977e5bbf4001e1a88e398c87737 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Wed, 19 Oct 2016 15:47:49 -0500 Subject: optimize production output and generate sourcemaps --- config/webpack.config.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/config/webpack.config.js b/config/webpack.config.js index b4892a11ad0..5d285e5fc40 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -22,6 +22,8 @@ var config = { filename: IS_PRODUCTION ? '[name]-[chunkhash].js' : '[name].js' }, + devtool: 'source-map', + module: { loaders: [ { @@ -52,7 +54,19 @@ var config = { } } -if (!IS_PRODUCTION) { +if (IS_PRODUCTION) { + config.plugins.push( + new webpack.NoErrorsPlugin(), + new webpack.optimize.UglifyJsPlugin({ + compress: { warnings: false } + }), + new webpack.DefinePlugin({ + 'process.env': { NODE_ENV: JSON.stringify('production') } + }), + new webpack.optimize.DedupePlugin(), + new webpack.optimize.OccurrenceOrderPlugin() + ); +} else { config.devServer = { port: DEV_SERVER_PORT, headers: { 'Access-Control-Allow-Origin': '*' } -- cgit v1.2.1 From 000180e5e469c39f626faccf91cdb2b1d25a97f8 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Wed, 19 Oct 2016 15:56:42 -0500 Subject: conditionally apply webpack-dev-server config --- config/webpack.config.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/config/webpack.config.js b/config/webpack.config.js index 5d285e5fc40..2aa1e8d7dd7 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -5,6 +5,7 @@ var webpack = require('webpack'); var StatsPlugin = require('stats-webpack-plugin'); var IS_PRODUCTION = process.env.NODE_ENV === 'production'; +var IS_DEV_SERVER = process.argv[1].indexOf('webpack-dev-server') !== -1; var ROOT_PATH = path.resolve(__dirname, '..'); // must match config.webpack.dev_server.port @@ -66,7 +67,9 @@ if (IS_PRODUCTION) { new webpack.optimize.DedupePlugin(), new webpack.optimize.OccurrenceOrderPlugin() ); -} else { +} + +if (IS_DEV_SERVER) { config.devServer = { port: DEV_SERVER_PORT, headers: { 'Access-Control-Allow-Origin': '*' } -- cgit v1.2.1 From 31bd36845ba1c18404f029f85b6a0f841c1c390c Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 20 Oct 2016 00:32:56 -0500 Subject: temporarily regress to babel 5 for parity with sprockets-es6 gem --- config/webpack.config.js | 5 +---- package.json | 6 +++--- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/config/webpack.config.js b/config/webpack.config.js index 2aa1e8d7dd7..acd5597da3a 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -30,10 +30,7 @@ var config = { { test: /\.es6$/, exclude: /node_modules/, - loader: 'babel-loader', - query: { - presets: ['es2015'] - } + loader: 'babel-loader' } ] }, diff --git a/package.json b/package.json index 526a3c34e01..b089eb805c7 100644 --- a/package.json +++ b/package.json @@ -7,9 +7,9 @@ "eslint-report": "npm run eslint -- --format html --output-file ./eslint-report.html" }, "dependencies": { - "babel-core": "^6.17.0", - "babel-loader": "^6.2.5", - "babel-preset-es2015": "^6.16.0", + "babel": "^5.8.38", + "babel-core": "^5.8.38", + "babel-loader": "^5.4.2", "stats-webpack-plugin": "^0.4.2", "webpack": "^1.13.2", "webpack-dev-server": "^1.16.2" -- cgit v1.2.1 From 55f291e8ceae6d3d432039f72f6935c62fb2a872 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 28 Oct 2016 03:22:02 -0500 Subject: replace application.js sprockets output with webpack-generated equivalent --- app/assets/javascripts/application.js | 1 + .../javascripts/lib/utils/datetime_utility.js | 2 +- app/assets/javascripts/users/calendar.js | 4 +- app/assets/javascripts/webpack/application.js | 293 +++++ app/assets/javascripts/webpack/bundle.js | 4 - app/assets/javascripts/webpack/hello_world.js.es6 | 11 - app/views/layouts/_head.html.haml | 3 +- config/webpack.config.js | 20 +- package.json | 13 + vendor/assets/javascripts/jquery.atwho.js | 1202 ++++++++++++++++++++ vendor/assets/javascripts/jquery.caret.js | 436 +++++++ vendor/assets/javascripts/jquery.turbolinks.js | 49 + vendor/assets/javascripts/turbolinks.js | 781 +++++++++++++ 13 files changed, 2797 insertions(+), 22 deletions(-) create mode 100644 app/assets/javascripts/webpack/application.js delete mode 100644 app/assets/javascripts/webpack/bundle.js delete mode 100644 app/assets/javascripts/webpack/hello_world.js.es6 create mode 100644 vendor/assets/javascripts/jquery.atwho.js create mode 100644 vendor/assets/javascripts/jquery.caret.js create mode 100644 vendor/assets/javascripts/jquery.turbolinks.js create mode 100644 vendor/assets/javascripts/turbolinks.js diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index e43afbb4cc9..c21f0572fa7 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -22,6 +22,7 @@ /*= require jquery.endless-scroll */ /*= require jquery.highlight */ /*= require jquery.waitforimages */ +/*= require jquery.caret */ /*= require jquery.atwho */ /*= require jquery.scrollTo */ /*= require jquery.turbolinks */ diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js index e8e502694d6..30e4e490543 100644 --- a/app/assets/javascripts/lib/utils/datetime_utility.js +++ b/app/assets/javascripts/lib/utils/datetime_utility.js @@ -17,7 +17,7 @@ w.gl.utils.days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; w.gl.utils.formatDate = function(datetime) { - return dateFormat(datetime, 'mmm d, yyyy h:MMtt Z'); + return (new Date(datetime)).format('mmm d, yyyy h:MMtt Z'); }; w.gl.utils.getDayName = function(date) { diff --git a/app/assets/javascripts/users/calendar.js b/app/assets/javascripts/users/calendar.js index 578be7c3590..43ee6a9d9fd 100644 --- a/app/assets/javascripts/users/calendar.js +++ b/app/assets/javascripts/users/calendar.js @@ -33,7 +33,7 @@ date.setDate(date.getDate() + i); var day = date.getDay(); - var count = timestamps[dateFormat(date, 'yyyy-mm-dd')]; + var count = timestamps[date.format('yyyy-mm-dd')]; // Create a new group array if this is the first day of the week // or if is first object @@ -122,7 +122,7 @@ if (stamp.count > 0) { contribText = stamp.count + " contribution" + (stamp.count > 1 ? 's' : ''); } - dateText = dateFormat(date, 'mmm d, yyyy'); + dateText = date.format('mmm d, yyyy'); return contribText + "
" + (gl.utils.getDayName(date)) + " " + dateText; }; })(this)).attr('class', 'user-contrib-cell js-tooltip').attr('fill', (function(_this) { diff --git a/app/assets/javascripts/webpack/application.js b/app/assets/javascripts/webpack/application.js new file mode 100644 index 00000000000..660e00d4c5b --- /dev/null +++ b/app/assets/javascripts/webpack/application.js @@ -0,0 +1,293 @@ +/* eslint-disable */ + +/** + * Simulate sprockets compile order of application.js through CommonJS require statements + * + * Currently exports everything appropriate to window until the scripts that rely on this behavior + * can be refactored. + * + * Test the output from this against sprockets output and it should be almost identical apart from + * webpack's CommonJS wrapper. You can add the following line to webpack.config.js to fix the + * script indentation: + * config.output.sourcePrefix = ''; + */ + +/*= require jquery2 */ +window.jQuery = window.$ = require('jquery'); + +/*= require jquery-ui/autocomplete */ +// depends on jquery-ui/core, jquery-ui/widget, jquery-ui/menu, jquery-ui/position +require('jquery-ui/ui/core'); +require('jquery-ui/ui/widget'); +require('jquery-ui/ui/position'); +require('jquery-ui/ui/menu'); +require('jquery-ui/ui/autocomplete'); + +/*= require jquery-ui/datepicker */ +// depends on jquery-ui/core +require('jquery-ui/ui/datepicker'); + +/*= require jquery-ui/draggable */ +// depends on jquery-ui/core, jquery-ui/widget, jquery-ui/mouse +require('jquery-ui/ui/mouse'); +require('jquery-ui/ui/draggable'); + +/*= require jquery-ui/effect-highlight */ +// depends on jquery-ui/effect +require('jquery-ui/ui/effect'); +require('jquery-ui/ui/effect-highlight'); + +/*= require jquery-ui/sortable */ +// depends on jquery-ui/core, jquery-ui/widget, jquery-ui/mouse +require('jquery-ui/ui/sortable'); + +/*= require jquery_ujs */ +require('jquery-ujs'); + +/*= require jquery.endless-scroll */ +require('vendor/jquery.endless-scroll'); + +/*= require jquery.highlight */ +require('vendor/jquery.highlight'); + +/*= require jquery.waitforimages */ +require('vendor/jquery.waitforimages'); + +/*= require jquery.atwho */ +require('vendor/jquery.caret'); // required by jquery.atwho +require('vendor/jquery.atwho'); + +/*= require jquery.scrollTo */ +require('vendor/jquery.scrollTo'); + +/*= require jquery.turbolinks */ +require('vendor/jquery.turbolinks'); + +/*= require js.cookie */ +window.Cookies = require('vendor/js.cookie'); + +/*= require turbolinks */ +require('vendor/turbolinks'); + +/*= require autosave */ +require('../autosave'); + +/*= require bootstrap/affix */ +require('bootstrap/js/affix'); + +/*= require bootstrap/alert */ +require('bootstrap/js/alert'); + +/*= require bootstrap/button */ +require('bootstrap/js/button'); + +/*= require bootstrap/collapse */ +require('bootstrap/js/collapse'); + +/*= require bootstrap/dropdown */ +require('bootstrap/js/dropdown'); + +/*= require bootstrap/modal */ +require('bootstrap/js/modal'); + +/*= require bootstrap/scrollspy */ +require('bootstrap/js/scrollspy'); + +/*= require bootstrap/tab */ +require('bootstrap/js/tab'); + +/*= require bootstrap/transition */ +require('bootstrap/js/transition'); + +/*= require bootstrap/tooltip */ +require('bootstrap/js/tooltip'); + +/*= require bootstrap/popover */ +require('bootstrap/js/popover'); + +/*= require select2 */ +require('select2/select2.js'); + +/*= require underscore */ +window._ = require('underscore'); + +/*= require dropzone */ +window.Dropzone = require('dropzone'); + +/*= require mousetrap */ +require('mousetrap'); + +/*= require mousetrap/pause */ +require('mousetrap/plugins/pause/mousetrap-pause'); + +/*= require shortcuts */ +require('../shortcuts'); + +/*= require shortcuts_navigation */ +require('../shortcuts_navigation'); + +/*= require shortcuts_dashboard_navigation */ +require('../shortcuts_dashboard_navigation'); + +/*= require shortcuts_issuable */ +require('../shortcuts_issuable'); + +/*= require shortcuts_network */ +require('../shortcuts_network'); + +/*= require jquery.nicescroll */ +require('vendor/jquery.nicescroll'); + +/*= require date.format */ +require('vendor/date.format'); + +/*= require_directory ./behaviors */ +require('vendor/jquery.ba-resize'); +window.autosize = require('vendor/autosize'); +require('../behaviors/autosize'); // requires vendor/jquery.ba-resize and vendor/autosize +require('../behaviors/details_behavior'); +require('../extensions/jquery'); +require('../behaviors/quick_submit'); // requires extensions/jquery +require('../behaviors/requires_input'); +require('../behaviors/toggler_behavior'); + +/*= require_directory ./blob */ +require('../blob/template_selector'); +require('../blob/blob_ci_yaml'); // requires template_selector +require('../blob/blob_file_dropzone'); +require('../blob/blob_gitignore_selector'); +require('../blob/blob_gitignore_selectors'); +require('../blob/blob_license_selector'); +require('../blob/blob_license_selectors'); + +/*= require_directory ./templates */ +require('../templates/issuable_template_selector'); +require('../templates/issuable_template_selectors'); + +/*= require_directory ./commit */ +require('../commit/file'); +require('../commit/image_file'); + +/*= require_directory ./extensions */ +require('../extensions/array'); +require('../extensions/element'); + +/*= require_directory ./lib/utils */ +require('../lib/utils/animate'); +require('../lib/utils/common_utils'); +require('../lib/utils/datetime_utility'); +// require('../lib/utils/emoji_aliases.js.erb'); +window.gl.emojiAliases = function() { return require('emoji-aliases'); }; +require('../lib/utils/jquery.timeago'); +require('../lib/utils/notify'); +require('../lib/utils/text_utility'); +require('../lib/utils/type_utility'); +require('../lib/utils/url_utility'); + +/*= require_directory ./u2f */ +require('../u2f/authenticate'); +require('../u2f/error'); +require('../u2f/register'); +require('../u2f/util'); + +/*= require_directory . */ +require('../abuse_reports'); +require('../activities'); +require('../admin'); +require('../api'); +require('../aside'); +require('../awards_handler'); +require('../breakpoints'); +require('../broadcast_message'); +require('../build'); +require('../build_artifacts'); +require('../build_variables'); +require('../commit'); +require('../commits'); +require('../compare'); +require('../compare_autocomplete'); +require('../confirm_danger_modal'); +window.Clipboard = require('vendor/clipboard'); // required by copy_to_clipboard +require('../copy_to_clipboard'); +require('../create_label'); +require('vue'); // required by cycle_analytics +require('../cycle_analytics'); +require('../diff'); +require('../dispatcher'); +require('../preview_markdown'); +require('../dropzone_input'); +require('../due_date_select'); +require('../files_comment_button'); +require('../flash'); +require('../gfm_auto_complete'); +require('../gl_dropdown'); +require('../gl_field_errors'); +require('../gl_form'); +require('../group_avatar'); +require('../groups_select'); +require('../header'); +require('../importer_status'); +require('../issuable'); +require('../issuable_context'); +require('../issuable_form'); +require('vendor/task_list'); // required by issue +require('../issue'); +require('../issue_status_select'); +require('../issues_bulk_assignment'); +require('../label_manager'); +require('../labels'); +require('../labels_select'); +require('../layout_nav'); +require('../line_highlighter'); +require('../logo'); +require('../member_expiration_date'); +require('../members'); +require('../merge_request_tabs'); +require('../merge_request'); +require('../merge_request_widget'); +require('../merged_buttons'); +require('../milestone'); +require('../milestone_select'); +require('../namespace_select'); +require('../new_branch_form'); +require('../new_commit_form'); +require('../notes'); +require('../notifications_dropdown'); +require('../notifications_form'); +require('../pager'); +require('../pipelines'); +require('../project'); +require('../project_avatar'); +require('../project_find_file'); +require('../project_fork'); +require('../project_import'); +require('../project_new'); +require('../project_select'); +require('../project_show'); +require('../projects_list'); +require('../right_sidebar'); +require('../search'); +require('../search_autocomplete'); +require('../shortcuts_blob'); +require('../shortcuts_find_file'); +require('../sidebar'); +require('../single_file_diff'); +require('../snippets_list'); +require('../star'); +require('../subscription'); +require('../subscription_select'); +require('../syntax_highlight'); +require('../todos'); +require('../tree'); +require('../user'); +require('../user_tabs'); +require('../username_validator'); +require('../users_select'); +require('vendor/latinise'); // required by wikis +require('../wikis'); +require('../zen_mode'); + +/*= require fuzzaldrin-plus */ +require('vendor/fuzzaldrin-plus'); + +require('../application'); diff --git a/app/assets/javascripts/webpack/bundle.js b/app/assets/javascripts/webpack/bundle.js deleted file mode 100644 index b8e38151e5f..00000000000 --- a/app/assets/javascripts/webpack/bundle.js +++ /dev/null @@ -1,4 +0,0 @@ -var HelloWorld = require('./hello_world').default; - -var message = new HelloWorld('webpack'); -message.sayHello(); diff --git a/app/assets/javascripts/webpack/hello_world.js.es6 b/app/assets/javascripts/webpack/hello_world.js.es6 deleted file mode 100644 index b3d7c9dd4d4..00000000000 --- a/app/assets/javascripts/webpack/hello_world.js.es6 +++ /dev/null @@ -1,11 +0,0 @@ -/* eslint-disable no-undef, no-alert */ - -export default class HelloWorld { - constructor(name) { - this.message = `Hello ${name}!`; - } - - sayHello() { - alert(this.message); - } -} diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index 87aadfb1bf5..d260e2133f2 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -28,8 +28,7 @@ = stylesheet_link_tag "application", media: "all" = stylesheet_link_tag "print", media: "print" - = javascript_include_tag "application" - = javascript_include_tag *webpack_asset_paths("bundle") + = javascript_include_tag *webpack_asset_paths("application") - if content_for?(:page_specific_javascripts) = yield :page_specific_javascripts diff --git a/config/webpack.config.js b/config/webpack.config.js index acd5597da3a..d45638fbcbd 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -14,7 +14,7 @@ var DEV_SERVER_PORT = 3808; var config = { context: ROOT_PATH, entry: { - bundle: './app/assets/javascripts/webpack/bundle.js' + application: './app/assets/javascripts/webpack/application.js' }, output: { @@ -31,6 +31,15 @@ var config = { test: /\.es6$/, exclude: /node_modules/, loader: 'babel-loader' + }, + { + test: /\.(js|es6)$/, + loader: 'imports-loader', + query: 'this=>window' + }, + { + test: /\.json$/, + loader: 'json-loader' } ] }, @@ -48,7 +57,14 @@ var config = { ], resolve: { - extensions: ['', '.js', '.es6', '.js.es6'] + extensions: ['', '.js', '.es6', '.js.es6'], + alias: { + 'bootstrap/js': 'bootstrap-sass/assets/javascripts/bootstrap', + 'emoji-aliases$': path.join(ROOT_PATH, 'fixtures/emojis/aliases.json'), + 'vendor': path.join(ROOT_PATH, 'vendor/assets/javascripts'), + 'vue$': 'vue/dist/vue.js', + 'vue-resource$': 'vue-resource/dist/vue-resource.js' + } } } diff --git a/package.json b/package.json index b089eb805c7..7ef811ae478 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,20 @@ "babel": "^5.8.38", "babel-core": "^5.8.38", "babel-loader": "^5.4.2", + "bootstrap-sass": "3.3.6", + "dropzone": "4.2.0", + "exports-loader": "^0.6.3", + "imports-loader": "^0.6.5", + "jquery": "2.2.1", + "jquery-ui": "github:jquery/jquery-ui#1.11.4", + "jquery-ujs": "1.2.1", + "json-loader": "^0.5.4", + "mousetrap": "1.4.6", + "select2": "3.5.2-browserify", "stats-webpack-plugin": "^0.4.2", + "underscore": "1.8.3", + "vue": "1.0.26", + "vue-resource": "0.9.3", "webpack": "^1.13.2", "webpack-dev-server": "^1.16.2" }, diff --git a/vendor/assets/javascripts/jquery.atwho.js b/vendor/assets/javascripts/jquery.atwho.js new file mode 100644 index 00000000000..0d295ebe5af --- /dev/null +++ b/vendor/assets/javascripts/jquery.atwho.js @@ -0,0 +1,1202 @@ +/** + * at.js - 1.5.1 + * Copyright (c) 2016 chord.luo ; + * Homepage: http://ichord.github.com/At.js + * License: MIT + */ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define(["jquery"], function (a0) { + return (factory(a0)); + }); + } else if (typeof exports === 'object') { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(require("jquery")); + } else { + factory(jQuery); + } +}(this, function ($) { +var DEFAULT_CALLBACKS, KEY_CODE; + +KEY_CODE = { + DOWN: 40, + UP: 38, + ESC: 27, + TAB: 9, + ENTER: 13, + CTRL: 17, + A: 65, + P: 80, + N: 78, + LEFT: 37, + UP: 38, + RIGHT: 39, + DOWN: 40, + BACKSPACE: 8, + SPACE: 32 +}; + +DEFAULT_CALLBACKS = { + beforeSave: function(data) { + return Controller.arrayToDefaultHash(data); + }, + matcher: function(flag, subtext, should_startWithSpace, acceptSpaceBar) { + var _a, _y, match, regexp, space; + flag = flag.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&"); + if (should_startWithSpace) { + flag = '(?:^|\\s)' + flag; + } + _a = decodeURI("%C3%80"); + _y = decodeURI("%C3%BF"); + space = acceptSpaceBar ? "\ " : ""; + regexp = new RegExp(flag + "([A-Za-z" + _a + "-" + _y + "0-9_" + space + "\'\.\+\-]*)$|" + flag + "([^\\x00-\\xff]*)$", 'gi'); + match = regexp.exec(subtext); + if (match) { + return match[2] || match[1]; + } else { + return null; + } + }, + filter: function(query, data, searchKey) { + var _results, i, item, len; + _results = []; + for (i = 0, len = data.length; i < len; i++) { + item = data[i]; + if (~new String(item[searchKey]).toLowerCase().indexOf(query.toLowerCase())) { + _results.push(item); + } + } + return _results; + }, + remoteFilter: null, + sorter: function(query, items, searchKey) { + var _results, i, item, len; + if (!query) { + return items; + } + _results = []; + for (i = 0, len = items.length; i < len; i++) { + item = items[i]; + item.atwho_order = new String(item[searchKey]).toLowerCase().indexOf(query.toLowerCase()); + if (item.atwho_order > -1) { + _results.push(item); + } + } + return _results.sort(function(a, b) { + return a.atwho_order - b.atwho_order; + }); + }, + tplEval: function(tpl, map) { + var error, error1, template; + template = tpl; + try { + if (typeof tpl !== 'string') { + template = tpl(map); + } + return template.replace(/\$\{([^\}]*)\}/g, function(tag, key, pos) { + return map[key]; + }); + } catch (error1) { + error = error1; + return ""; + } + }, + highlighter: function(li, query) { + var regexp; + if (!query) { + return li; + } + regexp = new RegExp(">\\s*(\\w*?)(" + query.replace("+", "\\+") + ")(\\w*)\\s*<", 'ig'); + return li.replace(regexp, function(str, $1, $2, $3) { + return '> ' + $1 + '' + $2 + '' + $3 + ' <'; + }); + }, + beforeInsert: function(value, $li, e) { + return value; + }, + beforeReposition: function(offset) { + return offset; + }, + afterMatchFailed: function(at, el) {} +}; + +var App; + +App = (function() { + function App(inputor) { + this.currentFlag = null; + this.controllers = {}; + this.aliasMaps = {}; + this.$inputor = $(inputor); + this.setupRootElement(); + this.listen(); + } + + App.prototype.createContainer = function(doc) { + var ref; + if ((ref = this.$el) != null) { + ref.remove(); + } + return $(doc.body).append(this.$el = $("
")); + }; + + App.prototype.setupRootElement = function(iframe, asRoot) { + var error, error1; + if (asRoot == null) { + asRoot = false; + } + if (iframe) { + this.window = iframe.contentWindow; + this.document = iframe.contentDocument || this.window.document; + this.iframe = iframe; + } else { + this.document = this.$inputor[0].ownerDocument; + this.window = this.document.defaultView || this.document.parentWindow; + try { + this.iframe = this.window.frameElement; + } catch (error1) { + error = error1; + this.iframe = null; + if ($.fn.atwho.debug) { + throw new Error("iframe auto-discovery is failed.\nPlease use `setIframe` to set the target iframe manually.\n" + error); + } + } + } + return this.createContainer((this.iframeAsRoot = asRoot) ? this.document : document); + }; + + App.prototype.controller = function(at) { + var c, current, currentFlag, ref; + if (this.aliasMaps[at]) { + current = this.controllers[this.aliasMaps[at]]; + } else { + ref = this.controllers; + for (currentFlag in ref) { + c = ref[currentFlag]; + if (currentFlag === at) { + current = c; + break; + } + } + } + if (current) { + return current; + } else { + return this.controllers[this.currentFlag]; + } + }; + + App.prototype.setContextFor = function(at) { + this.currentFlag = at; + return this; + }; + + App.prototype.reg = function(flag, setting) { + var base, controller; + controller = (base = this.controllers)[flag] || (base[flag] = this.$inputor.is('[contentEditable]') ? new EditableController(this, flag) : new TextareaController(this, flag)); + if (setting.alias) { + this.aliasMaps[setting.alias] = flag; + } + controller.init(setting); + return this; + }; + + App.prototype.listen = function() { + return this.$inputor.on('compositionstart', (function(_this) { + return function(e) { + var ref; + if ((ref = _this.controller()) != null) { + ref.view.hide(); + } + _this.isComposing = true; + return null; + }; + })(this)).on('compositionend', (function(_this) { + return function(e) { + _this.isComposing = false; + setTimeout(function(e) { + return _this.dispatch(e); + }); + return null; + }; + })(this)).on('keyup.atwhoInner', (function(_this) { + return function(e) { + return _this.onKeyup(e); + }; + })(this)).on('keydown.atwhoInner', (function(_this) { + return function(e) { + return _this.onKeydown(e); + }; + })(this)).on('blur.atwhoInner', (function(_this) { + return function(e) { + var c; + if (c = _this.controller()) { + c.expectedQueryCBId = null; + return c.view.hide(e, c.getOpt("displayTimeout")); + } + }; + })(this)).on('click.atwhoInner', (function(_this) { + return function(e) { + return _this.dispatch(e); + }; + })(this)).on('scroll.atwhoInner', (function(_this) { + return function() { + var lastScrollTop; + lastScrollTop = _this.$inputor.scrollTop(); + return function(e) { + var currentScrollTop, ref; + currentScrollTop = e.target.scrollTop; + if (lastScrollTop !== currentScrollTop) { + if ((ref = _this.controller()) != null) { + ref.view.hide(e); + } + } + lastScrollTop = currentScrollTop; + return true; + }; + }; + })(this)()); + }; + + App.prototype.shutdown = function() { + var _, c, ref; + ref = this.controllers; + for (_ in ref) { + c = ref[_]; + c.destroy(); + delete this.controllers[_]; + } + this.$inputor.off('.atwhoInner'); + return this.$el.remove(); + }; + + App.prototype.dispatch = function(e) { + var _, c, ref, results; + ref = this.controllers; + results = []; + for (_ in ref) { + c = ref[_]; + results.push(c.lookUp(e)); + } + return results; + }; + + App.prototype.onKeyup = function(e) { + var ref; + switch (e.keyCode) { + case KEY_CODE.ESC: + e.preventDefault(); + if ((ref = this.controller()) != null) { + ref.view.hide(); + } + break; + case KEY_CODE.DOWN: + case KEY_CODE.UP: + case KEY_CODE.CTRL: + case KEY_CODE.ENTER: + $.noop(); + break; + case KEY_CODE.P: + case KEY_CODE.N: + if (!e.ctrlKey) { + this.dispatch(e); + } + break; + default: + this.dispatch(e); + } + }; + + App.prototype.onKeydown = function(e) { + var ref, view; + view = (ref = this.controller()) != null ? ref.view : void 0; + if (!(view && view.visible())) { + return; + } + switch (e.keyCode) { + case KEY_CODE.ESC: + e.preventDefault(); + view.hide(e); + break; + case KEY_CODE.UP: + e.preventDefault(); + view.prev(); + break; + case KEY_CODE.DOWN: + e.preventDefault(); + view.next(); + break; + case KEY_CODE.P: + if (!e.ctrlKey) { + return; + } + e.preventDefault(); + view.prev(); + break; + case KEY_CODE.N: + if (!e.ctrlKey) { + return; + } + e.preventDefault(); + view.next(); + break; + case KEY_CODE.TAB: + case KEY_CODE.ENTER: + case KEY_CODE.SPACE: + if (!view.visible()) { + return; + } + if (!this.controller().getOpt('spaceSelectsMatch') && e.keyCode === KEY_CODE.SPACE) { + return; + } + if (!this.controller().getOpt('tabSelectsMatch') && e.keyCode === KEY_CODE.TAB) { + return; + } + if (view.highlighted()) { + e.preventDefault(); + view.choose(e); + } else { + view.hide(e); + } + break; + default: + $.noop(); + } + }; + + return App; + +})(); + +var Controller, + slice = [].slice; + +Controller = (function() { + Controller.prototype.uid = function() { + return (Math.random().toString(16) + "000000000").substr(2, 8) + (new Date().getTime()); + }; + + function Controller(app, at1) { + this.app = app; + this.at = at1; + this.$inputor = this.app.$inputor; + this.id = this.$inputor[0].id || this.uid(); + this.expectedQueryCBId = null; + this.setting = null; + this.query = null; + this.pos = 0; + this.range = null; + if ((this.$el = $("#atwho-ground-" + this.id, this.app.$el)).length === 0) { + this.app.$el.append(this.$el = $("
")); + } + this.model = new Model(this); + this.view = new View(this); + } + + Controller.prototype.init = function(setting) { + this.setting = $.extend({}, this.setting || $.fn.atwho["default"], setting); + this.view.init(); + return this.model.reload(this.setting.data); + }; + + Controller.prototype.destroy = function() { + this.trigger('beforeDestroy'); + this.model.destroy(); + this.view.destroy(); + return this.$el.remove(); + }; + + Controller.prototype.callDefault = function() { + var args, error, error1, funcName; + funcName = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; + try { + return DEFAULT_CALLBACKS[funcName].apply(this, args); + } catch (error1) { + error = error1; + return $.error(error + " Or maybe At.js doesn't have function " + funcName); + } + }; + + Controller.prototype.trigger = function(name, data) { + var alias, eventName; + if (data == null) { + data = []; + } + data.push(this); + alias = this.getOpt('alias'); + eventName = alias ? name + "-" + alias + ".atwho" : name + ".atwho"; + return this.$inputor.trigger(eventName, data); + }; + + Controller.prototype.callbacks = function(funcName) { + return this.getOpt("callbacks")[funcName] || DEFAULT_CALLBACKS[funcName]; + }; + + Controller.prototype.getOpt = function(at, default_value) { + var e, error1; + try { + return this.setting[at]; + } catch (error1) { + e = error1; + return null; + } + }; + + Controller.prototype.insertContentFor = function($li) { + var data, tpl; + tpl = this.getOpt('insertTpl'); + data = $.extend({}, $li.data('item-data'), { + 'atwho-at': this.at + }); + return this.callbacks("tplEval").call(this, tpl, data, "onInsert"); + }; + + Controller.prototype.renderView = function(data) { + var searchKey; + searchKey = this.getOpt("searchKey"); + data = this.callbacks("sorter").call(this, this.query.text, data.slice(0, 1001), searchKey); + return this.view.render(data.slice(0, this.getOpt('limit'))); + }; + + Controller.arrayToDefaultHash = function(data) { + var i, item, len, results; + if (!$.isArray(data)) { + return data; + } + results = []; + for (i = 0, len = data.length; i < len; i++) { + item = data[i]; + if ($.isPlainObject(item)) { + results.push(item); + } else { + results.push({ + name: item + }); + } + } + return results; + }; + + Controller.prototype.lookUp = function(e) { + var query, wait; + if (e && e.type === 'click' && !this.getOpt('lookUpOnClick')) { + return; + } + if (this.getOpt('suspendOnComposing') && this.app.isComposing) { + return; + } + query = this.catchQuery(e); + if (!query) { + this.expectedQueryCBId = null; + return query; + } + this.app.setContextFor(this.at); + if (wait = this.getOpt('delay')) { + this._delayLookUp(query, wait); + } else { + this._lookUp(query); + } + return query; + }; + + Controller.prototype._delayLookUp = function(query, wait) { + var now, remaining; + now = Date.now ? Date.now() : new Date().getTime(); + this.previousCallTime || (this.previousCallTime = now); + remaining = wait - (now - this.previousCallTime); + if ((0 < remaining && remaining < wait)) { + this.previousCallTime = now; + this._stopDelayedCall(); + return this.delayedCallTimeout = setTimeout((function(_this) { + return function() { + _this.previousCallTime = 0; + _this.delayedCallTimeout = null; + return _this._lookUp(query); + }; + })(this), wait); + } else { + this._stopDelayedCall(); + if (this.previousCallTime !== now) { + this.previousCallTime = 0; + } + return this._lookUp(query); + } + }; + + Controller.prototype._stopDelayedCall = function() { + if (this.delayedCallTimeout) { + clearTimeout(this.delayedCallTimeout); + return this.delayedCallTimeout = null; + } + }; + + Controller.prototype._generateQueryCBId = function() { + return {}; + }; + + Controller.prototype._lookUp = function(query) { + var _callback; + _callback = function(queryCBId, data) { + if (queryCBId !== this.expectedQueryCBId) { + return; + } + if (data && data.length > 0) { + return this.renderView(this.constructor.arrayToDefaultHash(data)); + } else { + return this.view.hide(); + } + }; + this.expectedQueryCBId = this._generateQueryCBId(); + return this.model.query(query.text, $.proxy(_callback, this, this.expectedQueryCBId)); + }; + + return Controller; + +})(); + +var TextareaController, + 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; + +TextareaController = (function(superClass) { + extend(TextareaController, superClass); + + function TextareaController() { + return TextareaController.__super__.constructor.apply(this, arguments); + } + + TextareaController.prototype.catchQuery = function() { + var caretPos, content, end, isString, query, start, subtext; + content = this.$inputor.val(); + caretPos = this.$inputor.caret('pos', { + iframe: this.app.iframe + }); + subtext = content.slice(0, caretPos); + query = this.callbacks("matcher").call(this, this.at, subtext, this.getOpt('startWithSpace'), this.getOpt("acceptSpaceBar")); + isString = typeof query === 'string'; + if (isString && query.length < this.getOpt('minLen', 0)) { + return; + } + if (isString && query.length <= this.getOpt('maxLen', 20)) { + start = caretPos - query.length; + end = start + query.length; + this.pos = start; + query = { + 'text': query, + 'headPos': start, + 'endPos': end + }; + this.trigger("matched", [this.at, query.text]); + } else { + query = null; + this.view.hide(); + } + return this.query = query; + }; + + TextareaController.prototype.rect = function() { + var c, iframeOffset, scaleBottom; + if (!(c = this.$inputor.caret('offset', this.pos - 1, { + iframe: this.app.iframe + }))) { + return; + } + if (this.app.iframe && !this.app.iframeAsRoot) { + iframeOffset = $(this.app.iframe).offset(); + c.left += iframeOffset.left; + c.top += iframeOffset.top; + } + scaleBottom = this.app.document.selection ? 0 : 2; + return { + left: c.left, + top: c.top, + bottom: c.top + c.height + scaleBottom + }; + }; + + TextareaController.prototype.insert = function(content, $li) { + var $inputor, source, startStr, suffix, text; + $inputor = this.$inputor; + source = $inputor.val(); + startStr = source.slice(0, Math.max(this.query.headPos - this.at.length, 0)); + suffix = (suffix = this.getOpt('suffix')) === "" ? suffix : suffix || " "; + content += suffix; + text = "" + startStr + content + (source.slice(this.query['endPos'] || 0)); + $inputor.val(text); + $inputor.caret('pos', startStr.length + content.length, { + iframe: this.app.iframe + }); + if (!$inputor.is(':focus')) { + $inputor.focus(); + } + return $inputor.change(); + }; + + return TextareaController; + +})(Controller); + +var EditableController, + 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; + +EditableController = (function(superClass) { + extend(EditableController, superClass); + + function EditableController() { + return EditableController.__super__.constructor.apply(this, arguments); + } + + EditableController.prototype._getRange = function() { + var sel; + sel = this.app.window.getSelection(); + if (sel.rangeCount > 0) { + return sel.getRangeAt(0); + } + }; + + EditableController.prototype._setRange = function(position, node, range) { + if (range == null) { + range = this._getRange(); + } + if (!range) { + return; + } + node = $(node)[0]; + if (position === 'after') { + range.setEndAfter(node); + range.setStartAfter(node); + } else { + range.setEndBefore(node); + range.setStartBefore(node); + } + range.collapse(false); + return this._clearRange(range); + }; + + EditableController.prototype._clearRange = function(range) { + var sel; + if (range == null) { + range = this._getRange(); + } + sel = this.app.window.getSelection(); + if (this.ctrl_a_pressed == null) { + sel.removeAllRanges(); + return sel.addRange(range); + } + }; + + EditableController.prototype._movingEvent = function(e) { + var ref; + return e.type === 'click' || ((ref = e.which) === KEY_CODE.RIGHT || ref === KEY_CODE.LEFT || ref === KEY_CODE.UP || ref === KEY_CODE.DOWN); + }; + + EditableController.prototype._unwrap = function(node) { + var next; + node = $(node).unwrap().get(0); + if ((next = node.nextSibling) && next.nodeValue) { + node.nodeValue += next.nodeValue; + $(next).remove(); + } + return node; + }; + + EditableController.prototype.catchQuery = function(e) { + var $inserted, $query, _range, index, inserted, isString, lastNode, matched, offset, query, query_content, range; + if (!(range = this._getRange())) { + return; + } + if (!range.collapsed) { + return; + } + if (e.which === KEY_CODE.ENTER) { + ($query = $(range.startContainer).closest('.atwho-query')).contents().unwrap(); + if ($query.is(':empty')) { + $query.remove(); + } + ($query = $(".atwho-query", this.app.document)).text($query.text()).contents().last().unwrap(); + this._clearRange(); + return; + } + if (/firefox/i.test(navigator.userAgent)) { + if ($(range.startContainer).is(this.$inputor)) { + this._clearRange(); + return; + } + if (e.which === KEY_CODE.BACKSPACE && range.startContainer.nodeType === document.ELEMENT_NODE && (offset = range.startOffset - 1) >= 0) { + _range = range.cloneRange(); + _range.setStart(range.startContainer, offset); + if ($(_range.cloneContents()).contents().last().is('.atwho-inserted')) { + inserted = $(range.startContainer).contents().get(offset); + this._setRange('after', $(inserted).contents().last()); + } + } else if (e.which === KEY_CODE.LEFT && range.startContainer.nodeType === document.TEXT_NODE) { + $inserted = $(range.startContainer.previousSibling); + if ($inserted.is('.atwho-inserted') && range.startOffset === 0) { + this._setRange('after', $inserted.contents().last()); + } + } + } + $(range.startContainer).closest('.atwho-inserted').addClass('atwho-query').siblings().removeClass('atwho-query'); + if (($query = $(".atwho-query", this.app.document)).length > 0 && $query.is(':empty') && $query.text().length === 0) { + $query.remove(); + } + if (!this._movingEvent(e)) { + $query.removeClass('atwho-inserted'); + } + if ($query.length > 0) { + switch (e.which) { + case KEY_CODE.LEFT: + this._setRange('before', $query.get(0), range); + $query.removeClass('atwho-query'); + return; + case KEY_CODE.RIGHT: + this._setRange('after', $query.get(0).nextSibling, range); + $query.removeClass('atwho-query'); + return; + } + } + if ($query.length > 0 && (query_content = $query.attr('data-atwho-at-query'))) { + $query.empty().html(query_content).attr('data-atwho-at-query', null); + this._setRange('after', $query.get(0), range); + } + _range = range.cloneRange(); + _range.setStart(range.startContainer, 0); + matched = this.callbacks("matcher").call(this, this.at, _range.toString(), this.getOpt('startWithSpace'), this.getOpt("acceptSpaceBar")); + isString = typeof matched === 'string'; + if ($query.length === 0 && isString && (index = range.startOffset - this.at.length - matched.length) >= 0) { + range.setStart(range.startContainer, index); + $query = $('', this.app.document).attr(this.getOpt("editableAtwhoQueryAttrs")).addClass('atwho-query'); + range.surroundContents($query.get(0)); + lastNode = $query.contents().last().get(0); + if (/firefox/i.test(navigator.userAgent)) { + range.setStart(lastNode, lastNode.length); + range.setEnd(lastNode, lastNode.length); + this._clearRange(range); + } else { + this._setRange('after', lastNode, range); + } + } + if (isString && matched.length < this.getOpt('minLen', 0)) { + return; + } + if (isString && matched.length <= this.getOpt('maxLen', 20)) { + query = { + text: matched, + el: $query + }; + this.trigger("matched", [this.at, query.text]); + return this.query = query; + } else { + this.view.hide(); + this.query = { + el: $query + }; + if ($query.text().indexOf(this.at) >= 0) { + if (this._movingEvent(e) && $query.hasClass('atwho-inserted')) { + $query.removeClass('atwho-query'); + } else if (false !== this.callbacks('afterMatchFailed').call(this, this.at, $query)) { + this._setRange("after", this._unwrap($query.text($query.text()).contents().first())); + } + } + return null; + } + }; + + EditableController.prototype.rect = function() { + var $iframe, iframeOffset, rect; + rect = this.query.el.offset(); + if (this.app.iframe && !this.app.iframeAsRoot) { + iframeOffset = ($iframe = $(this.app.iframe)).offset(); + rect.left += iframeOffset.left - this.$inputor.scrollLeft(); + rect.top += iframeOffset.top - this.$inputor.scrollTop(); + } + rect.bottom = rect.top + this.query.el.height(); + return rect; + }; + + EditableController.prototype.insert = function(content, $li) { + var data, range, suffix, suffixNode; + if (!this.$inputor.is(':focus')) { + this.$inputor.focus(); + } + suffix = (suffix = this.getOpt('suffix')) === "" ? suffix : suffix || "\u00A0"; + data = $li.data('item-data'); + this.query.el.removeClass('atwho-query').addClass('atwho-inserted').html(content).attr('data-atwho-at-query', "" + data['atwho-at'] + this.query.text); + if (range = this._getRange()) { + range.setEndAfter(this.query.el[0]); + range.collapse(false); + range.insertNode(suffixNode = this.app.document.createTextNode("\u200D" + suffix)); + this._setRange('after', suffixNode, range); + } + if (!this.$inputor.is(':focus')) { + this.$inputor.focus(); + } + return this.$inputor.change(); + }; + + return EditableController; + +})(Controller); + +var Model; + +Model = (function() { + function Model(context) { + this.context = context; + this.at = this.context.at; + this.storage = this.context.$inputor; + } + + Model.prototype.destroy = function() { + return this.storage.data(this.at, null); + }; + + Model.prototype.saved = function() { + return this.fetch() > 0; + }; + + Model.prototype.query = function(query, callback) { + var _remoteFilter, data, searchKey; + data = this.fetch(); + searchKey = this.context.getOpt("searchKey"); + data = this.context.callbacks('filter').call(this.context, query, data, searchKey) || []; + _remoteFilter = this.context.callbacks('remoteFilter'); + if (data.length > 0 || (!_remoteFilter && data.length === 0)) { + return callback(data); + } else { + return _remoteFilter.call(this.context, query, callback); + } + }; + + Model.prototype.fetch = function() { + return this.storage.data(this.at) || []; + }; + + Model.prototype.save = function(data) { + return this.storage.data(this.at, this.context.callbacks("beforeSave").call(this.context, data || [])); + }; + + Model.prototype.load = function(data) { + if (!(this.saved() || !data)) { + return this._load(data); + } + }; + + Model.prototype.reload = function(data) { + return this._load(data); + }; + + Model.prototype._load = function(data) { + if (typeof data === "string") { + return $.ajax(data, { + dataType: "json" + }).done((function(_this) { + return function(data) { + return _this.save(data); + }; + })(this)); + } else { + return this.save(data); + } + }; + + return Model; + +})(); + +var View; + +View = (function() { + function View(context) { + this.context = context; + this.$el = $("
    "); + this.$elUl = this.$el.children(); + this.timeoutID = null; + this.context.$el.append(this.$el); + this.bindEvent(); + } + + View.prototype.init = function() { + var header_tpl, id; + id = this.context.getOpt("alias") || this.context.at.charCodeAt(0); + header_tpl = this.context.getOpt("headerTpl"); + if (header_tpl && this.$el.children().length === 1) { + this.$el.prepend(header_tpl); + } + return this.$el.attr({ + 'id': "at-view-" + id + }); + }; + + View.prototype.destroy = function() { + return this.$el.remove(); + }; + + View.prototype.bindEvent = function() { + var $menu, lastCoordX, lastCoordY; + $menu = this.$el.find('ul'); + lastCoordX = 0; + lastCoordY = 0; + return $menu.on('mousemove.atwho-view', 'li', (function(_this) { + return function(e) { + var $cur; + if (lastCoordX === e.clientX && lastCoordY === e.clientY) { + return; + } + lastCoordX = e.clientX; + lastCoordY = e.clientY; + $cur = $(e.currentTarget); + if ($cur.hasClass('cur')) { + return; + } + $menu.find('.cur').removeClass('cur'); + return $cur.addClass('cur'); + }; + })(this)).on('click.atwho-view', 'li', (function(_this) { + return function(e) { + $menu.find('.cur').removeClass('cur'); + $(e.currentTarget).addClass('cur'); + _this.choose(e); + return e.preventDefault(); + }; + })(this)); + }; + + View.prototype.visible = function() { + return this.$el.is(":visible"); + }; + + View.prototype.highlighted = function() { + return this.$el.find(".cur").length > 0; + }; + + View.prototype.choose = function(e) { + var $li, content; + if (($li = this.$el.find(".cur")).length) { + content = this.context.insertContentFor($li); + this.context._stopDelayedCall(); + this.context.insert(this.context.callbacks("beforeInsert").call(this.context, content, $li, e), $li); + this.context.trigger("inserted", [$li, e]); + this.hide(e); + } + if (this.context.getOpt("hideWithoutSuffix")) { + return this.stopShowing = true; + } + }; + + View.prototype.reposition = function(rect) { + var _window, offset, overflowOffset, ref; + _window = this.context.app.iframeAsRoot ? this.context.app.window : window; + if (rect.bottom + this.$el.height() - $(_window).scrollTop() > $(_window).height()) { + rect.bottom = rect.top - this.$el.height(); + } + if (rect.left > (overflowOffset = $(_window).width() - this.$el.width() - 5)) { + rect.left = overflowOffset; + } + offset = { + left: rect.left, + top: rect.bottom + }; + if ((ref = this.context.callbacks("beforeReposition")) != null) { + ref.call(this.context, offset); + } + this.$el.offset(offset); + return this.context.trigger("reposition", [offset]); + }; + + View.prototype.next = function() { + var cur, next, nextEl, offset; + cur = this.$el.find('.cur').removeClass('cur'); + next = cur.next(); + if (!next.length) { + next = this.$el.find('li:first'); + } + next.addClass('cur'); + nextEl = next[0]; + offset = nextEl.offsetTop + nextEl.offsetHeight + (nextEl.nextSibling ? nextEl.nextSibling.offsetHeight : 0); + return this.scrollTop(Math.max(0, offset - this.$el.height())); + }; + + View.prototype.prev = function() { + var cur, offset, prev, prevEl; + cur = this.$el.find('.cur').removeClass('cur'); + prev = cur.prev(); + if (!prev.length) { + prev = this.$el.find('li:last'); + } + prev.addClass('cur'); + prevEl = prev[0]; + offset = prevEl.offsetTop + prevEl.offsetHeight + (prevEl.nextSibling ? prevEl.nextSibling.offsetHeight : 0); + return this.scrollTop(Math.max(0, offset - this.$el.height())); + }; + + View.prototype.scrollTop = function(scrollTop) { + var scrollDuration; + scrollDuration = this.context.getOpt('scrollDuration'); + if (scrollDuration) { + return this.$elUl.animate({ + scrollTop: scrollTop + }, scrollDuration); + } else { + return this.$elUl.scrollTop(scrollTop); + } + }; + + View.prototype.show = function() { + var rect; + if (this.stopShowing) { + this.stopShowing = false; + return; + } + if (!this.visible()) { + this.$el.show(); + this.$el.scrollTop(0); + this.context.trigger('shown'); + } + if (rect = this.context.rect()) { + return this.reposition(rect); + } + }; + + View.prototype.hide = function(e, time) { + var callback; + if (!this.visible()) { + return; + } + if (isNaN(time)) { + this.$el.hide(); + return this.context.trigger('hidden', [e]); + } else { + callback = (function(_this) { + return function() { + return _this.hide(); + }; + })(this); + clearTimeout(this.timeoutID); + return this.timeoutID = setTimeout(callback, time); + } + }; + + View.prototype.render = function(list) { + var $li, $ul, i, item, len, li, tpl; + if (!($.isArray(list) && list.length > 0)) { + this.hide(); + return; + } + this.$el.find('ul').empty(); + $ul = this.$el.find('ul'); + tpl = this.context.getOpt('displayTpl'); + for (i = 0, len = list.length; i < len; i++) { + item = list[i]; + item = $.extend({}, item, { + 'atwho-at': this.context.at + }); + li = this.context.callbacks("tplEval").call(this.context, tpl, item, "onDisplay"); + $li = $(this.context.callbacks("highlighter").call(this.context, li, this.context.query.text)); + $li.data("item-data", item); + $ul.append($li); + } + this.show(); + if (this.context.getOpt('highlightFirst')) { + return $ul.find("li:first").addClass("cur"); + } + }; + + return View; + +})(); + +var Api; + +Api = { + load: function(at, data) { + var c; + if (c = this.controller(at)) { + return c.model.load(data); + } + }, + isSelecting: function() { + var ref; + return !!((ref = this.controller()) != null ? ref.view.visible() : void 0); + }, + hide: function() { + var ref; + return (ref = this.controller()) != null ? ref.view.hide() : void 0; + }, + reposition: function() { + var c; + if (c = this.controller()) { + return c.view.reposition(c.rect()); + } + }, + setIframe: function(iframe, asRoot) { + this.setupRootElement(iframe, asRoot); + return null; + }, + run: function() { + return this.dispatch(); + }, + destroy: function() { + this.shutdown(); + return this.$inputor.data('atwho', null); + } +}; + +$.fn.atwho = function(method) { + var _args, result; + _args = arguments; + result = null; + this.filter('textarea, input, [contenteditable=""], [contenteditable=true]').each(function() { + var $this, app; + if (!(app = ($this = $(this)).data("atwho"))) { + $this.data('atwho', (app = new App(this))); + } + if (typeof method === 'object' || !method) { + return app.reg(method.at, method); + } else if (Api[method] && app) { + return result = Api[method].apply(app, Array.prototype.slice.call(_args, 1)); + } else { + return $.error("Method " + method + " does not exist on jQuery.atwho"); + } + }); + if (result != null) { + return result; + } else { + return this; + } +}; + +$.fn.atwho["default"] = { + at: void 0, + alias: void 0, + data: null, + displayTpl: "
  • ${name}
  • ", + insertTpl: "${atwho-at}${name}", + headerTpl: null, + callbacks: DEFAULT_CALLBACKS, + searchKey: "name", + suffix: void 0, + hideWithoutSuffix: false, + startWithSpace: true, + acceptSpaceBar: false, + highlightFirst: true, + limit: 5, + maxLen: 20, + minLen: 0, + displayTimeout: 300, + delay: null, + spaceSelectsMatch: false, + tabSelectsMatch: true, + editableAtwhoQueryAttrs: {}, + scrollDuration: 150, + suspendOnComposing: true, + lookUpOnClick: true +}; + +$.fn.atwho.debug = false; + +})); diff --git a/vendor/assets/javascripts/jquery.caret.js b/vendor/assets/javascripts/jquery.caret.js new file mode 100644 index 00000000000..811ec63ee47 --- /dev/null +++ b/vendor/assets/javascripts/jquery.caret.js @@ -0,0 +1,436 @@ +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module. + define(["jquery"], function ($) { + return (root.returnExportsGlobal = factory($)); + }); + } else if (typeof exports === 'object') { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like enviroments that support module.exports, + // like Node. + module.exports = factory(require("jquery")); + } else { + factory(jQuery); + } +}(this, function ($) { + +/* + Implement Github like autocomplete mentions + http://ichord.github.com/At.js + + Copyright (c) 2013 chord.luo@gmail.com + Licensed under the MIT license. +*/ + +/* +本插件操作 textarea 或者 input 内的插入符 +只实现了获得插入符在文本框中的位置,我设置 +插入符的位置. +*/ + +"use strict"; +var EditableCaret, InputCaret, Mirror, Utils, discoveryIframeOf, methods, oDocument, oFrame, oWindow, pluginName, setContextBy; + +pluginName = 'caret'; + +EditableCaret = (function() { + function EditableCaret($inputor) { + this.$inputor = $inputor; + this.domInputor = this.$inputor[0]; + } + + EditableCaret.prototype.setPos = function(pos) { + var fn, found, offset, sel; + if (sel = oWindow.getSelection()) { + offset = 0; + found = false; + (fn = function(pos, parent) { + var node, range, _i, _len, _ref, _results; + _ref = parent.childNodes; + _results = []; + for (_i = 0, _len = _ref.length; _i < _len; _i++) { + node = _ref[_i]; + if (found) { + break; + } + if (node.nodeType === 3) { + if (offset + node.length >= pos) { + found = true; + range = oDocument.createRange(); + range.setStart(node, pos - offset); + sel.removeAllRanges(); + sel.addRange(range); + break; + } else { + _results.push(offset += node.length); + } + } else { + _results.push(fn(pos, node)); + } + } + return _results; + })(pos, this.domInputor); + } + return this.domInputor; + }; + + EditableCaret.prototype.getIEPosition = function() { + return this.getPosition(); + }; + + EditableCaret.prototype.getPosition = function() { + var inputor_offset, offset; + offset = this.getOffset(); + inputor_offset = this.$inputor.offset(); + offset.left -= inputor_offset.left; + offset.top -= inputor_offset.top; + return offset; + }; + + EditableCaret.prototype.getOldIEPos = function() { + var preCaretTextRange, textRange; + textRange = oDocument.selection.createRange(); + preCaretTextRange = oDocument.body.createTextRange(); + preCaretTextRange.moveToElementText(this.domInputor); + preCaretTextRange.setEndPoint("EndToEnd", textRange); + return preCaretTextRange.text.length; + }; + + EditableCaret.prototype.getPos = function() { + var clonedRange, pos, range; + if (range = this.range()) { + clonedRange = range.cloneRange(); + clonedRange.selectNodeContents(this.domInputor); + clonedRange.setEnd(range.endContainer, range.endOffset); + pos = clonedRange.toString().length; + clonedRange.detach(); + return pos; + } else if (oDocument.selection) { + return this.getOldIEPos(); + } + }; + + EditableCaret.prototype.getOldIEOffset = function() { + var range, rect; + range = oDocument.selection.createRange().duplicate(); + range.moveStart("character", -1); + rect = range.getBoundingClientRect(); + return { + height: rect.bottom - rect.top, + left: rect.left, + top: rect.top + }; + }; + + EditableCaret.prototype.getOffset = function(pos) { + var clonedRange, offset, range, rect, shadowCaret; + if (oWindow.getSelection && (range = this.range())) { + if (range.endOffset - 1 > 0 && range.endContainer !== this.domInputor) { + clonedRange = range.cloneRange(); + clonedRange.setStart(range.endContainer, range.endOffset - 1); + clonedRange.setEnd(range.endContainer, range.endOffset); + rect = clonedRange.getBoundingClientRect(); + offset = { + height: rect.height, + left: rect.left + rect.width, + top: rect.top + }; + clonedRange.detach(); + } + if (!offset || (offset != null ? offset.height : void 0) === 0) { + clonedRange = range.cloneRange(); + shadowCaret = $(oDocument.createTextNode("|")); + clonedRange.insertNode(shadowCaret[0]); + clonedRange.selectNode(shadowCaret[0]); + rect = clonedRange.getBoundingClientRect(); + offset = { + height: rect.height, + left: rect.left, + top: rect.top + }; + shadowCaret.remove(); + clonedRange.detach(); + } + } else if (oDocument.selection) { + offset = this.getOldIEOffset(); + } + if (offset) { + offset.top += $(oWindow).scrollTop(); + offset.left += $(oWindow).scrollLeft(); + } + return offset; + }; + + EditableCaret.prototype.range = function() { + var sel; + if (!oWindow.getSelection) { + return; + } + sel = oWindow.getSelection(); + if (sel.rangeCount > 0) { + return sel.getRangeAt(0); + } else { + return null; + } + }; + + return EditableCaret; + +})(); + +InputCaret = (function() { + function InputCaret($inputor) { + this.$inputor = $inputor; + this.domInputor = this.$inputor[0]; + } + + InputCaret.prototype.getIEPos = function() { + var endRange, inputor, len, normalizedValue, pos, range, textInputRange; + inputor = this.domInputor; + range = oDocument.selection.createRange(); + pos = 0; + if (range && range.parentElement() === inputor) { + normalizedValue = inputor.value.replace(/\r\n/g, "\n"); + len = normalizedValue.length; + textInputRange = inputor.createTextRange(); + textInputRange.moveToBookmark(range.getBookmark()); + endRange = inputor.createTextRange(); + endRange.collapse(false); + if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) { + pos = len; + } else { + pos = -textInputRange.moveStart("character", -len); + } + } + return pos; + }; + + InputCaret.prototype.getPos = function() { + if (oDocument.selection) { + return this.getIEPos(); + } else { + return this.domInputor.selectionStart; + } + }; + + InputCaret.prototype.setPos = function(pos) { + var inputor, range; + inputor = this.domInputor; + if (oDocument.selection) { + range = inputor.createTextRange(); + range.move("character", pos); + range.select(); + } else if (inputor.setSelectionRange) { + inputor.setSelectionRange(pos, pos); + } + return inputor; + }; + + InputCaret.prototype.getIEOffset = function(pos) { + var h, textRange, x, y; + textRange = this.domInputor.createTextRange(); + pos || (pos = this.getPos()); + textRange.move('character', pos); + x = textRange.boundingLeft; + y = textRange.boundingTop; + h = textRange.boundingHeight; + return { + left: x, + top: y, + height: h + }; + }; + + InputCaret.prototype.getOffset = function(pos) { + var $inputor, offset, position; + $inputor = this.$inputor; + if (oDocument.selection) { + offset = this.getIEOffset(pos); + offset.top += $(oWindow).scrollTop() + $inputor.scrollTop(); + offset.left += $(oWindow).scrollLeft() + $inputor.scrollLeft(); + return offset; + } else { + offset = $inputor.offset(); + position = this.getPosition(pos); + return offset = { + left: offset.left + position.left - $inputor.scrollLeft(), + top: offset.top + position.top - $inputor.scrollTop(), + height: position.height + }; + } + }; + + InputCaret.prototype.getPosition = function(pos) { + var $inputor, at_rect, end_range, format, html, mirror, start_range; + $inputor = this.$inputor; + format = function(value) { + value = value.replace(/<|>|`|"|&/g, '?').replace(/\r\n|\r|\n/g, "
    "); + if (/firefox/i.test(navigator.userAgent)) { + value = value.replace(/\s/g, ' '); + } + return value; + }; + if (pos === void 0) { + pos = this.getPos(); + } + start_range = $inputor.val().slice(0, pos); + end_range = $inputor.val().slice(pos); + html = "" + format(start_range) + ""; + html += "|"; + html += "" + format(end_range) + ""; + mirror = new Mirror($inputor); + return at_rect = mirror.create(html).rect(); + }; + + InputCaret.prototype.getIEPosition = function(pos) { + var h, inputorOffset, offset, x, y; + offset = this.getIEOffset(pos); + inputorOffset = this.$inputor.offset(); + x = offset.left - inputorOffset.left; + y = offset.top - inputorOffset.top; + h = offset.height; + return { + left: x, + top: y, + height: h + }; + }; + + return InputCaret; + +})(); + +Mirror = (function() { + Mirror.prototype.css_attr = ["borderBottomWidth", "borderLeftWidth", "borderRightWidth", "borderTopStyle", "borderRightStyle", "borderBottomStyle", "borderLeftStyle", "borderTopWidth", "boxSizing", "fontFamily", "fontSize", "fontWeight", "height", "letterSpacing", "lineHeight", "marginBottom", "marginLeft", "marginRight", "marginTop", "outlineWidth", "overflow", "overflowX", "overflowY", "paddingBottom", "paddingLeft", "paddingRight", "paddingTop", "textAlign", "textOverflow", "textTransform", "whiteSpace", "wordBreak", "wordWrap"]; + + function Mirror($inputor) { + this.$inputor = $inputor; + } + + Mirror.prototype.mirrorCss = function() { + var css, + _this = this; + css = { + position: 'absolute', + left: -9999, + top: 0, + zIndex: -20000 + }; + if (this.$inputor.prop('tagName') === 'TEXTAREA') { + this.css_attr.push('width'); + } + $.each(this.css_attr, function(i, p) { + return css[p] = _this.$inputor.css(p); + }); + return css; + }; + + Mirror.prototype.create = function(html) { + this.$mirror = $('
    '); + this.$mirror.css(this.mirrorCss()); + this.$mirror.html(html); + this.$inputor.after(this.$mirror); + return this; + }; + + Mirror.prototype.rect = function() { + var $flag, pos, rect; + $flag = this.$mirror.find("#caret"); + pos = $flag.position(); + rect = { + left: pos.left, + top: pos.top, + height: $flag.height() + }; + this.$mirror.remove(); + return rect; + }; + + return Mirror; + +})(); + +Utils = { + contentEditable: function($inputor) { + return !!($inputor[0].contentEditable && $inputor[0].contentEditable === 'true'); + } +}; + +methods = { + pos: function(pos) { + if (pos || pos === 0) { + return this.setPos(pos); + } else { + return this.getPos(); + } + }, + position: function(pos) { + if (oDocument.selection) { + return this.getIEPosition(pos); + } else { + return this.getPosition(pos); + } + }, + offset: function(pos) { + var offset; + offset = this.getOffset(pos); + return offset; + } +}; + +oDocument = null; + +oWindow = null; + +oFrame = null; + +setContextBy = function(settings) { + var iframe; + if (iframe = settings != null ? settings.iframe : void 0) { + oFrame = iframe; + oWindow = iframe.contentWindow; + return oDocument = iframe.contentDocument || oWindow.document; + } else { + oFrame = void 0; + oWindow = window; + return oDocument = document; + } +}; + +discoveryIframeOf = function($dom) { + var error; + oDocument = $dom[0].ownerDocument; + oWindow = oDocument.defaultView || oDocument.parentWindow; + try { + return oFrame = oWindow.frameElement; + } catch (_error) { + error = _error; + } +}; + +$.fn.caret = function(method, value, settings) { + var caret; + if (methods[method]) { + if ($.isPlainObject(value)) { + setContextBy(value); + value = void 0; + } else { + setContextBy(settings); + } + caret = Utils.contentEditable(this) ? new EditableCaret(this) : new InputCaret(this); + return methods[method].apply(caret, [value]); + } else { + return $.error("Method " + method + " does not exist on jQuery.caret"); + } +}; + +$.fn.caret.EditableCaret = EditableCaret; + +$.fn.caret.InputCaret = InputCaret; + +$.fn.caret.Utils = Utils; + +$.fn.caret.apis = methods; + + +})); diff --git a/vendor/assets/javascripts/jquery.turbolinks.js b/vendor/assets/javascripts/jquery.turbolinks.js new file mode 100644 index 00000000000..fd6e95e75d5 --- /dev/null +++ b/vendor/assets/javascripts/jquery.turbolinks.js @@ -0,0 +1,49 @@ +// Generated by CoffeeScript 1.7.1 + +/* +jQuery.Turbolinks ~ https://github.com/kossnocorp/jquery.turbolinks +jQuery plugin for drop-in fix binded events problem caused by Turbolinks + +The MIT License +Copyright (c) 2012-2013 Sasha Koss & Rico Sta. Cruz + */ + +(function() { + var $, $document; + + $ = window.jQuery || (typeof require === "function" ? require('jquery') : void 0); + + $document = $(document); + + $.turbo = { + version: '2.1.0', + isReady: false, + use: function(load, fetch) { + return $document.off('.turbo').on("" + load + ".turbo", this.onLoad).on("" + fetch + ".turbo", this.onFetch); + }, + addCallback: function(callback) { + if ($.turbo.isReady) { + callback($); + } + return $document.on('turbo:ready', function() { + return callback($); + }); + }, + onLoad: function() { + $.turbo.isReady = true; + return $document.trigger('turbo:ready'); + }, + onFetch: function() { + return $.turbo.isReady = false; + }, + register: function() { + $(this.onLoad); + return $.fn.ready = this.addCallback; + } + }; + + $.turbo.register(); + + $.turbo.use('page:load', 'page:fetch'); + +}).call(this); diff --git a/vendor/assets/javascripts/turbolinks.js b/vendor/assets/javascripts/turbolinks.js new file mode 100644 index 00000000000..17a2635bf2a --- /dev/null +++ b/vendor/assets/javascripts/turbolinks.js @@ -0,0 +1,781 @@ +// Turbolinks Classic v2.5.3 compiled from CoffeeScript +(function() { + var CSRFToken, Click, ComponentUrl, EVENTS, Link, ProgressBar, browserIsntBuggy, browserSupportsCustomEvents, browserSupportsPushState, browserSupportsTurbolinks, bypassOnLoadPopstate, cacheCurrentPage, cacheSize, changePage, clone, constrainPageCacheTo, createDocument, crossOriginRedirect, currentState, enableProgressBar, enableTransitionCache, executeScriptTags, extractTitleAndBody, fetch, fetchHistory, fetchReplacement, historyStateIsDefined, initializeTurbolinks, installDocumentReadyPageEventTriggers, installHistoryChangeHandler, installJqueryAjaxSuccessPageUpdateTrigger, loadedAssets, manuallyTriggerHashChangeForFirefox, pageCache, pageChangePrevented, pagesCached, popCookie, processResponse, progressBar, recallScrollPosition, ref, referer, reflectNewUrl, reflectRedirectedUrl, rememberCurrentState, rememberCurrentUrl, rememberReferer, removeNoscriptTags, requestMethodIsSafe, resetScrollPosition, setAutofocusElement, transitionCacheEnabled, transitionCacheFor, triggerEvent, visit, xhr, + indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }, + 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, + slice = [].slice, + bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }; + + pageCache = {}; + + cacheSize = 10; + + transitionCacheEnabled = false; + + progressBar = null; + + currentState = null; + + loadedAssets = null; + + referer = null; + + xhr = null; + + EVENTS = { + BEFORE_CHANGE: 'page:before-change', + FETCH: 'page:fetch', + RECEIVE: 'page:receive', + CHANGE: 'page:change', + UPDATE: 'page:update', + LOAD: 'page:load', + RESTORE: 'page:restore', + BEFORE_UNLOAD: 'page:before-unload', + EXPIRE: 'page:expire' + }; + + fetch = function(url) { + var cachedPage; + url = new ComponentUrl(url); + rememberReferer(); + cacheCurrentPage(); + if (progressBar != null) { + progressBar.start(); + } + if (transitionCacheEnabled && (cachedPage = transitionCacheFor(url.absolute))) { + fetchHistory(cachedPage); + return fetchReplacement(url, null, false); + } else { + return fetchReplacement(url, resetScrollPosition); + } + }; + + transitionCacheFor = function(url) { + var cachedPage; + cachedPage = pageCache[url]; + if (cachedPage && !cachedPage.transitionCacheDisabled) { + return cachedPage; + } + }; + + enableTransitionCache = function(enable) { + if (enable == null) { + enable = true; + } + return transitionCacheEnabled = enable; + }; + + enableProgressBar = function(enable) { + if (enable == null) { + enable = true; + } + if (!browserSupportsTurbolinks) { + return; + } + if (enable) { + return progressBar != null ? progressBar : progressBar = new ProgressBar('html'); + } else { + if (progressBar != null) { + progressBar.uninstall(); + } + return progressBar = null; + } + }; + + fetchReplacement = function(url, onLoadFunction, showProgressBar) { + if (showProgressBar == null) { + showProgressBar = true; + } + triggerEvent(EVENTS.FETCH, { + url: url.absolute + }); + if (xhr != null) { + xhr.abort(); + } + xhr = new XMLHttpRequest; + xhr.open('GET', url.withoutHashForIE10compatibility(), true); + xhr.setRequestHeader('Accept', 'text/html, application/xhtml+xml, application/xml'); + xhr.setRequestHeader('X-XHR-Referer', referer); + xhr.onload = function() { + var doc; + triggerEvent(EVENTS.RECEIVE, { + url: url.absolute + }); + if (doc = processResponse()) { + reflectNewUrl(url); + reflectRedirectedUrl(); + changePage.apply(null, extractTitleAndBody(doc)); + manuallyTriggerHashChangeForFirefox(); + if (typeof onLoadFunction === "function") { + onLoadFunction(); + } + return triggerEvent(EVENTS.LOAD); + } else { + return document.location.href = crossOriginRedirect() || url.absolute; + } + }; + if (progressBar && showProgressBar) { + xhr.onprogress = (function(_this) { + return function(event) { + var percent; + percent = event.lengthComputable ? event.loaded / event.total * 100 : progressBar.value + (100 - progressBar.value) / 10; + return progressBar.advanceTo(percent); + }; + })(this); + } + xhr.onloadend = function() { + return xhr = null; + }; + xhr.onerror = function() { + return document.location.href = url.absolute; + }; + return xhr.send(); + }; + + fetchHistory = function(cachedPage) { + if (xhr != null) { + xhr.abort(); + } + changePage(cachedPage.title, cachedPage.body); + recallScrollPosition(cachedPage); + return triggerEvent(EVENTS.RESTORE); + }; + + cacheCurrentPage = function() { + var currentStateUrl; + currentStateUrl = new ComponentUrl(currentState.url); + pageCache[currentStateUrl.absolute] = { + url: currentStateUrl.relative, + body: document.body, + title: document.title, + positionY: window.pageYOffset, + positionX: window.pageXOffset, + cachedAt: new Date().getTime(), + transitionCacheDisabled: document.querySelector('[data-no-transition-cache]') != null + }; + return constrainPageCacheTo(cacheSize); + }; + + pagesCached = function(size) { + if (size == null) { + size = cacheSize; + } + if (/^[\d]+$/.test(size)) { + return cacheSize = parseInt(size); + } + }; + + constrainPageCacheTo = function(limit) { + var cacheTimesRecentFirst, i, key, len, pageCacheKeys, results; + pageCacheKeys = Object.keys(pageCache); + cacheTimesRecentFirst = pageCacheKeys.map(function(url) { + return pageCache[url].cachedAt; + }).sort(function(a, b) { + return b - a; + }); + results = []; + for (i = 0, len = pageCacheKeys.length; i < len; i++) { + key = pageCacheKeys[i]; + if (!(pageCache[key].cachedAt <= cacheTimesRecentFirst[limit])) { + continue; + } + triggerEvent(EVENTS.EXPIRE, pageCache[key]); + results.push(delete pageCache[key]); + } + return results; + }; + + changePage = function(title, body, csrfToken, runScripts) { + triggerEvent(EVENTS.BEFORE_UNLOAD); + document.title = title; + document.documentElement.replaceChild(body, document.body); + if (csrfToken != null) { + CSRFToken.update(csrfToken); + } + setAutofocusElement(); + if (runScripts) { + executeScriptTags(); + } + currentState = window.history.state; + if (progressBar != null) { + progressBar.done(); + } + triggerEvent(EVENTS.CHANGE); + return triggerEvent(EVENTS.UPDATE); + }; + + executeScriptTags = function() { + var attr, copy, i, j, len, len1, nextSibling, parentNode, ref, ref1, script, scripts; + scripts = Array.prototype.slice.call(document.body.querySelectorAll('script:not([data-turbolinks-eval="false"])')); + for (i = 0, len = scripts.length; i < len; i++) { + script = scripts[i]; + if (!((ref = script.type) === '' || ref === 'text/javascript')) { + continue; + } + copy = document.createElement('script'); + ref1 = script.attributes; + for (j = 0, len1 = ref1.length; j < len1; j++) { + attr = ref1[j]; + copy.setAttribute(attr.name, attr.value); + } + if (!script.hasAttribute('async')) { + copy.async = false; + } + copy.appendChild(document.createTextNode(script.innerHTML)); + parentNode = script.parentNode, nextSibling = script.nextSibling; + parentNode.removeChild(script); + parentNode.insertBefore(copy, nextSibling); + } + }; + + removeNoscriptTags = function(node) { + node.innerHTML = node.innerHTML.replace(//ig, ''); + return node; + }; + + setAutofocusElement = function() { + var autofocusElement, list; + autofocusElement = (list = document.querySelectorAll('input[autofocus], textarea[autofocus]'))[list.length - 1]; + if (autofocusElement && document.activeElement !== autofocusElement) { + return autofocusElement.focus(); + } + }; + + reflectNewUrl = function(url) { + if ((url = new ComponentUrl(url)).absolute !== referer) { + return window.history.pushState({ + turbolinks: true, + url: url.absolute + }, '', url.absolute); + } + }; + + reflectRedirectedUrl = function() { + var location, preservedHash; + if (location = xhr.getResponseHeader('X-XHR-Redirected-To')) { + location = new ComponentUrl(location); + preservedHash = location.hasNoHash() ? document.location.hash : ''; + return window.history.replaceState(window.history.state, '', location.href + preservedHash); + } + }; + + crossOriginRedirect = function() { + var redirect; + if (((redirect = xhr.getResponseHeader('Location')) != null) && (new ComponentUrl(redirect)).crossOrigin()) { + return redirect; + } + }; + + rememberReferer = function() { + return referer = document.location.href; + }; + + rememberCurrentUrl = function() { + return window.history.replaceState({ + turbolinks: true, + url: document.location.href + }, '', document.location.href); + }; + + rememberCurrentState = function() { + return currentState = window.history.state; + }; + + manuallyTriggerHashChangeForFirefox = function() { + var url; + if (navigator.userAgent.match(/Firefox/) && !(url = new ComponentUrl).hasNoHash()) { + window.history.replaceState(currentState, '', url.withoutHash()); + return document.location.hash = url.hash; + } + }; + + recallScrollPosition = function(page) { + return window.scrollTo(page.positionX, page.positionY); + }; + + resetScrollPosition = function() { + if (document.location.hash) { + return document.location.href = document.location.href; + } else { + return window.scrollTo(0, 0); + } + }; + + clone = function(original) { + var copy, key, value; + if ((original == null) || typeof original !== 'object') { + return original; + } + copy = new original.constructor(); + for (key in original) { + value = original[key]; + copy[key] = clone(value); + } + return copy; + }; + + popCookie = function(name) { + var ref, value; + value = ((ref = document.cookie.match(new RegExp(name + "=(\\w+)"))) != null ? ref[1].toUpperCase() : void 0) || ''; + document.cookie = name + '=; expires=Thu, 01-Jan-70 00:00:01 GMT; path=/'; + return value; + }; + + triggerEvent = function(name, data) { + var event; + if (typeof Prototype !== 'undefined') { + Event.fire(document, name, data, true); + } + event = document.createEvent('Events'); + if (data) { + event.data = data; + } + event.initEvent(name, true, true); + return document.dispatchEvent(event); + }; + + pageChangePrevented = function(url) { + return !triggerEvent(EVENTS.BEFORE_CHANGE, { + url: url + }); + }; + + processResponse = function() { + var assetsChanged, clientOrServerError, doc, extractTrackAssets, intersection, validContent; + clientOrServerError = function() { + var ref; + return (400 <= (ref = xhr.status) && ref < 600); + }; + validContent = function() { + var contentType; + return ((contentType = xhr.getResponseHeader('Content-Type')) != null) && contentType.match(/^(?:text\/html|application\/xhtml\+xml|application\/xml)(?:;|$)/); + }; + extractTrackAssets = function(doc) { + var i, len, node, ref, results; + ref = doc.querySelector('head').childNodes; + results = []; + for (i = 0, len = ref.length; i < len; i++) { + node = ref[i]; + if ((typeof node.getAttribute === "function" ? node.getAttribute('data-turbolinks-track') : void 0) != null) { + results.push(node.getAttribute('src') || node.getAttribute('href')); + } + } + return results; + }; + assetsChanged = function(doc) { + var fetchedAssets; + loadedAssets || (loadedAssets = extractTrackAssets(document)); + fetchedAssets = extractTrackAssets(doc); + return fetchedAssets.length !== loadedAssets.length || intersection(fetchedAssets, loadedAssets).length !== loadedAssets.length; + }; + intersection = function(a, b) { + var i, len, ref, results, value; + if (a.length > b.length) { + ref = [b, a], a = ref[0], b = ref[1]; + } + results = []; + for (i = 0, len = a.length; i < len; i++) { + value = a[i]; + if (indexOf.call(b, value) >= 0) { + results.push(value); + } + } + return results; + }; + if (!clientOrServerError() && validContent()) { + doc = createDocument(xhr.responseText); + if (doc && !assetsChanged(doc)) { + return doc; + } + } + }; + + extractTitleAndBody = function(doc) { + var title; + title = doc.querySelector('title'); + return [title != null ? title.textContent : void 0, removeNoscriptTags(doc.querySelector('body')), CSRFToken.get(doc).token, 'runScripts']; + }; + + CSRFToken = { + get: function(doc) { + var tag; + if (doc == null) { + doc = document; + } + return { + node: tag = doc.querySelector('meta[name="csrf-token"]'), + token: tag != null ? typeof tag.getAttribute === "function" ? tag.getAttribute('content') : void 0 : void 0 + }; + }, + update: function(latest) { + var current; + current = this.get(); + if ((current.token != null) && (latest != null) && current.token !== latest) { + return current.node.setAttribute('content', latest); + } + } + }; + + createDocument = function(html) { + var doc; + doc = document.documentElement.cloneNode(); + doc.innerHTML = html; + doc.head = doc.querySelector('head'); + doc.body = doc.querySelector('body'); + return doc; + }; + + ComponentUrl = (function() { + function ComponentUrl(original1) { + this.original = original1 != null ? original1 : document.location.href; + if (this.original.constructor === ComponentUrl) { + return this.original; + } + this._parse(); + } + + ComponentUrl.prototype.withoutHash = function() { + return this.href.replace(this.hash, '').replace('#', ''); + }; + + ComponentUrl.prototype.withoutHashForIE10compatibility = function() { + return this.withoutHash(); + }; + + ComponentUrl.prototype.hasNoHash = function() { + return this.hash.length === 0; + }; + + ComponentUrl.prototype.crossOrigin = function() { + return this.origin !== (new ComponentUrl).origin; + }; + + ComponentUrl.prototype._parse = function() { + var ref; + (this.link != null ? this.link : this.link = document.createElement('a')).href = this.original; + ref = this.link, this.href = ref.href, this.protocol = ref.protocol, this.host = ref.host, this.hostname = ref.hostname, this.port = ref.port, this.pathname = ref.pathname, this.search = ref.search, this.hash = ref.hash; + this.origin = [this.protocol, '//', this.hostname].join(''); + if (this.port.length !== 0) { + this.origin += ":" + this.port; + } + this.relative = [this.pathname, this.search, this.hash].join(''); + return this.absolute = this.href; + }; + + return ComponentUrl; + + })(); + + Link = (function(superClass) { + extend(Link, superClass); + + Link.HTML_EXTENSIONS = ['html']; + + Link.allowExtensions = function() { + var extension, extensions, i, len; + extensions = 1 <= arguments.length ? slice.call(arguments, 0) : []; + for (i = 0, len = extensions.length; i < len; i++) { + extension = extensions[i]; + Link.HTML_EXTENSIONS.push(extension); + } + return Link.HTML_EXTENSIONS; + }; + + function Link(link1) { + this.link = link1; + if (this.link.constructor === Link) { + return this.link; + } + this.original = this.link.href; + this.originalElement = this.link; + this.link = this.link.cloneNode(false); + Link.__super__.constructor.apply(this, arguments); + } + + Link.prototype.shouldIgnore = function() { + return this.crossOrigin() || this._anchored() || this._nonHtml() || this._optOut() || this._target(); + }; + + Link.prototype._anchored = function() { + return (this.hash.length > 0 || this.href.charAt(this.href.length - 1) === '#') && (this.withoutHash() === (new ComponentUrl).withoutHash()); + }; + + Link.prototype._nonHtml = function() { + return this.pathname.match(/\.[a-z]+$/g) && !this.pathname.match(new RegExp("\\.(?:" + (Link.HTML_EXTENSIONS.join('|')) + ")?$", 'g')); + }; + + Link.prototype._optOut = function() { + var ignore, link; + link = this.originalElement; + while (!(ignore || link === document)) { + ignore = link.getAttribute('data-no-turbolink') != null; + link = link.parentNode; + } + return ignore; + }; + + Link.prototype._target = function() { + return this.link.target.length !== 0; + }; + + return Link; + + })(ComponentUrl); + + Click = (function() { + Click.installHandlerLast = function(event) { + if (!event.defaultPrevented) { + document.removeEventListener('click', Click.handle, false); + return document.addEventListener('click', Click.handle, false); + } + }; + + Click.handle = function(event) { + return new Click(event); + }; + + function Click(event1) { + this.event = event1; + if (this.event.defaultPrevented) { + return; + } + this._extractLink(); + if (this._validForTurbolinks()) { + if (!pageChangePrevented(this.link.absolute)) { + visit(this.link.href); + } + this.event.preventDefault(); + } + } + + Click.prototype._extractLink = function() { + var link; + link = this.event.target; + while (!(!link.parentNode || link.nodeName === 'A')) { + link = link.parentNode; + } + if (link.nodeName === 'A' && link.href.length !== 0) { + return this.link = new Link(link); + } + }; + + Click.prototype._validForTurbolinks = function() { + return (this.link != null) && !(this.link.shouldIgnore() || this._nonStandardClick()); + }; + + Click.prototype._nonStandardClick = function() { + return this.event.which > 1 || this.event.metaKey || this.event.ctrlKey || this.event.shiftKey || this.event.altKey; + }; + + return Click; + + })(); + + ProgressBar = (function() { + var className; + + className = 'turbolinks-progress-bar'; + + function ProgressBar(elementSelector) { + this.elementSelector = elementSelector; + this._trickle = bind(this._trickle, this); + this.value = 0; + this.content = ''; + this.speed = 300; + this.opacity = 0.99; + this.install(); + } + + ProgressBar.prototype.install = function() { + this.element = document.querySelector(this.elementSelector); + this.element.classList.add(className); + this.styleElement = document.createElement('style'); + document.head.appendChild(this.styleElement); + return this._updateStyle(); + }; + + ProgressBar.prototype.uninstall = function() { + this.element.classList.remove(className); + return document.head.removeChild(this.styleElement); + }; + + ProgressBar.prototype.start = function() { + return this.advanceTo(5); + }; + + ProgressBar.prototype.advanceTo = function(value) { + var ref; + if ((value > (ref = this.value) && ref <= 100)) { + this.value = value; + this._updateStyle(); + if (this.value === 100) { + return this._stopTrickle(); + } else if (this.value > 0) { + return this._startTrickle(); + } + } + }; + + ProgressBar.prototype.done = function() { + if (this.value > 0) { + this.advanceTo(100); + return this._reset(); + } + }; + + ProgressBar.prototype._reset = function() { + var originalOpacity; + originalOpacity = this.opacity; + setTimeout((function(_this) { + return function() { + _this.opacity = 0; + return _this._updateStyle(); + }; + })(this), this.speed / 2); + return setTimeout((function(_this) { + return function() { + _this.value = 0; + _this.opacity = originalOpacity; + return _this._withSpeed(0, function() { + return _this._updateStyle(true); + }); + }; + })(this), this.speed); + }; + + ProgressBar.prototype._startTrickle = function() { + if (this.trickling) { + return; + } + this.trickling = true; + return setTimeout(this._trickle, this.speed); + }; + + ProgressBar.prototype._stopTrickle = function() { + return delete this.trickling; + }; + + ProgressBar.prototype._trickle = function() { + if (!this.trickling) { + return; + } + this.advanceTo(this.value + Math.random() / 2); + return setTimeout(this._trickle, this.speed); + }; + + ProgressBar.prototype._withSpeed = function(speed, fn) { + var originalSpeed, result; + originalSpeed = this.speed; + this.speed = speed; + result = fn(); + this.speed = originalSpeed; + return result; + }; + + ProgressBar.prototype._updateStyle = function(forceRepaint) { + if (forceRepaint == null) { + forceRepaint = false; + } + if (forceRepaint) { + this._changeContentToForceRepaint(); + } + return this.styleElement.textContent = this._createCSSRule(); + }; + + ProgressBar.prototype._changeContentToForceRepaint = function() { + return this.content = this.content === '' ? ' ' : ''; + }; + + ProgressBar.prototype._createCSSRule = function() { + return this.elementSelector + "." + className + "::before {\n content: '" + this.content + "';\n position: fixed;\n top: 0;\n left: 0;\n z-index: 2000;\n background-color: #0076ff;\n height: 3px;\n opacity: " + this.opacity + ";\n width: " + this.value + "%;\n transition: width " + this.speed + "ms ease-out, opacity " + (this.speed / 2) + "ms ease-in;\n transform: translate3d(0,0,0);\n}"; + }; + + return ProgressBar; + + })(); + + bypassOnLoadPopstate = function(fn) { + return setTimeout(fn, 500); + }; + + installDocumentReadyPageEventTriggers = function() { + return document.addEventListener('DOMContentLoaded', (function() { + triggerEvent(EVENTS.CHANGE); + return triggerEvent(EVENTS.UPDATE); + }), true); + }; + + installJqueryAjaxSuccessPageUpdateTrigger = function() { + if (typeof jQuery !== 'undefined') { + return jQuery(document).on('ajaxSuccess', function(event, xhr, settings) { + if (!jQuery.trim(xhr.responseText)) { + return; + } + return triggerEvent(EVENTS.UPDATE); + }); + } + }; + + installHistoryChangeHandler = function(event) { + var cachedPage, ref; + if ((ref = event.state) != null ? ref.turbolinks : void 0) { + if (cachedPage = pageCache[(new ComponentUrl(event.state.url)).absolute]) { + cacheCurrentPage(); + return fetchHistory(cachedPage); + } else { + return visit(event.target.location.href); + } + } + }; + + initializeTurbolinks = function() { + rememberCurrentUrl(); + rememberCurrentState(); + document.addEventListener('click', Click.installHandlerLast, true); + window.addEventListener('hashchange', function(event) { + rememberCurrentUrl(); + return rememberCurrentState(); + }, false); + return bypassOnLoadPopstate(function() { + return window.addEventListener('popstate', installHistoryChangeHandler, false); + }); + }; + + historyStateIsDefined = window.history.state !== void 0 || navigator.userAgent.match(/Firefox\/2[6|7]/); + + browserSupportsPushState = window.history && window.history.pushState && window.history.replaceState && historyStateIsDefined; + + browserIsntBuggy = !navigator.userAgent.match(/CriOS\//); + + requestMethodIsSafe = (ref = popCookie('request_method')) === 'GET' || ref === ''; + + browserSupportsTurbolinks = browserSupportsPushState && browserIsntBuggy && requestMethodIsSafe; + + browserSupportsCustomEvents = document.addEventListener && document.createEvent; + + if (browserSupportsCustomEvents) { + installDocumentReadyPageEventTriggers(); + installJqueryAjaxSuccessPageUpdateTrigger(); + } + + if (browserSupportsTurbolinks) { + visit = fetch; + initializeTurbolinks(); + } else { + visit = function(url) { + return document.location.href = url; + }; + } + + this.Turbolinks = { + visit: visit, + pagesCached: pagesCached, + enableTransitionCache: enableTransitionCache, + enableProgressBar: enableProgressBar, + allowLinkExtensions: Link.allowExtensions, + supported: browserSupportsTurbolinks, + EVENTS: clone(EVENTS) + }; + +}).call(this); -- cgit v1.2.1 From fe964cc235ed22a5d013d5874284763b698aba7c Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 3 Nov 2016 16:38:54 -0500 Subject: migrate all javascript asset bundles and require syntax --- .eslintrc | 4 +- app/assets/javascripts/application.js | 111 ++++---- app/assets/javascripts/awards_handler.js | 4 +- app/assets/javascripts/behaviors/autosize.js | 4 +- app/assets/javascripts/behaviors/quick_submit.js | 2 +- app/assets/javascripts/behaviors/requires_input.js | 2 +- app/assets/javascripts/blob/blob_ci_yaml.js.es6 | 3 +- .../blob/blob_dockerfile_selector.js.es6 | 3 +- .../javascripts/blob/blob_gitignore_selector.js | 2 +- .../javascripts/blob/blob_license_selector.js | 2 +- .../javascripts/blob_edit/blob_edit_bundle.js | 2 +- app/assets/javascripts/boards/boards_bundle.js.es6 | 28 +- .../javascripts/boards/components/board.js.es6 | 6 +- .../boards/components/board_list.js.es6 | 4 +- app/assets/javascripts/copy_to_clipboard.js | 2 +- .../cycle_analytics/cycle_analytics_bundle.js.es6 | 9 +- .../diff_notes/diff_notes_bundle.js.es6 | 18 +- app/assets/javascripts/dropzone_input.js | 2 +- .../environments/components/environment.js.es6 | 8 +- .../components/environment_actions.js.es6 | 3 +- .../components/environment_external_url.js.es6 | 3 +- .../components/environment_item.js.es6 | 17 +- .../components/environment_rollback.js.es6 | 3 +- .../components/environment_stop.js.es6 | 3 +- .../components/environment_terminal_button.js.es6 | 3 +- .../environments/environments_bundle.js.es6 | 8 +- .../services/environments_service.js.es6 | 1 + app/assets/javascripts/gl_field_errors.js.es6 | 2 +- app/assets/javascripts/gl_form.js | 2 + app/assets/javascripts/graphs/graphs_bundle.js | 15 +- .../javascripts/graphs/stat_graph_contributors.js | 2 +- .../graphs/stat_graph_contributors_graph.js | 2 +- app/assets/javascripts/header.js | 1 - app/assets/javascripts/issue.js | 6 +- app/assets/javascripts/lib/chart.js | 6 +- app/assets/javascripts/lib/d3.js | 6 +- .../javascripts/lib/utils/datetime_utility.js | 4 +- .../javascripts/lib/utils/emoji_aliases.js.erb | 6 - app/assets/javascripts/line_highlighter.js | 2 +- .../merge_conflicts/merge_conflicts_bundle.js.es6 | 16 +- app/assets/javascripts/merge_request.js | 6 +- app/assets/javascripts/merge_request_tabs.js.es6 | 6 +- app/assets/javascripts/network/network_bundle.js | 10 +- app/assets/javascripts/notes.js | 15 +- app/assets/javascripts/pipelines.js.es6 | 2 +- app/assets/javascripts/profile/profile_bundle.js | 10 +- .../protected_branches_bundle.js | 4 +- app/assets/javascripts/shortcuts_blob.js | 2 +- .../javascripts/shortcuts_dashboard_navigation.js | 2 +- app/assets/javascripts/shortcuts_find_file.js | 2 +- app/assets/javascripts/shortcuts_issuable.js | 4 +- app/assets/javascripts/shortcuts_navigation.js | 2 +- app/assets/javascripts/shortcuts_network.js | 2 +- app/assets/javascripts/snippet/snippet_bundle.js | 4 +- app/assets/javascripts/subbable_resource.js.es6 | 3 - .../templates/issuable_template_selector.js.es6 | 2 +- .../javascripts/terminal/terminal_bundle.js.es6 | 10 +- app/assets/javascripts/users/users_bundle.js | 10 +- .../javascripts/vue_common_component/commit.js.es6 | 4 +- app/assets/javascripts/webpack/application.js | 293 --------------------- app/assets/javascripts/wikis.js.es6 | 6 +- app/assets/javascripts/zen_mode.js | 10 +- app/helpers/javascript_helper.rb | 3 + app/views/profiles/_head.html.haml | 2 +- app/views/projects/blob/edit.html.haml | 2 +- app/views/projects/blob/new.html.haml | 2 +- app/views/projects/boards/_show.html.haml | 4 +- app/views/projects/cycle_analytics/show.html.haml | 2 +- app/views/projects/environments/index.html.haml | 2 +- app/views/projects/graphs/_head.html.haml | 4 +- app/views/projects/merge_requests/_show.html.haml | 2 +- .../projects/merge_requests/conflicts.html.haml | 2 +- .../merge_requests/widget/open/_accept.html.haml | 2 +- .../merge_requests/widget/open/_check.html.haml | 2 +- app/views/projects/network/show.html.haml | 2 +- .../projects/protected_branches/index.html.haml | 2 +- app/views/shared/snippets/_form.html.haml | 3 +- app/views/users/show.html.haml | 4 +- config/application.rb | 20 +- config/webpack.config.js | 21 +- package.json | 1 + vendor/assets/javascripts/es6-promise.auto.js | 3 - vendor/assets/javascripts/xterm/fit.js | 4 +- 83 files changed, 261 insertions(+), 564 deletions(-) delete mode 100644 app/assets/javascripts/lib/utils/emoji_aliases.js.erb delete mode 100644 app/assets/javascripts/webpack/application.js diff --git a/.eslintrc b/.eslintrc index e13f76b213c..8bab73bbe16 100644 --- a/.eslintrc +++ b/.eslintrc @@ -15,6 +15,8 @@ "filenames" ], "rules": { - "filenames/match-regex": [2, "^[a-z0-9_]+(.js)?$"] + "filenames/match-regex": [2, "^[a-z0-9_]+(.js)?$"], + "import/no-extraneous-dependencies": "off", + "import/no-unresolved": "off" } } diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index c21f0572fa7..830d706f02d 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -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,62 +6,59 @@ /* 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.caret */ -/*= 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 . */ -/*= 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'); +require('vendor/jquery.turbolinks'); +window.Cookies = require('vendor/js.cookie'); +require('vendor/turbolinks'); +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'); +require('vendor/date.format'); +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('.', false, /^\.\/(?!application).*\.(js|es6)$/)); +require('vendor/fuzzaldrin-plus'); +window.ES6Promise = require('vendor/es6-promise.auto'); +window.ES6Promise.polyfill(); (function () { document.addEventListener('page:fetch', function () { diff --git a/app/assets/javascripts/awards_handler.js b/app/assets/javascripts/awards_handler.js index 107a7978a87..db9df8cdd3c 100644 --- a/app/assets/javascripts/awards_handler.js +++ b/app/assets/javascripts/awards_handler.js @@ -1,11 +1,13 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, no-var, spaced-comment, 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, radix, keyword-spacing, space-before-blocks, brace-style, no-underscore-dangle, no-plusplus, no-return-assign, camelcase, padded-blocks */ /* 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(); diff --git a/app/assets/javascripts/behaviors/autosize.js b/app/assets/javascripts/behaviors/autosize.js index c62a4c5a456..9b5cd25989d 100644 --- a/app/assets/javascripts/behaviors/autosize.js +++ b/app/assets/javascripts/behaviors/autosize.js @@ -1,8 +1,8 @@ /* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, consistent-return, padded-blocks, max-len */ /* global autosize */ -/*= require jquery.ba-resize */ -/*= require autosize */ +var autosize = require('vendor/autosize'); +require('vendor/jquery.ba-resize'); (function() { $(function() { diff --git a/app/assets/javascripts/behaviors/quick_submit.js b/app/assets/javascripts/behaviors/quick_submit.js index 586f941a6e3..4f43e8baf42 100644 --- a/app/assets/javascripts/behaviors/quick_submit.js +++ b/app/assets/javascripts/behaviors/quick_submit.js @@ -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 diff --git a/app/assets/javascripts/behaviors/requires_input.js b/app/assets/javascripts/behaviors/requires_input.js index 72362988b2e..28bc06c5d76 100644 --- a/app/assets/javascripts/behaviors/requires_input.js +++ b/app/assets/javascripts/behaviors/requires_input.js @@ -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 diff --git a/app/assets/javascripts/blob/blob_ci_yaml.js.es6 b/app/assets/javascripts/blob/blob_ci_yaml.js.es6 index 57bd13eecf8..a548509ee0d 100644 --- a/app/assets/javascripts/blob/blob_ci_yaml.js.es6 +++ b/app/assets/javascripts/blob/blob_ci_yaml.js.es6 @@ -1,7 +1,8 @@ /* eslint-disable padded-blocks, no-param-reassign, comma-dangle */ /* global Api */ -/*= require blob/template_selector */ +require('./template_selector'); + ((global) => { class BlobCiYamlSelector extends gl.TemplateSelector { diff --git a/app/assets/javascripts/blob/blob_dockerfile_selector.js.es6 b/app/assets/javascripts/blob/blob_dockerfile_selector.js.es6 index bdf95017613..d4f60cc6ecd 100644 --- a/app/assets/javascripts/blob/blob_dockerfile_selector.js.es6 +++ b/app/assets/javascripts/blob/blob_dockerfile_selector.js.es6 @@ -1,5 +1,6 @@ /* global Api */ -/*= require blob/template_selector */ + +require('./template_selector'); (() => { const global = window.gl || (window.gl = {}); diff --git a/app/assets/javascripts/blob/blob_gitignore_selector.js b/app/assets/javascripts/blob/blob_gitignore_selector.js index 15563e429a0..82a198ad825 100644 --- a/app/assets/javascripts/blob/blob_gitignore_selector.js +++ b/app/assets/javascripts/blob/blob_gitignore_selector.js @@ -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, padded-blocks */ /* 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; }, diff --git a/app/assets/javascripts/blob/blob_license_selector.js b/app/assets/javascripts/blob/blob_license_selector.js index d9c6f65a083..4c3ca20e25d 100644 --- a/app/assets/javascripts/blob/blob_license_selector.js +++ b/app/assets/javascripts/blob/blob_license_selector.js @@ -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, padded-blocks */ /* 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; }, diff --git a/app/assets/javascripts/blob_edit/blob_edit_bundle.js b/app/assets/javascripts/blob_edit/blob_edit_bundle.js index 8c40e36a80a..9c523d3b22e 100644 --- a/app/assets/javascripts/blob_edit/blob_edit_bundle.js +++ b/app/assets/javascripts/blob_edit/blob_edit_bundle.js @@ -2,7 +2,7 @@ /* global EditBlob */ /* global NewCommitForm */ -/*= require_tree . */ +require('./edit_blob'); (function() { $(function() { diff --git a/app/assets/javascripts/boards/boards_bundle.js.es6 b/app/assets/javascripts/boards/boards_bundle.js.es6 index 2c9ab61c94d..9f454486efc 100644 --- a/app/assets/javascripts/boards/boards_bundle.js.es6 +++ b/app/assets/javascripts/boards/boards_bundle.js.es6 @@ -1,19 +1,21 @@ -/* eslint-disable one-var, indent, quote-props, comma-dangle, space-before-function-paren */ +/* eslint-disable one-var, indent, 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('./vue_resource_interceptor'); $(() => { const $boardApp = document.getElementById('board-app'), diff --git a/app/assets/javascripts/boards/components/board.js.es6 b/app/assets/javascripts/boards/components/board.js.es6 index d1fb0ec48e0..07960fbbd80 100644 --- a/app/assets/javascripts/boards/components/board.js.es6 +++ b/app/assets/javascripts/boards/components/board.js.es6 @@ -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; diff --git a/app/assets/javascripts/boards/components/board_list.js.es6 b/app/assets/javascripts/boards/components/board_list.js.es6 index 6711930622b..d896076d4af 100644 --- a/app/assets/javascripts/boards/components/board_list.js.es6 +++ b/app/assets/javascripts/boards/components/board_list.js.es6 @@ -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; diff --git a/app/assets/javascripts/copy_to_clipboard.js b/app/assets/javascripts/copy_to_clipboard.js index 6a13f38588d..0a6f95e96ec 100644 --- a/app/assets/javascripts/copy_to_clipboard.js +++ b/app/assets/javascripts/copy_to_clipboard.js @@ -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, padded-blocks, max-len */ /* global Clipboard */ -/*= require clipboard */ +window.Clipboard = require('vendor/clipboard'); (function() { var genericError, genericSuccess, showTooltip; diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6 b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6 index 2f810a69758..3b2f5efa27d 100644 --- a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6 +++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6 @@ -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('.', false, /^\.\/(?!cycle_analytics_bundle).*\.(js|es6)$/)); $(() => { const OVERVIEW_DIALOG_COOKIE = 'cycle_analytics_help_dismissed'; diff --git a/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6 b/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6 index 840b5aa922e..0a25b8f1ccd 100644 --- a/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6 +++ b/app/assets/javascripts/diff_notes/diff_notes_bundle.js.es6 @@ -1,14 +1,16 @@ -/* 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 vue -//= require vue-resource -//= require_directory ./models -//= require_directory ./stores -//= require_directory ./services -//= require_directory ./mixins -//= require_directory ./components +function requireAll(context) { return context.keys().map(context); } + +window.Vue = require('vue'); +window.Vue.use(require('vue-resource')); +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'; diff --git a/app/assets/javascripts/dropzone_input.js b/app/assets/javascripts/dropzone_input.js index 56cb39be642..b280ab88c8d 100644 --- a/app/assets/javascripts/dropzone_input.js +++ b/app/assets/javascripts/dropzone_input.js @@ -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, no-plusplus, prefer-arrow-callback, padded-blocks */ /* global Dropzone */ -/*= require preview_markdown */ +require('./preview_markdown'); (function() { this.DropzoneInput = (function() { diff --git a/app/assets/javascripts/environments/components/environment.js.es6 b/app/assets/javascripts/environments/components/environment.js.es6 index 6b7fb9215d1..cc533620ead 100644 --- a/app/assets/javascripts/environments/components/environment.js.es6 +++ b/app/assets/javascripts/environments/components/environment.js.es6 @@ -2,10 +2,10 @@ /* global Vue */ /* global EnvironmentsService */ -//= 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 || {}; diff --git a/app/assets/javascripts/environments/components/environment_actions.js.es6 b/app/assets/javascripts/environments/components/environment_actions.js.es6 index 81468f4d3bc..ed1c78945db 100644 --- a/app/assets/javascripts/environments/components/environment_actions.js.es6 +++ b/app/assets/javascripts/environments/components/environment_actions.js.es6 @@ -1,6 +1,7 @@ -/*= require vue */ /* global Vue */ +window.Vue = require('vue'); + (() => { window.gl = window.gl || {}; window.gl.environmentsList = window.gl.environmentsList || {}; diff --git a/app/assets/javascripts/environments/components/environment_external_url.js.es6 b/app/assets/javascripts/environments/components/environment_external_url.js.es6 index 6592c1b5f0f..28cc0022d17 100644 --- a/app/assets/javascripts/environments/components/environment_external_url.js.es6 +++ b/app/assets/javascripts/environments/components/environment_external_url.js.es6 @@ -1,6 +1,7 @@ -/*= require vue */ /* global Vue */ +window.Vue = require('vue'); + (() => { window.gl = window.gl || {}; window.gl.environmentsList = window.gl.environmentsList || {}; diff --git a/app/assets/javascripts/environments/components/environment_item.js.es6 b/app/assets/javascripts/environments/components/environment_item.js.es6 index 0e6bc3fdb2c..521873b14b4 100644 --- a/app/assets/javascripts/environments/components/environment_item.js.es6 +++ b/app/assets/javascripts/environments/components/environment_item.js.es6 @@ -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'); (() => { /** diff --git a/app/assets/javascripts/environments/components/environment_rollback.js.es6 b/app/assets/javascripts/environments/components/environment_rollback.js.es6 index b52298b4a88..5938340a128 100644 --- a/app/assets/javascripts/environments/components/environment_rollback.js.es6 +++ b/app/assets/javascripts/environments/components/environment_rollback.js.es6 @@ -1,6 +1,7 @@ -/*= require vue */ /* global Vue */ +window.Vue = require('vue'); + (() => { window.gl = window.gl || {}; window.gl.environmentsList = window.gl.environmentsList || {}; diff --git a/app/assets/javascripts/environments/components/environment_stop.js.es6 b/app/assets/javascripts/environments/components/environment_stop.js.es6 index 0a29f2f36e9..be9526989a0 100644 --- a/app/assets/javascripts/environments/components/environment_stop.js.es6 +++ b/app/assets/javascripts/environments/components/environment_stop.js.es6 @@ -1,6 +1,7 @@ -/*= require vue */ /* global Vue */ +window.Vue = require('vue'); + (() => { window.gl = window.gl || {}; window.gl.environmentsList = window.gl.environmentsList || {}; diff --git a/app/assets/javascripts/environments/components/environment_terminal_button.js.es6 b/app/assets/javascripts/environments/components/environment_terminal_button.js.es6 index 050184ba497..a3ad063f7cb 100644 --- a/app/assets/javascripts/environments/components/environment_terminal_button.js.es6 +++ b/app/assets/javascripts/environments/components/environment_terminal_button.js.es6 @@ -1,6 +1,7 @@ -/*= require vue */ /* global Vue */ +window.Vue = require('vue'); + (() => { window.gl = window.gl || {}; window.gl.environmentsList = window.gl.environmentsList || {}; diff --git a/app/assets/javascripts/environments/environments_bundle.js.es6 b/app/assets/javascripts/environments/environments_bundle.js.es6 index 9f24a6a4f88..58f4c6eadb2 100644 --- a/app/assets/javascripts/environments/environments_bundle.js.es6 +++ b/app/assets/javascripts/environments/environments_bundle.js.es6 @@ -1,8 +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 || {}; diff --git a/app/assets/javascripts/environments/services/environments_service.js.es6 b/app/assets/javascripts/environments/services/environments_service.js.es6 index 575a45d9802..fab8d977f58 100644 --- a/app/assets/javascripts/environments/services/environments_service.js.es6 +++ b/app/assets/javascripts/environments/services/environments_service.js.es6 @@ -1,5 +1,6 @@ /* globals Vue */ /* eslint-disable no-unused-vars, no-param-reassign */ + class EnvironmentsService { constructor(root) { diff --git a/app/assets/javascripts/gl_field_errors.js.es6 b/app/assets/javascripts/gl_field_errors.js.es6 index 63f9cafa8d0..8b46c4e378f 100644 --- a/app/assets/javascripts/gl_field_errors.js.es6 +++ b/app/assets/javascripts/gl_field_errors.js.es6 @@ -1,6 +1,6 @@ /* eslint-disable comma-dangle, class-methods-use-this, max-len, space-before-function-paren, arrow-parens, no-param-reassign, padded-blocks */ -//= require gl_field_error +require('./gl_field_error'); ((global) => { const customValidationFlag = 'gl-field-error-ignore'; diff --git a/app/assets/javascripts/gl_form.js b/app/assets/javascripts/gl_form.js index 04814fa0843..34244813b4b 100644 --- a/app/assets/javascripts/gl_form.js +++ b/app/assets/javascripts/gl_form.js @@ -3,6 +3,8 @@ /* global DropzoneInput */ /* global autosize */ +var autosize = require('vendor/autosize'); + (function() { this.GLForm = (function() { function GLForm(form) { diff --git a/app/assets/javascripts/graphs/graphs_bundle.js b/app/assets/javascripts/graphs/graphs_bundle.js index 32c26349da0..4f7777aa5bc 100644 --- a/app/assets/javascripts/graphs/graphs_bundle.js +++ b/app/assets/javascripts/graphs/graphs_bundle.js @@ -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)$/)); diff --git a/app/assets/javascripts/graphs/stat_graph_contributors.js b/app/assets/javascripts/graphs/stat_graph_contributors.js index 2d08a7c6ac3..c702ce2743d 100644 --- a/app/assets/javascripts/graphs/stat_graph_contributors.js +++ b/app/assets/javascripts/graphs/stat_graph_contributors.js @@ -5,7 +5,7 @@ /* global ContributorsStatGraphUtil */ /* global d3 */ -/*= require d3 */ +window.d3 = require('d3'); (function() { this.ContributorsStatGraph = (function() { diff --git a/app/assets/javascripts/graphs/stat_graph_contributors_graph.js b/app/assets/javascripts/graphs/stat_graph_contributors_graph.js index 9c5e9381e52..3b7370bd8f6 100644 --- a/app/assets/javascripts/graphs/stat_graph_contributors_graph.js +++ b/app/assets/javascripts/graphs/stat_graph_contributors_graph.js @@ -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); }; }, diff --git a/app/assets/javascripts/header.js b/app/assets/javascripts/header.js index c7cbf9ca44b..9dd14b4c2ed 100644 --- a/app/assets/javascripts/header.js +++ b/app/assets/javascripts/header.js @@ -1,6 +1,5 @@ /* eslint-disable wrap-iife, func-names, space-before-function-paren, padded-blocks, prefer-arrow-callback, no-var, max-len */ (function() { - $(document).on('todo:toggle', function(e, count) { var $todoPendingCount = $('.todos-pending-count'); $todoPendingCount.text(gl.text.addDelimiter(count)); diff --git a/app/assets/javascripts/issue.js b/app/assets/javascripts/issue.js index 61e8531153b..97e03ede0e5 100644 --- a/app/assets/javascripts/issue.js +++ b/app/assets/javascripts/issue.js @@ -1,9 +1,9 @@ /* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, 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, padded-blocks, 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); }; }; diff --git a/app/assets/javascripts/lib/chart.js b/app/assets/javascripts/lib/chart.js index d8ad5aaeffe..9b011d89e93 100644 --- a/app/assets/javascripts/lib/chart.js +++ b/app/assets/javascripts/lib/chart.js @@ -1,7 +1,3 @@ /* eslint-disable func-names, space-before-function-paren */ -/*= require Chart */ - -(function() { - -}).call(this); +window.Chart = require('vendor/Chart'); diff --git a/app/assets/javascripts/lib/d3.js b/app/assets/javascripts/lib/d3.js index 57e7986576c..a9dd32edbed 100644 --- a/app/assets/javascripts/lib/d3.js +++ b/app/assets/javascripts/lib/d3.js @@ -1,7 +1,3 @@ /* eslint-disable func-names, space-before-function-paren */ -/*= require d3 */ - -(function() { - -}).call(this); +window.d3 = require('d3'); diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js index 30e4e490543..b6c1fd4c4f8 100644 --- a/app/assets/javascripts/lib/utils/datetime_utility.js +++ b/app/assets/javascripts/lib/utils/datetime_utility.js @@ -2,8 +2,8 @@ /* global timeago */ /* global dateFormat */ -/*= require timeago */ -/*= require date.format */ +window.timeago = require('vendor/timeago'); +require('vendor/date.format'); (function() { (function(w) { diff --git a/app/assets/javascripts/lib/utils/emoji_aliases.js.erb b/app/assets/javascripts/lib/utils/emoji_aliases.js.erb deleted file mode 100644 index aeb86c9fa5b..00000000000 --- a/app/assets/javascripts/lib/utils/emoji_aliases.js.erb +++ /dev/null @@ -1,6 +0,0 @@ -(function() { - gl.emojiAliases = function() { - return JSON.parse('<%= Gitlab::AwardEmoji.aliases.to_json %>'); - }; - -}).call(this); diff --git a/app/assets/javascripts/line_highlighter.js b/app/assets/javascripts/line_highlighter.js index 9af89b79f84..e7351173610 100644 --- a/app/assets/javascripts/line_highlighter.js +++ b/app/assets/javascripts/line_highlighter.js @@ -4,7 +4,7 @@ // // Handles single- and multi-line selection and highlight for blob views. // -/*= require jquery.scrollTo */ +require('vendor/jquery.scrollTo'); // // ### Example Markup diff --git a/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js.es6 b/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js.es6 index 83520702f9b..92fad17cf00 100644 --- a/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js.es6 +++ b/app/assets/javascripts/merge_conflicts/merge_conflicts_bundle.js.es6 @@ -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'; diff --git a/app/assets/javascripts/merge_request.js b/app/assets/javascripts/merge_request.js index 244c2f6746c..19526157410 100644 --- a/app/assets/javascripts/merge_request.js +++ b/app/assets/javascripts/merge_request.js @@ -1,9 +1,9 @@ /* eslint-disable func-names, space-before-function-paren, no-var, space-before-blocks, 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, padded-blocks, 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); }; }; diff --git a/app/assets/javascripts/merge_request_tabs.js.es6 b/app/assets/javascripts/merge_request_tabs.js.es6 index 860e7e066a0..b8ab00458de 100644 --- a/app/assets/javascripts/merge_request_tabs.js.es6 +++ b/app/assets/javascripts/merge_request_tabs.js.es6 @@ -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 diff --git a/app/assets/javascripts/network/network_bundle.js b/app/assets/javascripts/network/network_bundle.js index 17833d3419a..1e91911c02c 100644 --- a/app/assets/javascripts/network/network_bundle.js +++ b/app/assets/javascripts/network/network_bundle.js @@ -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() { diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 8de5a6191b6..872c0d0caaa 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -4,13 +4,14 @@ /* global Autosave */ /* global ResolveService */ -/*= 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); }; }; diff --git a/app/assets/javascripts/pipelines.js.es6 b/app/assets/javascripts/pipelines.js.es6 index 0b09ad113a3..f704551a548 100644 --- a/app/assets/javascripts/pipelines.js.es6 +++ b/app/assets/javascripts/pipelines.js.es6 @@ -1,6 +1,6 @@ /* eslint-disable no-new, guard-for-in, no-restricted-syntax, no-continue, padded-blocks, no-param-reassign, max-len */ -//= require lib/utils/bootstrap_linked_tabs +require('./lib/utils/bootstrap_linked_tabs'); ((global) => { diff --git a/app/assets/javascripts/profile/profile_bundle.js b/app/assets/javascripts/profile/profile_bundle.js index f50802bdf2e..d7f3c9fd37e 100644 --- a/app/assets/javascripts/profile/profile_bundle.js +++ b/app/assets/javascripts/profile/profile_bundle.js @@ -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)$/)); diff --git a/app/assets/javascripts/protected_branches/protected_branches_bundle.js b/app/assets/javascripts/protected_branches/protected_branches_bundle.js index 15b3affd469..ffb66caf5f4 100644 --- a/app/assets/javascripts/protected_branches/protected_branches_bundle.js +++ b/app/assets/javascripts/protected_branches/protected_branches_bundle.js @@ -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)$/)); diff --git a/app/assets/javascripts/shortcuts_blob.js b/app/assets/javascripts/shortcuts_blob.js index c26903038b4..41c00e2048b 100644 --- a/app/assets/javascripts/shortcuts_blob.js +++ b/app/assets/javascripts/shortcuts_blob.js @@ -2,7 +2,7 @@ /* global Shortcuts */ /* global Mousetrap */ -/*= require shortcuts */ +require('./shortcuts'); (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; }, diff --git a/app/assets/javascripts/shortcuts_dashboard_navigation.js b/app/assets/javascripts/shortcuts_dashboard_navigation.js index 4549742bbcb..bc33d52a906 100644 --- a/app/assets/javascripts/shortcuts_dashboard_navigation.js +++ b/app/assets/javascripts/shortcuts_dashboard_navigation.js @@ -2,7 +2,7 @@ /* global Mousetrap */ /* global Shortcuts */ -/*= require shortcuts */ +require('./shortcuts'); (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; }, diff --git a/app/assets/javascripts/shortcuts_find_file.js b/app/assets/javascripts/shortcuts_find_file.js index 3a81380eef0..775c3a5e9b7 100644 --- a/app/assets/javascripts/shortcuts_find_file.js +++ b/app/assets/javascripts/shortcuts_find_file.js @@ -2,7 +2,7 @@ /* global Mousetrap */ /* global ShortcutsNavigation */ -/*= require shortcuts_navigation */ +require('./shortcuts_navigation'); (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; }, diff --git a/app/assets/javascripts/shortcuts_issuable.js b/app/assets/javascripts/shortcuts_issuable.js index b892fbc3393..2823e43585c 100644 --- a/app/assets/javascripts/shortcuts_issuable.js +++ b/app/assets/javascripts/shortcuts_issuable.js @@ -4,8 +4,8 @@ /* global ShortcutsNavigation */ /* global sidebar */ -/*= require mousetrap */ -/*= require shortcuts_navigation */ +require('mousetrap'); +require('./shortcuts_navigation'); (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; }, diff --git a/app/assets/javascripts/shortcuts_navigation.js b/app/assets/javascripts/shortcuts_navigation.js index 0776d0a9b67..d35d1dd6bf2 100644 --- a/app/assets/javascripts/shortcuts_navigation.js +++ b/app/assets/javascripts/shortcuts_navigation.js @@ -2,7 +2,7 @@ /* global Mousetrap */ /* global Shortcuts */ -/*= require shortcuts */ +require('./shortcuts'); (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; }, diff --git a/app/assets/javascripts/shortcuts_network.js b/app/assets/javascripts/shortcuts_network.js index ecc3fab84c3..6a73b48899b 100644 --- a/app/assets/javascripts/shortcuts_network.js +++ b/app/assets/javascripts/shortcuts_network.js @@ -2,7 +2,7 @@ /* global Mousetrap */ /* global ShortcutsNavigation */ -/*= require shortcuts_navigation */ +require('./shortcuts_navigation'); (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; }, diff --git a/app/assets/javascripts/snippet/snippet_bundle.js b/app/assets/javascripts/snippet/snippet_bundle.js index 18512d179b3..a3f128f9315 100644 --- a/app/assets/javascripts/snippet/snippet_bundle.js +++ b/app/assets/javascripts/snippet/snippet_bundle.js @@ -1,7 +1,9 @@ /* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, quotes, semi, padded-blocks, max-len */ /* global ace */ -/*= require_tree . */ +// require everything else in this directory +function requireAll(context) { return context.keys().map(context); } +requireAll(require.context('.', false, /^\.\/(?!snippet_bundle).*\.(js|es6)$/)); (function() { $(function() { diff --git a/app/assets/javascripts/subbable_resource.js.es6 b/app/assets/javascripts/subbable_resource.js.es6 index 932120157a3..d8191605128 100644 --- a/app/assets/javascripts/subbable_resource.js.es6 +++ b/app/assets/javascripts/subbable_resource.js.es6 @@ -1,6 +1,3 @@ -//= require vue -//= require vue-resource - (() => { /* * SubbableResource can be extended to provide a pubsub-style service for one-off REST diff --git a/app/assets/javascripts/templates/issuable_template_selector.js.es6 b/app/assets/javascripts/templates/issuable_template_selector.js.es6 index bdec948fb63..8dce6ed9fbf 100644 --- a/app/assets/javascripts/templates/issuable_template_selector.js.es6 +++ b/app/assets/javascripts/templates/issuable_template_selector.js.es6 @@ -1,7 +1,7 @@ /* eslint-disable prefer-const, comma-dangle, max-len, no-useless-return, object-curly-spacing, no-param-reassign, max-len */ /* global Api */ -/*= require ../blob/template_selector */ +require('../blob/template_selector'); ((global) => { class IssuableTemplateSelector extends gl.TemplateSelector { diff --git a/app/assets/javascripts/terminal/terminal_bundle.js.es6 b/app/assets/javascripts/terminal/terminal_bundle.js.es6 index 33d2c1e1a17..13cf3a10a38 100644 --- a/app/assets/javascripts/terminal/terminal_bundle.js.es6 +++ b/app/assets/javascripts/terminal/terminal_bundle.js.es6 @@ -1,7 +1,7 @@ -//= require xterm/encoding-indexes -//= require xterm/encoding -//= require xterm/xterm.js -//= require xterm/fit.js -//= require ./terminal.js +require('vendor/xterm/encoding-indexes.js'); +require('vendor/xterm/encoding.js'); +window.Terminal = require('vendor/xterm/xterm.js'); +require('vendor/xterm/fit.js'); +require('./terminal.js'); $(() => new gl.Terminal({ selector: '#terminal' })); diff --git a/app/assets/javascripts/users/users_bundle.js b/app/assets/javascripts/users/users_bundle.js index f50802bdf2e..4cad60a59b1 100644 --- a/app/assets/javascripts/users/users_bundle.js +++ b/app/assets/javascripts/users/users_bundle.js @@ -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, /^\.\/(?!users_bundle).*\.(js|es6)$/)); diff --git a/app/assets/javascripts/vue_common_component/commit.js.es6 b/app/assets/javascripts/vue_common_component/commit.js.es6 index 62a22e39a3b..4adad7bea31 100644 --- a/app/assets/javascripts/vue_common_component/commit.js.es6 +++ b/app/assets/javascripts/vue_common_component/commit.js.es6 @@ -1,5 +1,7 @@ -/*= require vue */ /* global Vue */ + +window.Vue = require('vue'); + (() => { window.gl = window.gl || {}; diff --git a/app/assets/javascripts/webpack/application.js b/app/assets/javascripts/webpack/application.js deleted file mode 100644 index 660e00d4c5b..00000000000 --- a/app/assets/javascripts/webpack/application.js +++ /dev/null @@ -1,293 +0,0 @@ -/* eslint-disable */ - -/** - * Simulate sprockets compile order of application.js through CommonJS require statements - * - * Currently exports everything appropriate to window until the scripts that rely on this behavior - * can be refactored. - * - * Test the output from this against sprockets output and it should be almost identical apart from - * webpack's CommonJS wrapper. You can add the following line to webpack.config.js to fix the - * script indentation: - * config.output.sourcePrefix = ''; - */ - -/*= require jquery2 */ -window.jQuery = window.$ = require('jquery'); - -/*= require jquery-ui/autocomplete */ -// depends on jquery-ui/core, jquery-ui/widget, jquery-ui/menu, jquery-ui/position -require('jquery-ui/ui/core'); -require('jquery-ui/ui/widget'); -require('jquery-ui/ui/position'); -require('jquery-ui/ui/menu'); -require('jquery-ui/ui/autocomplete'); - -/*= require jquery-ui/datepicker */ -// depends on jquery-ui/core -require('jquery-ui/ui/datepicker'); - -/*= require jquery-ui/draggable */ -// depends on jquery-ui/core, jquery-ui/widget, jquery-ui/mouse -require('jquery-ui/ui/mouse'); -require('jquery-ui/ui/draggable'); - -/*= require jquery-ui/effect-highlight */ -// depends on jquery-ui/effect -require('jquery-ui/ui/effect'); -require('jquery-ui/ui/effect-highlight'); - -/*= require jquery-ui/sortable */ -// depends on jquery-ui/core, jquery-ui/widget, jquery-ui/mouse -require('jquery-ui/ui/sortable'); - -/*= require jquery_ujs */ -require('jquery-ujs'); - -/*= require jquery.endless-scroll */ -require('vendor/jquery.endless-scroll'); - -/*= require jquery.highlight */ -require('vendor/jquery.highlight'); - -/*= require jquery.waitforimages */ -require('vendor/jquery.waitforimages'); - -/*= require jquery.atwho */ -require('vendor/jquery.caret'); // required by jquery.atwho -require('vendor/jquery.atwho'); - -/*= require jquery.scrollTo */ -require('vendor/jquery.scrollTo'); - -/*= require jquery.turbolinks */ -require('vendor/jquery.turbolinks'); - -/*= require js.cookie */ -window.Cookies = require('vendor/js.cookie'); - -/*= require turbolinks */ -require('vendor/turbolinks'); - -/*= require autosave */ -require('../autosave'); - -/*= require bootstrap/affix */ -require('bootstrap/js/affix'); - -/*= require bootstrap/alert */ -require('bootstrap/js/alert'); - -/*= require bootstrap/button */ -require('bootstrap/js/button'); - -/*= require bootstrap/collapse */ -require('bootstrap/js/collapse'); - -/*= require bootstrap/dropdown */ -require('bootstrap/js/dropdown'); - -/*= require bootstrap/modal */ -require('bootstrap/js/modal'); - -/*= require bootstrap/scrollspy */ -require('bootstrap/js/scrollspy'); - -/*= require bootstrap/tab */ -require('bootstrap/js/tab'); - -/*= require bootstrap/transition */ -require('bootstrap/js/transition'); - -/*= require bootstrap/tooltip */ -require('bootstrap/js/tooltip'); - -/*= require bootstrap/popover */ -require('bootstrap/js/popover'); - -/*= require select2 */ -require('select2/select2.js'); - -/*= require underscore */ -window._ = require('underscore'); - -/*= require dropzone */ -window.Dropzone = require('dropzone'); - -/*= require mousetrap */ -require('mousetrap'); - -/*= require mousetrap/pause */ -require('mousetrap/plugins/pause/mousetrap-pause'); - -/*= require shortcuts */ -require('../shortcuts'); - -/*= require shortcuts_navigation */ -require('../shortcuts_navigation'); - -/*= require shortcuts_dashboard_navigation */ -require('../shortcuts_dashboard_navigation'); - -/*= require shortcuts_issuable */ -require('../shortcuts_issuable'); - -/*= require shortcuts_network */ -require('../shortcuts_network'); - -/*= require jquery.nicescroll */ -require('vendor/jquery.nicescroll'); - -/*= require date.format */ -require('vendor/date.format'); - -/*= require_directory ./behaviors */ -require('vendor/jquery.ba-resize'); -window.autosize = require('vendor/autosize'); -require('../behaviors/autosize'); // requires vendor/jquery.ba-resize and vendor/autosize -require('../behaviors/details_behavior'); -require('../extensions/jquery'); -require('../behaviors/quick_submit'); // requires extensions/jquery -require('../behaviors/requires_input'); -require('../behaviors/toggler_behavior'); - -/*= require_directory ./blob */ -require('../blob/template_selector'); -require('../blob/blob_ci_yaml'); // requires template_selector -require('../blob/blob_file_dropzone'); -require('../blob/blob_gitignore_selector'); -require('../blob/blob_gitignore_selectors'); -require('../blob/blob_license_selector'); -require('../blob/blob_license_selectors'); - -/*= require_directory ./templates */ -require('../templates/issuable_template_selector'); -require('../templates/issuable_template_selectors'); - -/*= require_directory ./commit */ -require('../commit/file'); -require('../commit/image_file'); - -/*= require_directory ./extensions */ -require('../extensions/array'); -require('../extensions/element'); - -/*= require_directory ./lib/utils */ -require('../lib/utils/animate'); -require('../lib/utils/common_utils'); -require('../lib/utils/datetime_utility'); -// require('../lib/utils/emoji_aliases.js.erb'); -window.gl.emojiAliases = function() { return require('emoji-aliases'); }; -require('../lib/utils/jquery.timeago'); -require('../lib/utils/notify'); -require('../lib/utils/text_utility'); -require('../lib/utils/type_utility'); -require('../lib/utils/url_utility'); - -/*= require_directory ./u2f */ -require('../u2f/authenticate'); -require('../u2f/error'); -require('../u2f/register'); -require('../u2f/util'); - -/*= require_directory . */ -require('../abuse_reports'); -require('../activities'); -require('../admin'); -require('../api'); -require('../aside'); -require('../awards_handler'); -require('../breakpoints'); -require('../broadcast_message'); -require('../build'); -require('../build_artifacts'); -require('../build_variables'); -require('../commit'); -require('../commits'); -require('../compare'); -require('../compare_autocomplete'); -require('../confirm_danger_modal'); -window.Clipboard = require('vendor/clipboard'); // required by copy_to_clipboard -require('../copy_to_clipboard'); -require('../create_label'); -require('vue'); // required by cycle_analytics -require('../cycle_analytics'); -require('../diff'); -require('../dispatcher'); -require('../preview_markdown'); -require('../dropzone_input'); -require('../due_date_select'); -require('../files_comment_button'); -require('../flash'); -require('../gfm_auto_complete'); -require('../gl_dropdown'); -require('../gl_field_errors'); -require('../gl_form'); -require('../group_avatar'); -require('../groups_select'); -require('../header'); -require('../importer_status'); -require('../issuable'); -require('../issuable_context'); -require('../issuable_form'); -require('vendor/task_list'); // required by issue -require('../issue'); -require('../issue_status_select'); -require('../issues_bulk_assignment'); -require('../label_manager'); -require('../labels'); -require('../labels_select'); -require('../layout_nav'); -require('../line_highlighter'); -require('../logo'); -require('../member_expiration_date'); -require('../members'); -require('../merge_request_tabs'); -require('../merge_request'); -require('../merge_request_widget'); -require('../merged_buttons'); -require('../milestone'); -require('../milestone_select'); -require('../namespace_select'); -require('../new_branch_form'); -require('../new_commit_form'); -require('../notes'); -require('../notifications_dropdown'); -require('../notifications_form'); -require('../pager'); -require('../pipelines'); -require('../project'); -require('../project_avatar'); -require('../project_find_file'); -require('../project_fork'); -require('../project_import'); -require('../project_new'); -require('../project_select'); -require('../project_show'); -require('../projects_list'); -require('../right_sidebar'); -require('../search'); -require('../search_autocomplete'); -require('../shortcuts_blob'); -require('../shortcuts_find_file'); -require('../sidebar'); -require('../single_file_diff'); -require('../snippets_list'); -require('../star'); -require('../subscription'); -require('../subscription_select'); -require('../syntax_highlight'); -require('../todos'); -require('../tree'); -require('../user'); -require('../user_tabs'); -require('../username_validator'); -require('../users_select'); -require('vendor/latinise'); // required by wikis -require('../wikis'); -require('../zen_mode'); - -/*= require fuzzaldrin-plus */ -require('vendor/fuzzaldrin-plus'); - -require('../application'); diff --git a/app/assets/javascripts/wikis.js.es6 b/app/assets/javascripts/wikis.js.es6 index ecff5fd5bf4..ef99b2e92f0 100644 --- a/app/assets/javascripts/wikis.js.es6 +++ b/app/assets/javascripts/wikis.js.es6 @@ -1,9 +1,9 @@ /* eslint-disable no-param-reassign */ /* global Breakpoints */ -/*= require latinise */ -/*= require breakpoints */ -/*= require jquery.nicescroll */ +require('vendor/latinise'); +require('./breakpoints'); +require('vendor/jquery.nicescroll'); ((global) => { const dasherize = str => str.replace(/[_\s]+/g, '-'); diff --git a/app/assets/javascripts/zen_mode.js b/app/assets/javascripts/zen_mode.js index e09b59dd5aa..a1c3a19a3e9 100644 --- a/app/assets/javascripts/zen_mode.js +++ b/app/assets/javascripts/zen_mode.js @@ -6,11 +6,11 @@ // /*= provides zen_mode:enter */ /*= provides zen_mode:leave */ -// -/*= require jquery.scrollTo */ -/*= require dropzone */ -/*= require mousetrap */ -/*= require mousetrap/pause */ + +require('vendor/jquery.scrollTo'); +window.Dropzone = require('dropzone'); +require('mousetrap'); +require('mousetrap/plugins/pause/mousetrap-pause'); // // ### Events diff --git a/app/helpers/javascript_helper.rb b/app/helpers/javascript_helper.rb index 0e456214d37..d9c8c70076b 100644 --- a/app/helpers/javascript_helper.rb +++ b/app/helpers/javascript_helper.rb @@ -2,4 +2,7 @@ module JavascriptHelper def page_specific_javascript_tag(js) javascript_include_tag asset_path(js), { "data-turbolinks-track" => true } end + def page_specific_javascript_bundle_tag(js) + javascript_include_tag *webpack_asset_paths(js), { "data-turbolinks-track" => true } + end end diff --git a/app/views/profiles/_head.html.haml b/app/views/profiles/_head.html.haml index 943ebdaeffe..1df04ea614e 100644 --- a/app/views/profiles/_head.html.haml +++ b/app/views/profiles/_head.html.haml @@ -1,3 +1,3 @@ - content_for :page_specific_javascripts do = page_specific_javascript_tag('lib/cropper.js') - = page_specific_javascript_tag('profile/profile_bundle.js') + = page_specific_javascript_bundle_tag('profile') diff --git a/app/views/projects/blob/edit.html.haml b/app/views/projects/blob/edit.html.haml index a5dcd93f42e..8853801016b 100644 --- a/app/views/projects/blob/edit.html.haml +++ b/app/views/projects/blob/edit.html.haml @@ -2,7 +2,7 @@ - page_title "Edit", @blob.path, @ref - content_for :page_specific_javascripts do = page_specific_javascript_tag('lib/ace.js') - = page_specific_javascript_tag('blob_edit/blob_edit_bundle.js') + = page_specific_javascript_bundle_tag('blob_edit') = render "projects/commits/head" %div{ class: container_class } diff --git a/app/views/projects/blob/new.html.haml b/app/views/projects/blob/new.html.haml index b6ed9518c48..e0ce8cc9601 100644 --- a/app/views/projects/blob/new.html.haml +++ b/app/views/projects/blob/new.html.haml @@ -1,7 +1,7 @@ - page_title "New File", @path.presence, @ref - content_for :page_specific_javascripts do = page_specific_javascript_tag('lib/ace.js') - = page_specific_javascript_tag('blob_edit/blob_edit_bundle.js') + = page_specific_javascript_bundle_tag('blob_edit') %h3.page-title New File diff --git a/app/views/projects/boards/_show.html.haml b/app/views/projects/boards/_show.html.haml index 356bd50f7f3..2d1f377a6dd 100644 --- a/app/views/projects/boards/_show.html.haml +++ b/app/views/projects/boards/_show.html.haml @@ -3,8 +3,8 @@ - page_title "Boards" - content_for :page_specific_javascripts do - = page_specific_javascript_tag('boards/boards_bundle.js') - = page_specific_javascript_tag('boards/test_utils/simulate_drag.js') if Rails.env.test? + = page_specific_javascript_bundle_tag('boards') + = page_specific_javascript_bundle_tag('boards_test') if Rails.env.test? %script#js-board-template{ type: "text/x-template" }= render "projects/boards/components/board" %script#js-board-list-template{ type: "text/x-template" }= render "projects/boards/components/board_list" diff --git a/app/views/projects/cycle_analytics/show.html.haml b/app/views/projects/cycle_analytics/show.html.haml index 479ce44f378..5405ff16bea 100644 --- a/app/views/projects/cycle_analytics/show.html.haml +++ b/app/views/projects/cycle_analytics/show.html.haml @@ -1,7 +1,7 @@ - @no_container = true - page_title "Cycle Analytics" - content_for :page_specific_javascripts do - = page_specific_javascript_tag("cycle_analytics/cycle_analytics_bundle.js") + = page_specific_javascript_bundle_tag('cycle_analytics') = render "projects/pipelines/head" diff --git a/app/views/projects/environments/index.html.haml b/app/views/projects/environments/index.html.haml index 8c728eb0f6a..1f27d41ddd9 100644 --- a/app/views/projects/environments/index.html.haml +++ b/app/views/projects/environments/index.html.haml @@ -3,7 +3,7 @@ = render "projects/pipelines/head" - content_for :page_specific_javascripts do - = page_specific_javascript_tag("environments/environments_bundle.js") + = page_specific_javascript_bundle_tag("environments") #environments-list-view{ data: { environments_data: environments_list_data, "can-create-deployment" => can?(current_user, :create_deployment, @project).to_s, diff --git a/app/views/projects/graphs/_head.html.haml b/app/views/projects/graphs/_head.html.haml index 1a62a6a809c..67018aaa2ac 100644 --- a/app/views/projects/graphs/_head.html.haml +++ b/app/views/projects/graphs/_head.html.haml @@ -5,8 +5,8 @@ %ul{ class: (container_class) } - content_for :page_specific_javascripts do - = page_specific_javascript_tag('lib/chart.js') - = page_specific_javascript_tag('graphs/graphs_bundle.js') + = page_specific_javascript_bundle_tag('lib_chart') + = page_specific_javascript_bundle_tag('graphs') = nav_link(action: :show) do = link_to 'Contributors', namespace_project_graph_path = nav_link(action: :commits) do diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index 1f63803c24e..97618984bb4 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -3,7 +3,7 @@ - page_description @merge_request.description - page_card_attributes @merge_request.card_attributes - content_for :page_specific_javascripts do - = page_specific_javascript_tag('diff_notes/diff_notes_bundle.js') + = page_specific_javascript_bundle_tag('diff_notes') .merge-request{ 'data-url' => merge_request_path(@merge_request) } = render "projects/merge_requests/show/mr_title" diff --git a/app/views/projects/merge_requests/conflicts.html.haml b/app/views/projects/merge_requests/conflicts.html.haml index b8b87dcdcaf..9242a84f150 100644 --- a/app/views/projects/merge_requests/conflicts.html.haml +++ b/app/views/projects/merge_requests/conflicts.html.haml @@ -1,6 +1,6 @@ - page_title "Merge Conflicts", "#{@merge_request.title} (#{@merge_request.to_reference}", "Merge Requests" - content_for :page_specific_javascripts do - = page_specific_javascript_tag('merge_conflicts/merge_conflicts_bundle.js') + = page_specific_javascript_bundle_tag('merge_conflicts') = page_specific_javascript_tag('lib/ace.js') = render "projects/merge_requests/show/mr_title" diff --git a/app/views/projects/merge_requests/widget/open/_accept.html.haml b/app/views/projects/merge_requests/widget/open/_accept.html.haml index 7809e9c8c72..487943f1167 100644 --- a/app/views/projects/merge_requests/widget/open/_accept.html.haml +++ b/app/views/projects/merge_requests/widget/open/_accept.html.haml @@ -1,5 +1,5 @@ - content_for :page_specific_javascripts do - = page_specific_javascript_tag('merge_request_widget/ci_bundle.js') + = page_specific_javascript_bundle_tag('merge_request_widget') - status_class = @pipeline ? " ci-#{@pipeline.status}" : nil diff --git a/app/views/projects/merge_requests/widget/open/_check.html.haml b/app/views/projects/merge_requests/widget/open/_check.html.haml index 50086767446..909dc52fc06 100644 --- a/app/views/projects/merge_requests/widget/open/_check.html.haml +++ b/app/views/projects/merge_requests/widget/open/_check.html.haml @@ -1,5 +1,5 @@ - content_for :page_specific_javascripts do - = page_specific_javascript_tag('merge_request_widget/ci_bundle.js') + = page_specific_javascript_bundle_tag('merge_request_widget') %strong = icon("spinner spin") diff --git a/app/views/projects/network/show.html.haml b/app/views/projects/network/show.html.haml index d8951e69242..b88eef65cef 100644 --- a/app/views/projects/network/show.html.haml +++ b/app/views/projects/network/show.html.haml @@ -1,7 +1,7 @@ - page_title "Network", @ref - content_for :page_specific_javascripts do = page_specific_javascript_tag('lib/raphael.js') - = page_specific_javascript_tag('network/network_bundle.js') + = page_specific_javascript_bundle_tag('network') = render "projects/commits/head" = render "head" %div{ class: container_class } diff --git a/app/views/projects/protected_branches/index.html.haml b/app/views/projects/protected_branches/index.html.haml index 42e9bdbd30e..b3b419bd92d 100644 --- a/app/views/projects/protected_branches/index.html.haml +++ b/app/views/projects/protected_branches/index.html.haml @@ -1,6 +1,6 @@ - page_title "Protected branches" - content_for :page_specific_javascripts do - = page_specific_javascript_tag('protected_branches/protected_branches_bundle.js') + = page_specific_javascript_bundle_tag('protected_branches') .row.prepend-top-default.append-bottom-default .col-lg-3 diff --git a/app/views/shared/snippets/_form.html.haml b/app/views/shared/snippets/_form.html.haml index 0c788032020..b5362a7d5d5 100644 --- a/app/views/shared/snippets/_form.html.haml +++ b/app/views/shared/snippets/_form.html.haml @@ -1,6 +1,6 @@ - content_for :page_specific_javascripts do = page_specific_javascript_tag('lib/ace.js') - = page_specific_javascript_tag('snippet/snippet_bundle.js') + = page_specific_javascript_bundle_tag('snippet') .snippet-form-holder = form_for @snippet, url: url, html: { class: "form-horizontal snippet-form js-requires-input" } do |f| @@ -34,4 +34,3 @@ = link_to "Cancel", namespace_project_snippets_path(@project.namespace, @project), class: "btn btn-cancel" - else = link_to "Cancel", snippets_path(@project), class: "btn btn-cancel" - diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index fb25eed4f37..6f43d083e4a 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -1,8 +1,8 @@ - page_title @user.name - page_description @user.bio - content_for :page_specific_javascripts do - = page_specific_javascript_tag('lib/d3.js') - = page_specific_javascript_tag('users/users_bundle.js') + = page_specific_javascript_bundle_tag('lib_d3') + = page_specific_javascript_bundle_tag('users') - header_title @user.name, user_path(@user) - @no_container = true diff --git a/config/application.rb b/config/application.rb index 02839dba1ed..7607c7a61b2 100644 --- a/config/application.rb +++ b/config/application.rb @@ -96,23 +96,9 @@ module Gitlab config.assets.precompile << "katex.css" config.assets.precompile << "katex.js" config.assets.precompile << "xterm/xterm.css" - config.assets.precompile << "graphs/graphs_bundle.js" - config.assets.precompile << "users/users_bundle.js" - config.assets.precompile << "network/network_bundle.js" - config.assets.precompile << "profile/profile_bundle.js" - config.assets.precompile << "protected_branches/protected_branches_bundle.js" - config.assets.precompile << "diff_notes/diff_notes_bundle.js" - config.assets.precompile << "merge_request_widget/ci_bundle.js" - config.assets.precompile << "boards/boards_bundle.js" - config.assets.precompile << "cycle_analytics/cycle_analytics_bundle.js" - config.assets.precompile << "merge_conflicts/merge_conflicts_bundle.js" - config.assets.precompile << "boards/test_utils/simulate_drag.js" - config.assets.precompile << "environments/environments_bundle.js" - config.assets.precompile << "blob_edit/blob_edit_bundle.js" - config.assets.precompile << "snippet/snippet_bundle.js" - config.assets.precompile << "terminal/terminal_bundle.js" - config.assets.precompile << "lib/utils/*.js" - config.assets.precompile << "lib/*.js" + config.assets.precompile << "lib/ace.js" + config.assets.precompile << "lib/cropper.js" + config.assets.precompile << "lib/raphael.js" config.assets.precompile << "u2f.js" config.assets.precompile << "vendor/assets/fonts/*" diff --git a/config/webpack.config.js b/config/webpack.config.js index d45638fbcbd..2fcf2e11450 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -12,9 +12,26 @@ var ROOT_PATH = path.resolve(__dirname, '..'); var DEV_SERVER_PORT = 3808; var config = { - context: ROOT_PATH, + context: path.join(ROOT_PATH, 'app/assets/javascripts'), entry: { - application: './app/assets/javascripts/webpack/application.js' + application: './application.js', + blob_edit: './blob_edit/blob_edit_bundle.js', + boards: './boards/boards_bundle.js', + boards_test: './boards/test_utils/simulate_drag.js', + cycle_analytics: './cycle_analytics/cycle_analytics_bundle.js', + diff_notes: './diff_notes/diff_notes_bundle.js', + environments: './environments/environments_bundle.js', + graphs: './graphs/graphs_bundle.js', + merge_conflicts: './merge_conflicts/merge_conflicts_bundle.js', + merge_request_widget: './merge_request_widget/ci_bundle.js', + network: './network/network_bundle.js', + profile: './profile/profile_bundle.js', + protected_branches: './protected_branches/protected_branches_bundle.js', + snippet: './snippet/snippet_bundle.js', + terminal: './terminal/terminal_bundle.js', + users: './users/users_bundle.js', + lib_chart: './lib/chart.js', + lib_d3: './lib/d3.js' }, output: { diff --git a/package.json b/package.json index 7ef811ae478..966c3daab40 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ "babel-core": "^5.8.38", "babel-loader": "^5.4.2", "bootstrap-sass": "3.3.6", + "d3": "3.5.11", "dropzone": "4.2.0", "exports-loader": "^0.6.3", "imports-loader": "^0.6.5", diff --git a/vendor/assets/javascripts/es6-promise.auto.js b/vendor/assets/javascripts/es6-promise.auto.js index 19e6c13a655..b8887115a37 100644 --- a/vendor/assets/javascripts/es6-promise.auto.js +++ b/vendor/assets/javascripts/es6-promise.auto.js @@ -1154,6 +1154,3 @@ Promise.Promise = Promise; return Promise; }))); - -ES6Promise.polyfill(); -//# sourceMappingURL=es6-promise.auto.map diff --git a/vendor/assets/javascripts/xterm/fit.js b/vendor/assets/javascripts/xterm/fit.js index 7e24fd9b36e..55438452cad 100644 --- a/vendor/assets/javascripts/xterm/fit.js +++ b/vendor/assets/javascripts/xterm/fit.js @@ -16,12 +16,12 @@ /* * CommonJS environment */ - module.exports = fit(require('../../xterm')); + module.exports = fit(require('./xterm')); } else if (typeof define == 'function') { /* * Require.js is available */ - define(['../../xterm'], fit); + define(['./xterm'], fit); } else { /* * Plain browser environment -- cgit v1.2.1 From 24b48a37131546f5927805e3be7d88e07dbfa9af Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 4 Nov 2016 18:12:00 -0500 Subject: disable "use strict" in babel config as it was broken in sprockets --- config/webpack.config.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/config/webpack.config.js b/config/webpack.config.js index 2fcf2e11450..da2a19838e4 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -47,7 +47,13 @@ var config = { { test: /\.es6$/, exclude: /node_modules/, - loader: 'babel-loader' + loader: 'babel-loader', + query: { + // "use strict" was broken in sprockets-es6 due to sprockets concatination method. + // many es5 strict errors which were never caught ended up in our es6 assets as a result. + // this hack is necessary until they can be fixed. + blacklist: ["useStrict"] + } }, { test: /\.(js|es6)$/, -- cgit v1.2.1 From 720650d2b0a978700edfd759c0928598f2b0ae0b Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 3 Nov 2016 19:11:38 -0500 Subject: precompile webpack assets when testing --- .gitlab-ci.yml | 5 +++++ config/application.rb | 1 + config/environments/development.rb | 3 +++ 3 files changed, 9 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index e0e780e1e6b..2ec9dfd2165 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,6 +24,9 @@ before_script: - '[ "$USE_BUNDLE_INSTALL" != "true" ] || retry bundle install --without postgres production --jobs $(nproc) $FLAGS' - retry gem install knapsack - '[ "$SETUP_DB" != "true" ] || bundle exec rake db:drop db:create db:schema:load db:migrate add_limits_mysql' + - curl --silent --location https://deb.nodesource.com/setup_6.x | bash - + - apt-get install --assume-yes nodejs + - npm install stages: - prepare @@ -61,6 +64,7 @@ stages: <<: *dedicated-runner <<: *use-db script: + - bundle exec rake webpack:compile - JOB_NAME=( $CI_BUILD_NAME ) - export CI_NODE_INDEX=${JOB_NAME[1]} - export CI_NODE_TOTAL=${JOB_NAME[2]} @@ -79,6 +83,7 @@ stages: <<: *dedicated-runner <<: *use-db script: + - bundle exec rake webpack:compile - JOB_NAME=( $CI_BUILD_NAME ) - export CI_NODE_INDEX=${JOB_NAME[1]} - export CI_NODE_TOTAL=${JOB_NAME[2]} diff --git a/config/application.rb b/config/application.rb index 7607c7a61b2..4efe73c7798 100644 --- a/config/application.rb +++ b/config/application.rb @@ -84,6 +84,7 @@ module Gitlab config.webpack.config_file = "config/webpack.config.js" config.webpack.output_dir = "public/assets/webpack" config.webpack.public_path = "assets/webpack" + config.webpack.dev_server.enabled = false # Enable the asset pipeline config.assets.enabled = true diff --git a/config/environments/development.rb b/config/environments/development.rb index 45a8c1add3e..168c434f261 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -22,6 +22,9 @@ Rails.application.configure do # Only use best-standards-support built into browsers config.action_dispatch.best_standards_support = :builtin + # Enable webpack dev server + config.webpack.dev_server.enabled = true + # Do not compress assets config.assets.compress = false -- cgit v1.2.1 From a2c1f2e0ea5ce1030ecfe4fa821b9268773baac5 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Mon, 21 Nov 2016 10:56:25 -0600 Subject: exempt node_modules from rubocop linting --- .rubocop.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.rubocop.yml b/.rubocop.yml index 80eb4a5c19e..3735a718c37 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -17,6 +17,7 @@ AllCops: # Exclude some GitLab files Exclude: - 'vendor/**/*' + - 'node_modules/**/*' - 'db/*' - 'db/fixtures/**/*' - 'tmp/**/*' -- cgit v1.2.1 From 11e9f32d1be94d9216416c730c0b72effed1aa73 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Mon, 21 Nov 2016 15:40:58 -0600 Subject: fix rubocop complaint about ambiguous splat operator --- app/helpers/javascript_helper.rb | 2 +- app/views/layouts/_head.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/helpers/javascript_helper.rb b/app/helpers/javascript_helper.rb index d9c8c70076b..64284910d4d 100644 --- a/app/helpers/javascript_helper.rb +++ b/app/helpers/javascript_helper.rb @@ -3,6 +3,6 @@ module JavascriptHelper javascript_include_tag asset_path(js), { "data-turbolinks-track" => true } end def page_specific_javascript_bundle_tag(js) - javascript_include_tag *webpack_asset_paths(js), { "data-turbolinks-track" => true } + javascript_include_tag(*webpack_asset_paths(js), { "data-turbolinks-track" => true }) end end diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index d260e2133f2..0d9f838e804 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -28,7 +28,7 @@ = stylesheet_link_tag "application", media: "all" = stylesheet_link_tag "print", media: "print" - = javascript_include_tag *webpack_asset_paths("application") + = javascript_include_tag(*webpack_asset_paths("application")) - if content_for?(:page_specific_javascripts) = yield :page_specific_javascripts -- cgit v1.2.1 From a569aa295a9e733c1aa975d69a95a71a677a43bb Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Mon, 21 Nov 2016 16:32:03 -0600 Subject: use karma for javascript testing --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 966c3daab40..97a98ad7cfc 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "eslint-plugin-filenames": "^1.1.0", "eslint-plugin-import": "^2.2.0", "eslint-plugin-jasmine": "^2.1.0", - "istanbul": "^0.4.5" + "istanbul": "^0.4.5", + "karma": "^1.3.0" } } -- cgit v1.2.1 From 3eb8569778ce2559eedab706f6f901238e39b355 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Sat, 10 Dec 2016 16:06:41 +0000 Subject: Correct merge conflicts Fixed eslint failures --- app/assets/javascripts/application.js | 1 - .../javascripts/lib/utils/datetime_utility.js | 4 +- vendor/assets/javascripts/date.format.js | 207 +++++++++++---------- 3 files changed, 109 insertions(+), 103 deletions(-) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 830d706f02d..6a6f827e580 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -47,7 +47,6 @@ require('./shortcuts_dashboard_navigation'); require('./shortcuts_issuable'); require('./shortcuts_network'); require('vendor/jquery.nicescroll'); -require('vendor/date.format'); requireAll(require.context('./behaviors', false, /^\.\/.*\.(js|es6)$/)); requireAll(require.context('./blob', false, /^\.\/.*\.(js|es6)$/)); requireAll(require.context('./templates', false, /^\.\/.*\.(js|es6)$/)); diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js index b6c1fd4c4f8..f859fc9c0da 100644 --- a/app/assets/javascripts/lib/utils/datetime_utility.js +++ b/app/assets/javascripts/lib/utils/datetime_utility.js @@ -3,7 +3,7 @@ /* global dateFormat */ window.timeago = require('vendor/timeago'); -require('vendor/date.format'); +window.dateFormat = require('vendor/date.format'); (function() { (function(w) { @@ -17,7 +17,7 @@ require('vendor/date.format'); w.gl.utils.days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; w.gl.utils.formatDate = function(datetime) { - return (new Date(datetime)).format('mmm d, yyyy h:MMtt Z'); + return dateFormat(datetime, 'mmm d, yyyy h:MMtt Z'); }; w.gl.utils.getDayName = function(date) { diff --git a/vendor/assets/javascripts/date.format.js b/vendor/assets/javascripts/date.format.js index f5dc4abcd80..2c9b4825443 100644 --- a/vendor/assets/javascripts/date.format.js +++ b/vendor/assets/javascripts/date.format.js @@ -11,115 +11,122 @@ * The date defaults to the current date/time. * The mask defaults to dateFormat.masks.default. */ + (function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : + typeof define === 'function' && define.amd ? define(factory) : + (global.dateFormat = factory()); + }(this, (function () { 'use strict'; + var dateFormat = function () { + var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g, + timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g, + timezoneClip = /[^-+\dA-Z]/g, + pad = function (val, len) { + val = String(val); + len = len || 2; + while (val.length < len) val = "0" + val; + return val; + }; -var dateFormat = function () { - var token = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])\1?|[LloSZ]|"[^"]*"|'[^']*'/g, - timezone = /\b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]\d{4})?)\b/g, - timezoneClip = /[^-+\dA-Z]/g, - pad = function (val, len) { - val = String(val); - len = len || 2; - while (val.length < len) val = "0" + val; - return val; - }; + // Regexes and supporting functions are cached through closure + return function (date, mask, utc) { + var dF = dateFormat; - // Regexes and supporting functions are cached through closure - return function (date, mask, utc) { - var dF = dateFormat; + // You can't provide utc if you skip other args (use the "UTC:" mask prefix) + if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) { + mask = date; + date = undefined; + } - // You can't provide utc if you skip other args (use the "UTC:" mask prefix) - if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !/\d/.test(date)) { - mask = date; - date = undefined; - } + // Passing date through Date applies Date.parse, if necessary + date = date ? new Date(date) : new Date; + if (isNaN(date)) throw SyntaxError("invalid date"); - // Passing date through Date applies Date.parse, if necessary - date = date ? new Date(date) : new Date; - if (isNaN(date)) throw SyntaxError("invalid date"); + mask = String(dF.masks[mask] || mask || dF.masks["default"]); - mask = String(dF.masks[mask] || mask || dF.masks["default"]); + // Allow setting the utc argument via the mask + if (mask.slice(0, 4) == "UTC:") { + mask = mask.slice(4); + utc = true; + } - // Allow setting the utc argument via the mask - if (mask.slice(0, 4) == "UTC:") { - mask = mask.slice(4); - utc = true; - } + var _ = utc ? "getUTC" : "get", + d = date[_ + "Date"](), + D = date[_ + "Day"](), + m = date[_ + "Month"](), + y = date[_ + "FullYear"](), + H = date[_ + "Hours"](), + M = date[_ + "Minutes"](), + s = date[_ + "Seconds"](), + L = date[_ + "Milliseconds"](), + o = utc ? 0 : date.getTimezoneOffset(), + flags = { + d: d, + dd: pad(d), + ddd: dF.i18n.dayNames[D], + dddd: dF.i18n.dayNames[D + 7], + m: m + 1, + mm: pad(m + 1), + mmm: dF.i18n.monthNames[m], + mmmm: dF.i18n.monthNames[m + 12], + yy: String(y).slice(2), + yyyy: y, + h: H % 12 || 12, + hh: pad(H % 12 || 12), + H: H, + HH: pad(H), + M: M, + MM: pad(M), + s: s, + ss: pad(s), + l: pad(L, 3), + L: pad(L > 99 ? Math.round(L / 10) : L), + t: H < 12 ? "a" : "p", + tt: H < 12 ? "am" : "pm", + T: H < 12 ? "A" : "P", + TT: H < 12 ? "AM" : "PM", + Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""), + o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4), + S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10] + }; - var _ = utc ? "getUTC" : "get", - d = date[_ + "Date"](), - D = date[_ + "Day"](), - m = date[_ + "Month"](), - y = date[_ + "FullYear"](), - H = date[_ + "Hours"](), - M = date[_ + "Minutes"](), - s = date[_ + "Seconds"](), - L = date[_ + "Milliseconds"](), - o = utc ? 0 : date.getTimezoneOffset(), - flags = { - d: d, - dd: pad(d), - ddd: dF.i18n.dayNames[D], - dddd: dF.i18n.dayNames[D + 7], - m: m + 1, - mm: pad(m + 1), - mmm: dF.i18n.monthNames[m], - mmmm: dF.i18n.monthNames[m + 12], - yy: String(y).slice(2), - yyyy: y, - h: H % 12 || 12, - hh: pad(H % 12 || 12), - H: H, - HH: pad(H), - M: M, - MM: pad(M), - s: s, - ss: pad(s), - l: pad(L, 3), - L: pad(L > 99 ? Math.round(L / 10) : L), - t: H < 12 ? "a" : "p", - tt: H < 12 ? "am" : "pm", - T: H < 12 ? "A" : "P", - TT: H < 12 ? "AM" : "PM", - Z: utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""), - o: (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4), - S: ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10] - }; + return mask.replace(token, function ($0) { + return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1); + }); + }; + }(); - return mask.replace(token, function ($0) { - return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1); - }); + // Some common format strings + dateFormat.masks = { + "default": "ddd mmm dd yyyy HH:MM:ss", + shortDate: "m/d/yy", + mediumDate: "mmm d, yyyy", + longDate: "mmmm d, yyyy", + fullDate: "dddd, mmmm d, yyyy", + shortTime: "h:MM TT", + mediumTime: "h:MM:ss TT", + longTime: "h:MM:ss TT Z", + isoDate: "yyyy-mm-dd", + isoTime: "HH:MM:ss", + isoDateTime: "yyyy-mm-dd'T'HH:MM:ss", + isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'" }; -}(); -// Some common format strings -dateFormat.masks = { - "default": "ddd mmm dd yyyy HH:MM:ss", - shortDate: "m/d/yy", - mediumDate: "mmm d, yyyy", - longDate: "mmmm d, yyyy", - fullDate: "dddd, mmmm d, yyyy", - shortTime: "h:MM TT", - mediumTime: "h:MM:ss TT", - longTime: "h:MM:ss TT Z", - isoDate: "yyyy-mm-dd", - isoTime: "HH:MM:ss", - isoDateTime: "yyyy-mm-dd'T'HH:MM:ss", - isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'" -}; + // Internationalization strings + dateFormat.i18n = { + dayNames: [ + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", + "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" + ], + monthNames: [ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", + "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" + ] + }; -// Internationalization strings -dateFormat.i18n = { - dayNames: [ - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", - "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" - ], - monthNames: [ - "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec", - "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" - ] -}; + // For convenience... + Date.prototype.format = function (mask, utc) { + return dateFormat(this, mask, utc); + }; -// For convenience... -Date.prototype.format = function (mask, utc) { - return dateFormat(this, mask, utc); -}; + return dateFormat; +}))); -- cgit v1.2.1 From 7c47cc94c5d7425583db3610c85cb150df601a91 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Thu, 29 Dec 2016 15:42:48 -0600 Subject: Swapped out teaspoon for karma --- .gitlab-ci.yml | 12 ++---- config/karma.config.js | 27 +++++++++++++ config/webpack.config.js | 7 +++- lib/tasks/gitlab/test.rake | 2 +- lib/tasks/test.rake | 2 +- package.json | 10 ++++- spec/javascripts/abuse_reports_spec.js.es6 | 5 ++- spec/javascripts/activities_spec.js.es6 | 9 +++-- spec/javascripts/awards_handler_spec.js | 8 ++-- spec/javascripts/behaviors/autosize_spec.js | 2 +- spec/javascripts/behaviors/quick_submit_spec.js | 3 +- spec/javascripts/behaviors/requires_input_spec.js | 3 +- spec/javascripts/boards/boards_store_spec.js.es6 | 25 ++++++------ spec/javascripts/boards/issue_spec.js.es6 | 25 ++++++------ spec/javascripts/boards/list_spec.js.es6 | 25 ++++++------ spec/javascripts/bootstrap_linked_tabs_spec.js.es6 | 3 +- spec/javascripts/build_spec.js.es6 | 11 +++--- spec/javascripts/dashboard_spec.js.es6 | 8 ++-- spec/javascripts/datetime_utility_spec.js.es6 | 2 +- spec/javascripts/diff_comments_store_spec.js.es6 | 7 ++-- .../environments/environment_actions_spec.js.es6 | 5 ++- .../environment_external_url_spec.js.es6 | 5 ++- .../environments/environment_item_spec.js.es6 | 7 ++-- .../environments/environment_rollback_spec.js.es6 | 6 ++- .../environments/environment_stop_spec.js.es6 | 6 ++- .../environments/environments_store_spec.js.es6 | 6 +-- spec/javascripts/environments/mock_data.js.es6 | 1 + spec/javascripts/extensions/array_spec.js.es6 | 2 +- spec/javascripts/extensions/element_spec.js.es6 | 2 +- spec/javascripts/extensions/jquery_spec.js | 2 +- spec/javascripts/extensions/object_spec.js.es6 | 2 +- spec/javascripts/gl_dropdown_spec.js.es6 | 10 ++--- spec/javascripts/gl_field_errors_spec.js.es6 | 4 +- .../graphs/stat_graph_contributors_graph_spec.js | 2 +- .../graphs/stat_graph_contributors_util_spec.js | 2 +- spec/javascripts/graphs/stat_graph_spec.js | 2 +- spec/javascripts/header_spec.js | 6 +-- spec/javascripts/issuable_spec.js.es6 | 4 +- spec/javascripts/issue_spec.js | 5 ++- spec/javascripts/labels_issue_sidebar_spec.js.es6 | 21 +++++----- .../javascripts/lib/utils/common_utils_spec.js.es6 | 2 +- spec/javascripts/line_highlighter_spec.js | 3 +- spec/javascripts/merge_request_spec.js | 3 +- spec/javascripts/merge_request_tabs_spec.js | 9 +++-- spec/javascripts/merge_request_widget_spec.js | 4 +- .../mini_pipeline_graph_dropdown_spec.js.es6 | 4 +- spec/javascripts/new_branch_spec.js | 5 ++- spec/javascripts/notes_spec.js | 9 +++-- spec/javascripts/pipelines_spec.js.es6 | 2 +- spec/javascripts/pretty_time_spec.js.es6 | 2 +- spec/javascripts/project_title_spec.js | 16 ++++---- spec/javascripts/right_sidebar_spec.js | 9 ++--- spec/javascripts/search_autocomplete_spec.js | 17 ++++---- spec/javascripts/shortcuts_issuable_spec.js | 3 +- spec/javascripts/signin_tabs_memoizer_spec.js.es6 | 3 +- spec/javascripts/smart_interval_spec.js.es6 | 4 +- spec/javascripts/spec_helper.js | 46 ++-------------------- spec/javascripts/subbable_resource_spec.js.es6 | 7 ++-- spec/javascripts/syntax_highlight_spec.js | 3 +- spec/javascripts/u2f/authenticate_spec.js | 11 +++--- spec/javascripts/u2f/register_spec.js | 11 +++--- .../vue_common_components/commit_spec.js.es6 | 3 +- spec/javascripts/zen_mode_spec.js | 3 +- vendor/assets/javascripts/jquery.turbolinks.js | 21 ++++++++-- 64 files changed, 260 insertions(+), 236 deletions(-) create mode 100644 config/karma.config.js diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2ec9dfd2165..6e727333929 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -291,7 +291,7 @@ rake db:seed_fu: paths: - log/development.log -teaspoon: +karma: cache: paths: - vendor/ruby @@ -300,9 +300,9 @@ teaspoon: <<: *use-db <<: *dedicated-runner script: - - npm install - npm link istanbul - - rake teaspoon + - rake webpack:compile + - npm run karma-start artifacts: name: coverage-javascript expire_in: 31d @@ -381,8 +381,6 @@ lint:javascript: - node_modules/ stage: test image: "node:7.1" - before_script: - - npm install script: - npm --silent run eslint @@ -393,8 +391,6 @@ lint:javascript:report: - node_modules/ stage: post-test image: "node:7.1" - before_script: - - npm install script: - find app/ spec/ -name '*.js' -or -name '*.js.es6' -exec sed --in-place 's|/\* eslint-disable .*\*/||' {} \; # run report over all files - npm --silent run eslint-report || true # ignore exit code @@ -444,7 +440,7 @@ pages: <<: *dedicated-runner dependencies: - coverage - - teaspoon + - karma - lint:javascript:report script: - mv public/ .public/ diff --git a/config/karma.config.js b/config/karma.config.js new file mode 100644 index 00000000000..478ef082547 --- /dev/null +++ b/config/karma.config.js @@ -0,0 +1,27 @@ +var path = require('path'); +var webpackConfig = require('./webpack.config.js'); +var ROOT_PATH = path.resolve(__dirname, '..'); + +// Karma configuration +module.exports = function(config) { + config.set({ + basePath: ROOT_PATH, + frameworks: ['jquery-2.1.0', 'jasmine'], + files: [ + 'spec/javascripts/*_spec.js', + 'spec/javascripts/*_spec.js.es6', + { pattern: 'spec/javascripts/fixtures/**/*.html', included: false, served: true }, + { pattern: 'spec/javascripts/fixtures/**/*.json', included: false, served: true }, + ], + preprocessors: { + 'spec/javascripts/*_spec.js': ['webpack'], + 'spec/javascripts/*_spec.js.es6': ['webpack'], + 'app/assets/javascripts/**/*.js': ['webpack'], + 'app/assets/javascripts/**/*.js.es6': ['webpack'], + }, + + webpack: webpackConfig, + + webpackMiddleware: { stats: 'errors-only' }, + }); +}; diff --git a/config/webpack.config.js b/config/webpack.config.js index da2a19838e4..5cba995888a 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -58,7 +58,7 @@ var config = { { test: /\.(js|es6)$/, loader: 'imports-loader', - query: 'this=>window' + query: '$=jquery,jQuery=jquery,this=>window' }, { test: /\.json$/, @@ -87,7 +87,10 @@ var config = { 'vendor': path.join(ROOT_PATH, 'vendor/assets/javascripts'), 'vue$': 'vue/dist/vue.js', 'vue-resource$': 'vue-resource/dist/vue-resource.js' - } + }, + root: [ + path.join(ROOT_PATH, 'app/assets/javascripts'), + ], } } diff --git a/lib/tasks/gitlab/test.rake b/lib/tasks/gitlab/test.rake index 4d4e746503a..ec7aec1621c 100644 --- a/lib/tasks/gitlab/test.rake +++ b/lib/tasks/gitlab/test.rake @@ -6,7 +6,7 @@ namespace :gitlab do %W(rake rubocop), %W(rake spinach), %W(rake spec), - %W(rake teaspoon) + %W(npm run karma-start) ] cmds.each do |cmd| diff --git a/lib/tasks/test.rake b/lib/tasks/test.rake index d3dcbd2c29b..83f53e5454b 100644 --- a/lib/tasks/test.rake +++ b/lib/tasks/test.rake @@ -7,5 +7,5 @@ end unless Rails.env.production? desc "GitLab | Run all tests on CI with simplecov" - task test_ci: [:rubocop, :brakeman, :teaspoon, :spinach, :spec] + task test_ci: [:rubocop, :brakeman, :'karma-start', :spinach, :spec] end diff --git a/package.json b/package.json index 97a98ad7cfc..ec012e9c3bd 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,8 @@ "dev-server": "node_modules/.bin/webpack-dev-server --config config/webpack.config.js", "eslint": "eslint --max-warnings 0 --ext .js,.js.es6 .", "eslint-fix": "npm run eslint -- --fix", - "eslint-report": "npm run eslint -- --format html --output-file ./eslint-report.html" + "eslint-report": "npm run eslint -- --format html --output-file ./eslint-report.html", + "karma-start": "karma start config/karma.config.js" }, "dependencies": { "babel": "^5.8.38", @@ -35,6 +36,11 @@ "eslint-plugin-import": "^2.2.0", "eslint-plugin-jasmine": "^2.1.0", "istanbul": "^0.4.5", - "karma": "^1.3.0" + "jasmine-core": "^2.5.2", + "jasmine-jquery": "^2.1.1", + "karma": "^1.3.0", + "karma-jasmine": "^1.1.0", + "karma-jquery": "^0.1.0", + "karma-webpack": "^1.8.0" } } diff --git a/spec/javascripts/abuse_reports_spec.js.es6 b/spec/javascripts/abuse_reports_spec.js.es6 index cf19aa05031..dadee40f9b9 100644 --- a/spec/javascripts/abuse_reports_spec.js.es6 +++ b/spec/javascripts/abuse_reports_spec.js.es6 @@ -1,5 +1,6 @@ -/*= require lib/utils/text_utility */ -/*= require abuse_reports */ +require('./spec_helper'); +require('lib/utils/text_utility'); +require('abuse_reports'); ((global) => { describe('Abuse Reports', () => { diff --git a/spec/javascripts/activities_spec.js.es6 b/spec/javascripts/activities_spec.js.es6 index b3617a45bd4..61fabd37170 100644 --- a/spec/javascripts/activities_spec.js.es6 +++ b/spec/javascripts/activities_spec.js.es6 @@ -1,9 +1,10 @@ /* eslint-disable no-unused-expressions, comma-spacing, prefer-const, no-prototype-builtins, semi, no-new, keyword-spacing, no-plusplus, no-shadow, max-len */ -/*= require js.cookie.js */ -/*= require jquery.endless-scroll.js */ -/*= require pager */ -/*= require activities */ +require('./spec_helper'); +require('vendor/js.cookie.js'); +require('vendor/jquery.endless-scroll.js'); +require('pager'); +require('activities'); (() => { window.gon || (window.gon = {}); diff --git a/spec/javascripts/awards_handler_spec.js b/spec/javascripts/awards_handler_spec.js index faba2837d41..88757e5c236 100644 --- a/spec/javascripts/awards_handler_spec.js +++ b/spec/javascripts/awards_handler_spec.js @@ -1,10 +1,10 @@ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-unused-expressions, comma-dangle, new-parens, no-unused-vars, quotes, jasmine/no-spec-dupes, prefer-template, padded-blocks, max-len */ /* global AwardsHandler */ -/*= require awards_handler */ -/*= require jquery */ -/*= require js.cookie */ -/*= require ./fixtures/emoji_menu */ +require('./spec_helper'); +require('awards_handler'); +require('vendor/js.cookie'); +require('./fixtures/emoji_menu'); (function() { var awardsHandler, lazyAssert, urlRoot; diff --git a/spec/javascripts/behaviors/autosize_spec.js b/spec/javascripts/behaviors/autosize_spec.js index e77d732a32a..e05793cf2e3 100644 --- a/spec/javascripts/behaviors/autosize_spec.js +++ b/spec/javascripts/behaviors/autosize_spec.js @@ -1,6 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, comma-dangle, no-return-assign, padded-blocks, max-len */ -/*= require behaviors/autosize */ +require('behaviors/autosize'); (function() { describe('Autosize behavior', function() { diff --git a/spec/javascripts/behaviors/quick_submit_spec.js b/spec/javascripts/behaviors/quick_submit_spec.js index 1a1f34cfdc0..4a00b1b2d38 100644 --- a/spec/javascripts/behaviors/quick_submit_spec.js +++ b/spec/javascripts/behaviors/quick_submit_spec.js @@ -1,6 +1,7 @@ /* eslint-disable space-before-function-paren, no-var, no-return-assign, comma-dangle, jasmine/no-spec-dupes, new-cap, padded-blocks, max-len */ -/*= require behaviors/quick_submit */ +require('./spec_helper'); +require('behaviors/quick_submit'); (function() { describe('Quick Submit behavior', function() { diff --git a/spec/javascripts/behaviors/requires_input_spec.js b/spec/javascripts/behaviors/requires_input_spec.js index 1f62591c06d..44d91d41abf 100644 --- a/spec/javascripts/behaviors/requires_input_spec.js +++ b/spec/javascripts/behaviors/requires_input_spec.js @@ -1,6 +1,7 @@ /* eslint-disable space-before-function-paren, no-var, padded-blocks */ -/*= require behaviors/requires_input */ +require('./spec_helper'); +require('behaviors/requires_input'); (function() { describe('requiresInput', function() { diff --git a/spec/javascripts/boards/boards_store_spec.js.es6 b/spec/javascripts/boards/boards_store_spec.js.es6 index b3a1afa28a5..d995380c620 100644 --- a/spec/javascripts/boards/boards_store_spec.js.es6 +++ b/spec/javascripts/boards/boards_store_spec.js.es6 @@ -6,19 +6,18 @@ /* global listObj */ /* global listObjDuplicate */ -//= require jquery -//= require jquery_ujs -//= require js.cookie -//= require vue -//= require vue-resource -//= require lib/utils/url_utility -//= require boards/models/issue -//= require boards/models/label -//= require boards/models/list -//= require boards/models/user -//= require boards/services/board_service -//= require boards/stores/boards_store -//= require ./mock_data +require('jquery_ujs'); +require('js.cookie'); +require('vue'); +require('vue-resource'); +require('lib/utils/url_utility'); +require('boards/models/issue'); +require('boards/models/label'); +require('boards/models/list'); +require('boards/models/user'); +require('boards/services/board_service'); +require('boards/stores/boards_store'); +require('./mock_data'); describe('Store', () => { beforeEach(() => { diff --git a/spec/javascripts/boards/issue_spec.js.es6 b/spec/javascripts/boards/issue_spec.js.es6 index c8a61a0a9b5..2cdbdd725b1 100644 --- a/spec/javascripts/boards/issue_spec.js.es6 +++ b/spec/javascripts/boards/issue_spec.js.es6 @@ -2,19 +2,18 @@ /* global BoardService */ /* global ListIssue */ -//= require jquery -//= require jquery_ujs -//= require js.cookie -//= require vue -//= require vue-resource -//= require lib/utils/url_utility -//= require boards/models/issue -//= require boards/models/label -//= require boards/models/list -//= require boards/models/user -//= require boards/services/board_service -//= require boards/stores/boards_store -//= require ./mock_data +require('jquery_ujs'); +require('js.cookie'); +require('vue'); +require('vue-resource'); +require('lib/utils/url_utility'); +require('boards/models/issue'); +require('boards/models/label'); +require('boards/models/list'); +require('boards/models/user'); +require('boards/services/board_service'); +require('boards/stores/boards_store'); +require('./mock_data'); describe('Issue model', () => { let issue; diff --git a/spec/javascripts/boards/list_spec.js.es6 b/spec/javascripts/boards/list_spec.js.es6 index 7d942ec3d65..dd82f482207 100644 --- a/spec/javascripts/boards/list_spec.js.es6 +++ b/spec/javascripts/boards/list_spec.js.es6 @@ -5,19 +5,18 @@ /* global List */ /* global listObj */ -//= require jquery -//= require jquery_ujs -//= require js.cookie -//= require vue -//= require vue-resource -//= require lib/utils/url_utility -//= require boards/models/issue -//= require boards/models/label -//= require boards/models/list -//= require boards/models/user -//= require boards/services/board_service -//= require boards/stores/boards_store -//= require ./mock_data +require('jquery_ujs'); +require('js.cookie'); +require('vue'); +require('vue-resource'); +require('lib/utils/url_utility'); +require('boards/models/issue'); +require('boards/models/label'); +require('boards/models/list'); +require('boards/models/user'); +require('boards/services/board_service'); +require('boards/stores/boards_store'); +require('./mock_data'); describe('List model', () => { let list; diff --git a/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 b/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 index ea953d0f5a5..b6d223dcb80 100644 --- a/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 +++ b/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 @@ -1,4 +1,5 @@ -//= require lib/utils/bootstrap_linked_tabs +require('./spec_helper'); +require('lib/utils/bootstrap_linked_tabs'); (() => { describe('Linked Tabs', () => { diff --git a/spec/javascripts/build_spec.js.es6 b/spec/javascripts/build_spec.js.es6 index 0c556382980..8b0c797647b 100644 --- a/spec/javascripts/build_spec.js.es6 +++ b/spec/javascripts/build_spec.js.es6 @@ -2,11 +2,12 @@ /* global Build */ /* global Turbolinks */ -//= require lib/utils/datetime_utility -//= require build -//= require breakpoints -//= require jquery.nicescroll -//= require turbolinks +require('./spec_helper'); +require('lib/utils/datetime_utility'); +require('build'); +require('breakpoints'); +require('vendor/jquery.nicescroll'); +require('vendor/turbolinks'); describe('Build', () => { const BUILD_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/builds/1`; diff --git a/spec/javascripts/dashboard_spec.js.es6 b/spec/javascripts/dashboard_spec.js.es6 index 3f6b328348d..4223215c096 100644 --- a/spec/javascripts/dashboard_spec.js.es6 +++ b/spec/javascripts/dashboard_spec.js.es6 @@ -1,9 +1,9 @@ /* eslint-disable no-new, padded-blocks */ -/*= require sidebar */ -/*= require jquery */ -/*= require js.cookie */ -/*= require lib/utils/text_utility */ +require('./spec_helper'); +require('sidebar'); +require('vendor/js.cookie'); +require('lib/utils/text_utility'); ((global) => { describe('Dashboard', () => { diff --git a/spec/javascripts/datetime_utility_spec.js.es6 b/spec/javascripts/datetime_utility_spec.js.es6 index 8ece24555c5..713e7742988 100644 --- a/spec/javascripts/datetime_utility_spec.js.es6 +++ b/spec/javascripts/datetime_utility_spec.js.es6 @@ -1,4 +1,4 @@ -//= require lib/utils/datetime_utility +require('lib/utils/datetime_utility'); (() => { describe('Date time utils', () => { diff --git a/spec/javascripts/diff_comments_store_spec.js.es6 b/spec/javascripts/diff_comments_store_spec.js.es6 index 18805d26ac0..f27ba0f93f7 100644 --- a/spec/javascripts/diff_comments_store_spec.js.es6 +++ b/spec/javascripts/diff_comments_store_spec.js.es6 @@ -1,10 +1,9 @@ /* eslint-disable no-extra-semi, jasmine/no-global-setup, dot-notation, jasmine/no-expect-in-setup-teardown, max-len */ /* global CommentsStore */ -//= require vue -//= require diff_notes/models/discussion -//= require diff_notes/models/note -//= require diff_notes/stores/comments +require('diff_notes/models/discussion'); +require('diff_notes/models/note'); +require('diff_notes/stores/comments'); (() => { function createDiscussion(noteId = 1, resolved = true) { diff --git a/spec/javascripts/environments/environment_actions_spec.js.es6 b/spec/javascripts/environments/environment_actions_spec.js.es6 index 056e4d41e93..34330f7bfd6 100644 --- a/spec/javascripts/environments/environment_actions_spec.js.es6 +++ b/spec/javascripts/environments/environment_actions_spec.js.es6 @@ -1,5 +1,6 @@ -//= require vue -//= require environments/components/environment_actions +require('./spec_helper'); +require('vue'); +require('environments/components/environment_actions'); describe('Actions Component', () => { preloadFixtures('static/environments/element.html.raw'); diff --git a/spec/javascripts/environments/environment_external_url_spec.js.es6 b/spec/javascripts/environments/environment_external_url_spec.js.es6 index 950a5d53fad..71785e7ecf1 100644 --- a/spec/javascripts/environments/environment_external_url_spec.js.es6 +++ b/spec/javascripts/environments/environment_external_url_spec.js.es6 @@ -1,5 +1,6 @@ -//= require vue -//= require environments/components/environment_external_url +require('./spec_helper'); +require('vue'); +require('environments/components/environment_external_url'); describe('External URL Component', () => { preloadFixtures('static/environments/element.html.raw'); diff --git a/spec/javascripts/environments/environment_item_spec.js.es6 b/spec/javascripts/environments/environment_item_spec.js.es6 index c178b9cc1ec..be753498269 100644 --- a/spec/javascripts/environments/environment_item_spec.js.es6 +++ b/spec/javascripts/environments/environment_item_spec.js.es6 @@ -1,6 +1,7 @@ -//= require vue -//= require timeago -//= require environments/components/environment_item +require('./spec_helper'); +require('vue'); +require('timeago'); +require('environments/components/environment_item'); describe('Environment item', () => { preloadFixtures('static/environments/table.html.raw'); diff --git a/spec/javascripts/environments/environment_rollback_spec.js.es6 b/spec/javascripts/environments/environment_rollback_spec.js.es6 index 21241116e29..72f44014258 100644 --- a/spec/javascripts/environments/environment_rollback_spec.js.es6 +++ b/spec/javascripts/environments/environment_rollback_spec.js.es6 @@ -1,5 +1,7 @@ -//= require vue -//= require environments/components/environment_rollback +require('./spec_helper'); +require('vue'); +require('environments/components/environment_rollback'); + describe('Rollback Component', () => { preloadFixtures('static/environments/element.html.raw'); diff --git a/spec/javascripts/environments/environment_stop_spec.js.es6 b/spec/javascripts/environments/environment_stop_spec.js.es6 index bb998a32f32..37ae970859c 100644 --- a/spec/javascripts/environments/environment_stop_spec.js.es6 +++ b/spec/javascripts/environments/environment_stop_spec.js.es6 @@ -1,5 +1,7 @@ -//= require vue -//= require environments/components/environment_stop +require('./spec_helper'); +require('vue'); +require('environments/components/environment_stop'); + describe('Stop Component', () => { preloadFixtures('static/environments/element.html.raw'); diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 index 17c00acf63e..eefe87be5aa 100644 --- a/spec/javascripts/environments/environments_store_spec.js.es6 +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -1,8 +1,8 @@ /* global environmentsList */ -//= require vue -//= require environments/stores/environments_store -//= require ./mock_data +require('vue'); +require('environments/stores/environments_store'); +require('./mock_data'); (() => { describe('Store', () => { diff --git a/spec/javascripts/environments/mock_data.js.es6 b/spec/javascripts/environments/mock_data.js.es6 index 9e16bc3e6a5..bc5f6246cba 100644 --- a/spec/javascripts/environments/mock_data.js.es6 +++ b/spec/javascripts/environments/mock_data.js.es6 @@ -1,4 +1,5 @@ /* eslint-disable no-unused-vars */ + const environmentsList = [ { id: 31, diff --git a/spec/javascripts/extensions/array_spec.js.es6 b/spec/javascripts/extensions/array_spec.js.es6 index 2ec759c8e80..5396e0eb639 100644 --- a/spec/javascripts/extensions/array_spec.js.es6 +++ b/spec/javascripts/extensions/array_spec.js.es6 @@ -1,6 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, padded-blocks */ -/*= require extensions/array */ +require('extensions/array'); (function() { describe('Array extensions', function() { diff --git a/spec/javascripts/extensions/element_spec.js.es6 b/spec/javascripts/extensions/element_spec.js.es6 index c5b86d35204..49544ae8b5c 100644 --- a/spec/javascripts/extensions/element_spec.js.es6 +++ b/spec/javascripts/extensions/element_spec.js.es6 @@ -1,4 +1,4 @@ -/*= require extensions/element */ +require('extensions/element'); (() => { describe('Element extensions', function () { diff --git a/spec/javascripts/extensions/jquery_spec.js b/spec/javascripts/extensions/jquery_spec.js index 91846bb9143..3163414b134 100644 --- a/spec/javascripts/extensions/jquery_spec.js +++ b/spec/javascripts/extensions/jquery_spec.js @@ -1,6 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, padded-blocks */ -/*= require extensions/jquery */ +require('extensions/jquery'); (function() { describe('jQuery extensions', function() { diff --git a/spec/javascripts/extensions/object_spec.js.es6 b/spec/javascripts/extensions/object_spec.js.es6 index 3b71c255b30..77ffa1a35ae 100644 --- a/spec/javascripts/extensions/object_spec.js.es6 +++ b/spec/javascripts/extensions/object_spec.js.es6 @@ -1,4 +1,4 @@ -/*= require extensions/object */ +require('extensions/object'); describe('Object extensions', () => { describe('assign', () => { diff --git a/spec/javascripts/gl_dropdown_spec.js.es6 b/spec/javascripts/gl_dropdown_spec.js.es6 index ce96571bd52..fac5b20ea7e 100644 --- a/spec/javascripts/gl_dropdown_spec.js.es6 +++ b/spec/javascripts/gl_dropdown_spec.js.es6 @@ -1,11 +1,11 @@ /* eslint-disable comma-dangle, prefer-const, no-param-reassign, no-plusplus, semi, no-unused-expressions, arrow-spacing, max-len */ /* global Turbolinks */ -/*= require jquery */ -/*= require gl_dropdown */ -/*= require turbolinks */ -/*= require lib/utils/common_utils */ -/*= require lib/utils/type_utility */ +require('./spec_helper'); +require('gl_dropdown'); +require('vendor/turbolinks'); +require('lib/utils/common_utils'); +require('lib/utils/type_utility'); (() => { const NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-link'; diff --git a/spec/javascripts/gl_field_errors_spec.js.es6 b/spec/javascripts/gl_field_errors_spec.js.es6 index e5d934540af..763e1bb5685 100644 --- a/spec/javascripts/gl_field_errors_spec.js.es6 +++ b/spec/javascripts/gl_field_errors_spec.js.es6 @@ -1,7 +1,7 @@ /* eslint-disable space-before-function-paren, arrow-body-style, indent, padded-blocks */ -//= require jquery -//= require gl_field_errors +require('./spec_helper'); +require('gl_field_errors'); ((global) => { preloadFixtures('static/gl_field_errors.html.raw'); diff --git a/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js b/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js index bc5cbeb6a40..a914eda90bb 100644 --- a/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js +++ b/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js @@ -3,7 +3,7 @@ /* global ContributorsGraph */ /* global ContributorsMasterGraph */ -//= require graphs/stat_graph_contributors_graph +require('graphs/stat_graph_contributors_graph'); describe("ContributorsGraph", function () { describe("#set_x_domain", function () { diff --git a/spec/javascripts/graphs/stat_graph_contributors_util_spec.js b/spec/javascripts/graphs/stat_graph_contributors_util_spec.js index 751f3d175e2..4f82e1c46db 100644 --- a/spec/javascripts/graphs/stat_graph_contributors_util_spec.js +++ b/spec/javascripts/graphs/stat_graph_contributors_util_spec.js @@ -1,7 +1,7 @@ /* eslint-disable quotes, padded-blocks, no-var, camelcase, object-curly-spacing, semi, indent, object-property-newline, comma-dangle, comma-spacing, spaced-comment, max-len, key-spacing, vars-on-top, quote-props, no-multi-spaces */ /* global ContributorsStatGraphUtil */ -//= require graphs/stat_graph_contributors_util +require('graphs/stat_graph_contributors_util'); describe("ContributorsStatGraphUtil", function () { diff --git a/spec/javascripts/graphs/stat_graph_spec.js b/spec/javascripts/graphs/stat_graph_spec.js index 0da124632ae..a017f35831d 100644 --- a/spec/javascripts/graphs/stat_graph_spec.js +++ b/spec/javascripts/graphs/stat_graph_spec.js @@ -1,7 +1,7 @@ /* eslint-disable quotes, padded-blocks, semi */ /* global StatGraph */ -//= require graphs/stat_graph +require('graphs/stat_graph'); describe("StatGraph", function () { diff --git a/spec/javascripts/header_spec.js b/spec/javascripts/header_spec.js index b5262afa1cf..cb12fa327d4 100644 --- a/spec/javascripts/header_spec.js +++ b/spec/javascripts/header_spec.js @@ -1,7 +1,7 @@ /* eslint-disable space-before-function-paren, padded-blocks, no-var */ -/*= require header */ -/*= require lib/utils/text_utility */ -/*= require jquery */ +require('./spec_helper'); +require('header'); +require('lib/utils/text_utility'); (function() { diff --git a/spec/javascripts/issuable_spec.js.es6 b/spec/javascripts/issuable_spec.js.es6 index 917a6267b92..2daadfa0c77 100644 --- a/spec/javascripts/issuable_spec.js.es6 +++ b/spec/javascripts/issuable_spec.js.es6 @@ -1,8 +1,8 @@ /* global Issuable */ /* global Turbolinks */ -//= require issuable -//= require turbolinks +require('issuable'); +require('turbolinks'); (() => { const BASE_URL = '/user/project/issues?scope=all&state=closed'; diff --git a/spec/javascripts/issue_spec.js b/spec/javascripts/issue_spec.js index eb07421826c..126b3682d5d 100644 --- a/spec/javascripts/issue_spec.js +++ b/spec/javascripts/issue_spec.js @@ -1,8 +1,9 @@ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-use-before-define, indent, no-trailing-spaces, comma-dangle, padded-blocks, max-len */ /* global Issue */ -/*= require lib/utils/text_utility */ -/*= require issue */ +require('./spec_helper'); +require('lib/utils/text_utility'); +require('issue'); (function() { var INVALID_URL = 'http://goesnowhere.nothing/whereami'; diff --git a/spec/javascripts/labels_issue_sidebar_spec.js.es6 b/spec/javascripts/labels_issue_sidebar_spec.js.es6 index e3146559a4a..885e975c32b 100644 --- a/spec/javascripts/labels_issue_sidebar_spec.js.es6 +++ b/spec/javascripts/labels_issue_sidebar_spec.js.es6 @@ -2,17 +2,16 @@ /* global IssuableContext */ /* global LabelsSelect */ -//= require lib/utils/type_utility -//= require jquery -//= require bootstrap -//= require gl_dropdown -//= require select2 -//= require jquery.nicescroll -//= require api -//= require create_label -//= require issuable_context -//= require users_select -//= require labels_select +require('./spec_helper'); +require('lib/utils/type_utility'); +require('gl_dropdown'); +require('select2'); +require('vendor/jquery.nicescroll'); +require('api'); +require('create_label'); +require('issuable_context'); +require('users_select'); +require('labels_select'); (() => { let saveLabelCount = 0; diff --git a/spec/javascripts/lib/utils/common_utils_spec.js.es6 b/spec/javascripts/lib/utils/common_utils_spec.js.es6 index ef75f600898..46aa0702bda 100644 --- a/spec/javascripts/lib/utils/common_utils_spec.js.es6 +++ b/spec/javascripts/lib/utils/common_utils_spec.js.es6 @@ -1,4 +1,4 @@ -//= require lib/utils/common_utils +require('lib/utils/common_utils'); (() => { describe('common_utils', () => { diff --git a/spec/javascripts/line_highlighter_spec.js b/spec/javascripts/line_highlighter_spec.js index 31f516b41bf..fb549b846e0 100644 --- a/spec/javascripts/line_highlighter_spec.js +++ b/spec/javascripts/line_highlighter_spec.js @@ -1,7 +1,8 @@ /* eslint-disable space-before-function-paren, no-var, no-param-reassign, quotes, prefer-template, no-else-return, new-cap, dot-notation, no-return-assign, comma-dangle, no-new, one-var, one-var-declaration-per-line, no-plusplus, jasmine/no-spec-dupes, no-underscore-dangle, padded-blocks, max-len */ /* global LineHighlighter */ -/*= require line_highlighter */ +require('./spec_helper'); +require('line_highlighter'); (function() { describe('LineHighlighter', function() { diff --git a/spec/javascripts/merge_request_spec.js b/spec/javascripts/merge_request_spec.js index 9b232617fe5..bbfa6aa67a5 100644 --- a/spec/javascripts/merge_request_spec.js +++ b/spec/javascripts/merge_request_spec.js @@ -1,7 +1,8 @@ /* eslint-disable space-before-function-paren, no-return-assign, padded-blocks */ /* global MergeRequest */ -/*= require merge_request */ +require('./spec_helper'); +require('merge_request'); (function() { describe('MergeRequest', function() { diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js index 98201fb98ed..a8fa47cdd57 100644 --- a/spec/javascripts/merge_request_tabs_spec.js +++ b/spec/javascripts/merge_request_tabs_spec.js @@ -1,9 +1,10 @@ /* eslint-disable no-var, comma-dangle, object-shorthand */ -/*= require merge_request_tabs */ -//= require breakpoints -//= require lib/utils/common_utils -//= require jquery.scrollTo +require('./spec_helper'); +require('merge_request_tabs'); +require('breakpoints'); +require('lib/utils/common_utils'); +require('vendor/jquery.scrollTo'); (function () { describe('MergeRequestTabs', function () { diff --git a/spec/javascripts/merge_request_widget_spec.js b/spec/javascripts/merge_request_widget_spec.js index 6f91529db00..b29f5bad234 100644 --- a/spec/javascripts/merge_request_widget_spec.js +++ b/spec/javascripts/merge_request_widget_spec.js @@ -1,7 +1,7 @@ /* eslint-disable space-before-function-paren, quotes, comma-dangle, dot-notation, indent, quote-props, no-var, padded-blocks, max-len */ -/*= require merge_request_widget */ -/*= require lib/utils/datetime_utility */ +require('merge_request_widget'); +require('lib/utils/datetime_utility'); (function() { describe('MergeRequestWidget', function() { diff --git a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 index a1c2fe3df37..32b80a4f4bd 100644 --- a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 +++ b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 @@ -1,7 +1,7 @@ /* eslint-disable no-new */ -//= require flash -//= require mini_pipeline_graph_dropdown +require('flash'); +require('mini_pipeline_graph_dropdown'); (() => { describe('Mini Pipeline Graph Dropdown', () => { diff --git a/spec/javascripts/new_branch_spec.js b/spec/javascripts/new_branch_spec.js index e0dc549a9f4..8d8c8ec9b0d 100644 --- a/spec/javascripts/new_branch_spec.js +++ b/spec/javascripts/new_branch_spec.js @@ -1,8 +1,9 @@ /* eslint-disable space-before-function-paren, one-var, no-var, one-var-declaration-per-line, no-return-assign, quotes, padded-blocks, max-len */ /* global NewBranchForm */ -/*= require jquery-ui/autocomplete */ -/*= require new_branch_form */ +require('./spec_helper'); +require('jquery-ui/ui/autocomplete'); +require('new_branch_form'); (function() { describe('Branch', function() { diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js index 9cdb0a5d5aa..d3cf2f6a0bb 100644 --- a/spec/javascripts/notes_spec.js +++ b/spec/javascripts/notes_spec.js @@ -1,10 +1,11 @@ /* eslint-disable space-before-function-paren, no-unused-expressions, no-var, object-shorthand, comma-dangle, semi, padded-blocks, max-len */ /* global Notes */ -/*= require notes */ -/*= require autosize */ -/*= require gl_form */ -/*= require lib/utils/text_utility */ +window._ = require('underscore'); +require('notes'); +require('vendor/autosize'); +require('gl_form'); +require('lib/utils/text_utility'); (function() { window.gon || (window.gon = {}); diff --git a/spec/javascripts/pipelines_spec.js.es6 b/spec/javascripts/pipelines_spec.js.es6 index f0f9ad7430d..1bee64b814f 100644 --- a/spec/javascripts/pipelines_spec.js.es6 +++ b/spec/javascripts/pipelines_spec.js.es6 @@ -1,4 +1,4 @@ -//= require pipelines +require('pipelines'); (() => { describe('Pipelines', () => { diff --git a/spec/javascripts/pretty_time_spec.js.es6 b/spec/javascripts/pretty_time_spec.js.es6 index 2e12d45f7a7..207d40983b4 100644 --- a/spec/javascripts/pretty_time_spec.js.es6 +++ b/spec/javascripts/pretty_time_spec.js.es6 @@ -1,4 +1,4 @@ -//= require lib/utils/pretty_time +require('lib/utils/pretty_time'); (() => { const PrettyTime = gl.PrettyTime; diff --git a/spec/javascripts/project_title_spec.js b/spec/javascripts/project_title_spec.js index 27b071f266d..bc09bbbe512 100644 --- a/spec/javascripts/project_title_spec.js +++ b/spec/javascripts/project_title_spec.js @@ -1,14 +1,14 @@ /* eslint-disable space-before-function-paren, no-unused-expressions, no-return-assign, no-param-reassign, no-var, new-cap, wrap-iife, no-unused-vars, quotes, jasmine/no-expect-in-setup-teardown, padded-blocks, max-len */ - /* global Project */ -/*= require bootstrap */ -/*= require select2 */ -/*= require lib/utils/type_utility */ -/*= require gl_dropdown */ -/*= require api */ -/*= require project_select */ -/*= require project */ +require('./spec_helper'); +require('bootstrap/js/dropdown'); +require('select2/select2.js'); +require('lib/utils/type_utility'); +require('gl_dropdown'); +require('api'); +require('project_select'); +require('project'); (function() { window.gon || (window.gon = {}); diff --git a/spec/javascripts/right_sidebar_spec.js b/spec/javascripts/right_sidebar_spec.js index 0177d8e4e79..e0343c19fbe 100644 --- a/spec/javascripts/right_sidebar_spec.js +++ b/spec/javascripts/right_sidebar_spec.js @@ -1,11 +1,10 @@ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, new-parens, no-return-assign, new-cap, vars-on-top, semi, padded-blocks, max-len */ /* global Sidebar */ -/*= require right_sidebar */ -/*= require jquery */ -/*= require js.cookie */ - -/*= require extensions/jquery.js */ +require('./spec_helper'); +require('right_sidebar'); +require('vendor/js.cookie'); +require('extensions/jquery.js'); (function() { var $aside, $icon, $labelsIcon, $page, $toggle, assertSidebarState; diff --git a/spec/javascripts/search_autocomplete_spec.js b/spec/javascripts/search_autocomplete_spec.js index e13c4ad772c..2609ca4f53b 100644 --- a/spec/javascripts/search_autocomplete_spec.js +++ b/spec/javascripts/search_autocomplete_spec.js @@ -1,13 +1,12 @@ /* eslint-disable space-before-function-paren, max-len, no-var, one-var, one-var-declaration-per-line, no-unused-expressions, consistent-return, no-param-reassign, default-case, no-return-assign, comma-dangle, object-shorthand, prefer-template, quotes, new-parens, vars-on-top, new-cap, padded-blocks, max-len */ - -/*= require gl_dropdown */ -/*= require search_autocomplete */ -/*= require jquery */ -/*= require lib/utils/common_utils */ -/*= require lib/utils/type_utility */ -/*= require fuzzaldrin-plus */ -/*= require turbolinks */ -/*= require jquery.turbolinks */ +require('./spec_helper'); +require('gl_dropdown'); +require('search_autocomplete'); +require('lib/utils/common_utils'); +require('lib/utils/type_utility'); +require('vendor/fuzzaldrin-plus'); +require('vendor/turbolinks'); +require('vendor/jquery.turbolinks'); (function() { var addBodyAttributes, assertLinks, dashboardIssuesPath, dashboardMRsPath, groupIssuesPath, groupMRsPath, groupName, mockDashboardOptions, mockGroupOptions, mockProjectOptions, projectIssuesPath, projectMRsPath, projectName, userId, widget; diff --git a/spec/javascripts/shortcuts_issuable_spec.js b/spec/javascripts/shortcuts_issuable_spec.js index ae5d639ad9c..e6605c46bfc 100644 --- a/spec/javascripts/shortcuts_issuable_spec.js +++ b/spec/javascripts/shortcuts_issuable_spec.js @@ -1,7 +1,8 @@ /* eslint-disable space-before-function-paren, no-return-assign, no-var, quotes, padded-blocks */ /* global ShortcutsIssuable */ -/*= require shortcuts_issuable */ +require('./spec_helper'); +require('shortcuts_issuable'); (function() { describe('ShortcutsIssuable', function() { diff --git a/spec/javascripts/signin_tabs_memoizer_spec.js.es6 b/spec/javascripts/signin_tabs_memoizer_spec.js.es6 index c274b9c45f4..f7aa3e663f9 100644 --- a/spec/javascripts/signin_tabs_memoizer_spec.js.es6 +++ b/spec/javascripts/signin_tabs_memoizer_spec.js.es6 @@ -1,4 +1,5 @@ -/*= require signin_tabs_memoizer */ +require('./spec_helper'); +require('signin_tabs_memoizer'); ((global) => { describe('SigninTabsMemoizer', () => { diff --git a/spec/javascripts/smart_interval_spec.js.es6 b/spec/javascripts/smart_interval_spec.js.es6 index 39d236986b9..23cf8689585 100644 --- a/spec/javascripts/smart_interval_spec.js.es6 +++ b/spec/javascripts/smart_interval_spec.js.es6 @@ -1,5 +1,5 @@ -//= require jquery -//= require smart_interval +require('./spec_helper'); +require('smart_interval'); (() => { const DEFAULT_MAX_INTERVAL = 100; diff --git a/spec/javascripts/spec_helper.js b/spec/javascripts/spec_helper.js index f8e3aca29fa..b6dcdba927b 100644 --- a/spec/javascripts/spec_helper.js +++ b/spec/javascripts/spec_helper.js @@ -1,48 +1,8 @@ -/* eslint-disable space-before-function-paren */ -// PhantomJS (Teaspoons default driver) doesn't have support for -// Function.prototype.bind, which has caused confusion. Use this polyfill to -// avoid the confusion. -/*= require support/bind-poly */ +require('jasmine-jquery'); -// You can require your own javascript files here. By default this will include -// everything in application, however you may get better load performance if you -// require the specific files that are being used in the spec that tests them. -/*= require jquery */ -/*= require jquery.turbolinks */ -/*= require bootstrap */ -/*= require underscore */ +jasmine.getFixtures().fixturesPath = 'base/spec/javascripts/fixtures'; +jasmine.getJSONFixtures().fixturesPath = 'base/spec/javascripts/fixtures'; -// Teaspoon includes some support files, but you can use anything from your own -// support path too. -// require support/jasmine-jquery-1.7.0 -// require support/jasmine-jquery-2.0.0 -/*= require support/jasmine-jquery-2.1.0 */ - -// require support/sinon -// require support/your-support-file -// Deferring execution -// If you're using CommonJS, RequireJS or some other asynchronous library you can -// defer execution. Call Teaspoon.execute() after everything has been loaded. -// Simple example of a timeout: -// Teaspoon.defer = true -// setTimeout(Teaspoon.execute, 1000) -// Matching files -// By default Teaspoon will look for files that match -// _spec.{js,js.es6}. Add a filename_spec.js file in your spec path -// and it'll be included in the default suite automatically. If you want to -// customize suites, check out the configuration in teaspoon_env.rb -// Manifest -// If you'd rather require your spec files manually (to control order for -// instance) you can disable the suite matcher in the configuration and use this -// file as a manifest. -// For more information: http://github.com/modeset/teaspoon - -// set our fixtures path -jasmine.getFixtures().fixturesPath = '/teaspoon/fixtures'; -jasmine.getJSONFixtures().fixturesPath = '/teaspoon/fixtures'; - -// defined in ActionDispatch::TestRequest -// see https://github.com/rails/rails/blob/v4.2.7.1/actionpack/lib/action_dispatch/testing/test_request.rb#L7 window.gl = window.gl || {}; window.gl.TEST_HOST = 'http://test.host'; window.gon = window.gon || {}; diff --git a/spec/javascripts/subbable_resource_spec.js.es6 b/spec/javascripts/subbable_resource_spec.js.es6 index 6a70dd856a7..c24e860afd1 100644 --- a/spec/javascripts/subbable_resource_spec.js.es6 +++ b/spec/javascripts/subbable_resource_spec.js.es6 @@ -1,9 +1,8 @@ /* eslint-disable max-len, arrow-parens, comma-dangle, no-plusplus */ -//= vue -//= vue-resource -//= require jquery -//= require subbable_resource +require('./spec_helper'); +window._ = require('underscore'); +require('subbable_resource'); /* * Test that each rest verb calls the publish and subscribe function and passes the correct value back diff --git a/spec/javascripts/syntax_highlight_spec.js b/spec/javascripts/syntax_highlight_spec.js index 5984ce8ffd4..c06339fa709 100644 --- a/spec/javascripts/syntax_highlight_spec.js +++ b/spec/javascripts/syntax_highlight_spec.js @@ -1,6 +1,7 @@ /* eslint-disable space-before-function-paren, no-var, no-return-assign, quotes, padded-blocks */ -/*= require syntax_highlight */ +require('./spec_helper'); +require('syntax_highlight'); (function() { describe('Syntax Highlighter', function() { diff --git a/spec/javascripts/u2f/authenticate_spec.js b/spec/javascripts/u2f/authenticate_spec.js index dc2f4967985..9cd59fb019e 100644 --- a/spec/javascripts/u2f/authenticate_spec.js +++ b/spec/javascripts/u2f/authenticate_spec.js @@ -2,11 +2,12 @@ /* global MockU2FDevice */ /* global U2FAuthenticate */ -/*= require u2f/authenticate */ -/*= require u2f/util */ -/*= require u2f/error */ -/*= require u2f */ -/*= require ./mock_u2f_device */ +require('./spec_helper'); +require('u2f/authenticate'); +require('u2f/util'); +require('u2f/error'); +require('vendor/u2f'); +require('./mock_u2f_device'); (function() { describe('U2FAuthenticate', function() { diff --git a/spec/javascripts/u2f/register_spec.js b/spec/javascripts/u2f/register_spec.js index ab4c5edd044..36989bee2d2 100644 --- a/spec/javascripts/u2f/register_spec.js +++ b/spec/javascripts/u2f/register_spec.js @@ -2,11 +2,12 @@ /* global MockU2FDevice */ /* global U2FRegister */ -/*= require u2f/register */ -/*= require u2f/util */ -/*= require u2f/error */ -/*= require u2f */ -/*= require ./mock_u2f_device */ +require('./spec_helper'); +require('u2f/register'); +require('u2f/util'); +require('u2f/error'); +require('vendor/u2f'); +require('./mock_u2f_device'); (function() { describe('U2FRegister', function() { diff --git a/spec/javascripts/vue_common_components/commit_spec.js.es6 b/spec/javascripts/vue_common_components/commit_spec.js.es6 index d6c6f786fb1..23ae7c4ba19 100644 --- a/spec/javascripts/vue_common_components/commit_spec.js.es6 +++ b/spec/javascripts/vue_common_components/commit_spec.js.es6 @@ -1,4 +1,5 @@ -//= require vue_common_component/commit +require('./spec_helper'); +require('vue_common_component/commit'); describe('Commit component', () => { let props; diff --git a/spec/javascripts/zen_mode_spec.js b/spec/javascripts/zen_mode_spec.js index f1c2edcc55c..2c790b193b0 100644 --- a/spec/javascripts/zen_mode_spec.js +++ b/spec/javascripts/zen_mode_spec.js @@ -3,7 +3,8 @@ /* global Mousetrap */ /* global ZenMode */ -/*= require zen_mode */ +require('./spec_helper'); +require('zen_mode'); (function() { var enterZen, escapeKeydown, exitZen; diff --git a/vendor/assets/javascripts/jquery.turbolinks.js b/vendor/assets/javascripts/jquery.turbolinks.js index fd6e95e75d5..0cf3fc7cf7a 100644 --- a/vendor/assets/javascripts/jquery.turbolinks.js +++ b/vendor/assets/javascripts/jquery.turbolinks.js @@ -8,10 +8,23 @@ The MIT License Copyright (c) 2012-2013 Sasha Koss & Rico Sta. Cruz */ -(function() { +(function (root, factory) { + if (typeof define === 'function' && define.amd) { + // AMD. Register as an anonymous module unless amdModuleId is set + define(["jquery"], function (a0) { + return (factory(a0)); + }); + } else if (typeof exports === 'object') { + // Node. Does not work with strict CommonJS, but + // only CommonJS-like environments that support module.exports, + // like Node. + module.exports = factory(require("jquery")); + } else { + factory(jQuery); + } +}(this, function($) { var $, $document; - - $ = window.jQuery || (typeof require === "function" ? require('jquery') : void 0); + $ = $ || window.jQuery || (typeof require === "function" ? require('jquery') : void 0); $document = $(document); @@ -46,4 +59,4 @@ Copyright (c) 2012-2013 Sasha Koss & Rico Sta. Cruz $.turbo.use('page:load', 'page:fetch'); -}).call(this); +})); -- cgit v1.2.1 From 1e8a4189dc4cd97702999367775c54c10463ffc9 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Sun, 11 Dec 2016 01:31:19 -0600 Subject: move webpack asset compilation to the setup-test-env stage --- .gitlab-ci.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6e727333929..ebf165abf14 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,8 +24,6 @@ before_script: - '[ "$USE_BUNDLE_INSTALL" != "true" ] || retry bundle install --without postgres production --jobs $(nproc) $FLAGS' - retry gem install knapsack - '[ "$SETUP_DB" != "true" ] || bundle exec rake db:drop db:create db:schema:load db:migrate add_limits_mysql' - - curl --silent --location https://deb.nodesource.com/setup_6.x | bash - - - apt-get install --assume-yes nodejs - npm install stages: @@ -64,7 +62,6 @@ stages: <<: *dedicated-runner <<: *use-db script: - - bundle exec rake webpack:compile - JOB_NAME=( $CI_BUILD_NAME ) - export CI_NODE_INDEX=${JOB_NAME[1]} - export CI_NODE_TOTAL=${JOB_NAME[2]} @@ -83,7 +80,6 @@ stages: <<: *dedicated-runner <<: *use-db script: - - bundle exec rake webpack:compile - JOB_NAME=( $CI_BUILD_NAME ) - export CI_NODE_INDEX=${JOB_NAME[1]} - export CI_NODE_TOTAL=${JOB_NAME[2]} @@ -113,6 +109,7 @@ setup-test-env: <<: *dedicated-runner stage: prepare script: + - bundle exec rake webpack:compile - bundle exec rake assets:precompile 2>/dev/null - bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init' artifacts: @@ -381,6 +378,8 @@ lint:javascript: - node_modules/ stage: test image: "node:7.1" + before_script: + - npm install script: - npm --silent run eslint @@ -391,6 +390,8 @@ lint:javascript:report: - node_modules/ stage: post-test image: "node:7.1" + before_script: + - npm install script: - find app/ spec/ -name '*.js' -or -name '*.js.es6' -exec sed --in-place 's|/\* eslint-disable .*\*/||' {} \; # run report over all files - npm --silent run eslint-report || true # ignore exit code -- cgit v1.2.1 From ee6de1d34f27fa4e60ab8a493d1b2d6ca997e91e Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 29 Dec 2016 15:30:58 -0600 Subject: ignore karma config in eslint --- .eslintignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.eslintignore b/.eslintignore index a9d27a6765e..c742b08c005 100644 --- a/.eslintignore +++ b/.eslintignore @@ -5,4 +5,5 @@ /public/ /tmp/ /vendor/ +karma.config.js webpack.config.js -- cgit v1.2.1 From 0e4aaa06d3a83f66a90a6f084efc8742a4221d5f Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Mon, 9 Jan 2017 18:04:04 -0600 Subject: remove remaining vestiges of teaspoon test runner --- .gitlab-ci.yml | 3 +- Gemfile | 4 - Gemfile.lock | 9 --- bin/teaspoon | 8 -- lib/tasks/gitlab/test.rake | 2 +- lib/tasks/karma.rake | 25 +++++++ lib/tasks/teaspoon.rake | 25 ------- lib/tasks/test.rake | 2 +- package.json | 1 + spec/teaspoon_env.rb | 178 --------------------------------------------- 10 files changed, 29 insertions(+), 228 deletions(-) delete mode 100755 bin/teaspoon create mode 100644 lib/tasks/karma.rake delete mode 100644 lib/tasks/teaspoon.rake delete mode 100644 spec/teaspoon_env.rb diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ebf165abf14..b8d2499f984 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -298,8 +298,7 @@ karma: <<: *dedicated-runner script: - npm link istanbul - - rake webpack:compile - - npm run karma-start + - rake karma artifacts: name: coverage-javascript expire_in: 31d diff --git a/Gemfile b/Gemfile index 27e415966df..0a5b4f5753c 100644 --- a/Gemfile +++ b/Gemfile @@ -290,13 +290,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.43.0', require: false gem 'rubocop-rspec', '~> 1.5.0', require: false diff --git a/Gemfile.lock b/Gemfile.lock index b88f51a7a43..d02d35d638c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -697,8 +697,6 @@ 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) @@ -722,10 +720,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 (0.4.2) activerecord (>= 3.2) @@ -958,14 +952,11 @@ 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 (~> 0.4.2) thin (~> 1.7.0) timecop (~> 0.8.0) diff --git a/bin/teaspoon b/bin/teaspoon deleted file mode 100755 index 7c3b8dfc4ed..00000000000 --- a/bin/teaspoon +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env ruby -begin - load File.expand_path('../spring', __FILE__) -rescue LoadError => e - raise unless e.message.include?('spring') -end -require 'bundler/setup' -load Gem.bin_path('teaspoon', 'teaspoon') diff --git a/lib/tasks/gitlab/test.rake b/lib/tasks/gitlab/test.rake index ec7aec1621c..84810b489ce 100644 --- a/lib/tasks/gitlab/test.rake +++ b/lib/tasks/gitlab/test.rake @@ -6,7 +6,7 @@ namespace :gitlab do %W(rake rubocop), %W(rake spinach), %W(rake spec), - %W(npm run karma-start) + %W(rake karma) ] cmds.each do |cmd| diff --git a/lib/tasks/karma.rake b/lib/tasks/karma.rake new file mode 100644 index 00000000000..89812a179ec --- /dev/null +++ b/lib/tasks/karma.rake @@ -0,0 +1,25 @@ +unless Rails.env.production? + Rake::Task['karma'].clear if Rake::Task.task_defined?('karma') + + namespace :karma do + desc 'GitLab | Karma | Generate fixtures for JavaScript tests' + RSpec::Core::RakeTask.new(:fixtures) do |t| + ENV['NO_KNAPSACK'] = 'true' + t.pattern = 'spec/javascripts/fixtures/*.rb' + t.rspec_opts = '--format documentation' + end + + desc 'GitLab | Karma | Run JavaScript tests' + task :tests do + sh "npm run karma" do |ok, res| + abort('rake karma:tests failed') unless ok + end + end + end + + desc 'GitLab | Karma | Shortcut for karma:fixtures and karma:tests' + task :karma do + Rake::Task['karma:fixtures'].invoke + Rake::Task['karma:tests'].invoke + end +end diff --git a/lib/tasks/teaspoon.rake b/lib/tasks/teaspoon.rake deleted file mode 100644 index 08caedd7ff3..00000000000 --- a/lib/tasks/teaspoon.rake +++ /dev/null @@ -1,25 +0,0 @@ -unless Rails.env.production? - Rake::Task['teaspoon'].clear if Rake::Task.task_defined?('teaspoon') - - namespace :teaspoon do - desc 'GitLab | Teaspoon | Generate fixtures for JavaScript tests' - RSpec::Core::RakeTask.new(:fixtures) do |t| - ENV['NO_KNAPSACK'] = 'true' - t.pattern = 'spec/javascripts/fixtures/*.rb' - t.rspec_opts = '--format documentation' - end - - desc 'GitLab | Teaspoon | Run JavaScript tests' - task :tests do - require "teaspoon/console" - options = {} - abort('rake teaspoon:tests failed') if Teaspoon::Console.new(options).failures? - end - end - - desc 'GitLab | Teaspoon | Shortcut for teaspoon:fixtures and teaspoon:tests' - task :teaspoon do - Rake::Task['teaspoon:fixtures'].invoke - Rake::Task['teaspoon:tests'].invoke - end -end diff --git a/lib/tasks/test.rake b/lib/tasks/test.rake index 83f53e5454b..3e01f91d32c 100644 --- a/lib/tasks/test.rake +++ b/lib/tasks/test.rake @@ -7,5 +7,5 @@ end unless Rails.env.production? desc "GitLab | Run all tests on CI with simplecov" - task test_ci: [:rubocop, :brakeman, :'karma-start', :spinach, :spec] + task test_ci: [:rubocop, :brakeman, :karma, :spinach, :spec] end diff --git a/package.json b/package.json index ec012e9c3bd..ca767ebec9c 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "eslint": "eslint --max-warnings 0 --ext .js,.js.es6 .", "eslint-fix": "npm run eslint -- --fix", "eslint-report": "npm run eslint -- --format html --output-file ./eslint-report.html", + "karma": "karma start config/karma.config.js --single-run", "karma-start": "karma start config/karma.config.js" }, "dependencies": { diff --git a/spec/teaspoon_env.rb b/spec/teaspoon_env.rb deleted file mode 100644 index 5ea020f313c..00000000000 --- a/spec/teaspoon_env.rb +++ /dev/null @@ -1,178 +0,0 @@ -Teaspoon.configure do |config| - # Determines where the Teaspoon routes will be mounted. Changing this to "/jasmine" would allow you to browse to - # `http://localhost:3000/jasmine` to run your tests. - config.mount_at = "/teaspoon" - - # Specifies the root where Teaspoon will look for files. If you're testing an engine using a dummy application it can - # be useful to set this to your engines root (e.g. `Teaspoon::Engine.root`). - # Note: Defaults to `Rails.root` if nil. - config.root = nil - - # Paths that will be appended to the Rails assets paths - # Note: Relative to `config.root`. - config.asset_paths = ["spec/javascripts", "spec/javascripts/stylesheets"] - - # Fixtures are rendered through a controller, which allows using HAML, RABL/JBuilder, etc. Files in these paths will - # be rendered as fixtures. - config.fixture_paths = ["spec/javascripts/fixtures"] - - # SUITES - # - # You can modify the default suite configuration and create new suites here. Suites are isolated from one another. - # - # When defining a suite you can provide a name and a block. If the name is left blank, :default is assumed. You can - # omit various directives and the ones defined in the default suite will be used. - # - # To run a specific suite - # - in the browser: http://localhost/teaspoon/[suite_name] - # - with the rake task: rake teaspoon suite=[suite_name] - # - with the cli: teaspoon --suite=[suite_name] - config.suite do |suite| - # Specify the framework you would like to use. This allows you to select versions, and will do some basic setup for - # you -- which you can override with the directives below. This should be specified first, as it can override other - # directives. - # Note: If no version is specified, the latest is assumed. - # - # Versions: 1.3.1, 2.0.3, 2.1.3, 2.2.0 - suite.use_framework :jasmine, "2.2.0" - - # Specify a file matcher as a regular expression and all matching files will be loaded when the suite is run. These - # files need to be within an asset path. You can add asset paths using the `config.asset_paths`. - suite.matcher = "{spec/javascripts,app/assets}/**/*_spec.{js,js.es6,es6}" - - # Load additional JS files, but requiring them in your spec helper is the preferred way to do this. - # suite.javascripts = [] - - # You can include your own stylesheets if you want to change how Teaspoon looks. - # Note: Spec related CSS can and should be loaded using fixtures. - # suite.stylesheets = ["teaspoon"] - - # This suites spec helper, which can require additional support files. This file is loaded before any of your test - # files are loaded. - suite.helper = "spec_helper" - - # Partial to be rendered in the head tag of the runner. You can use the provided ones or define your own by creating - # a `_boot.html.erb` in your fixtures path, and adjust the config to `"/boot"` for instance. - # - # Available: boot, boot_require_js - suite.boot_partial = "boot" - - # Partial to be rendered in the body tag of the runner. You can define your own to create a custom body structure. - suite.body_partial = "body" - - # Hooks allow you to use `Teaspoon.hook("fixtures")` before, after, or during your spec run. This will make a - # synchronous Ajax request to the server that will call all of the blocks you've defined for that hook name. - # suite.hook :fixtures, &proc{} - - # Determine whether specs loaded into the test harness should be embedded as individual script tags or concatenated - # into a single file. Similar to Rails' asset `debug: true` and `config.assets.debug = true` options. By default, - # Teaspoon expands all assets to provide more valuable stack traces that reference individual source files. - # suite.expand_assets = true - end - - # Example suite. Since we're just filtering to files already within the root test/javascripts, these files will also - # be run in the default suite -- but can be focused into a more specific suite. - # config.suite :targeted do |suite| - # suite.matcher = "spec/javascripts/targeted/*_spec.{js,js.coffee,coffee}" - # end - - # CONSOLE RUNNER SPECIFIC - # - # These configuration directives are applicable only when running via the rake task or command line interface. These - # directives can be overridden using the command line interface arguments or with ENV variables when using the rake - # task. - # - # Command Line Interface: - # teaspoon --driver=phantomjs --server-port=31337 --fail-fast=true --format=junit --suite=my_suite /spec/file_spec.js - # - # Rake: - # teaspoon DRIVER=phantomjs SERVER_PORT=31337 FAIL_FAST=true FORMATTERS=junit suite=my_suite - - # Specify which headless driver to use. Supports PhantomJS and Selenium Webdriver. - # - # Available: :phantomjs, :selenium, :capybara_webkit - # PhantomJS: https://github.com/modeset/teaspoon/wiki/Using-PhantomJS - # Selenium Webdriver: https://github.com/modeset/teaspoon/wiki/Using-Selenium-WebDriver - # Capybara Webkit: https://github.com/modeset/teaspoon/wiki/Using-Capybara-Webkit - # config.driver = :phantomjs - - # Specify additional options for the driver. - # - # PhantomJS: https://github.com/modeset/teaspoon/wiki/Using-PhantomJS - # Selenium Webdriver: https://github.com/modeset/teaspoon/wiki/Using-Selenium-WebDriver - # Capybara Webkit: https://github.com/modeset/teaspoon/wiki/Using-Capybara-Webkit - # config.driver_options = nil - - # Specify the timeout for the driver. Specs are expected to complete within this time frame or the run will be - # considered a failure. This is to avoid issues that can arise where tests stall. - # config.driver_timeout = 180 - - # Specify a server to use with Rack (e.g. thin, mongrel). If nil is provided Rack::Server is used. - # config.server = nil - - # Specify a port to run on a specific port, otherwise Teaspoon will use a random available port. - # config.server_port = nil - - # Timeout for starting the server in seconds. If your server is slow to start you may have to bump this, or you may - # want to lower this if you know it shouldn't take long to start. - # config.server_timeout = 20 - - # Force Teaspoon to fail immediately after a failing suite. Can be useful to make Teaspoon fail early if you have - # several suites, but in environments like CI this may not be desirable. - # config.fail_fast = true - - # Specify the formatters to use when outputting the results. - # Note: Output files can be specified by using `"junit>/path/to/output.xml"`. - # - # Available: :dot, :clean, :documentation, :json, :junit, :pride, :rspec_html, :snowday, :swayze_or_oprah, :tap, :tap_y, :teamcity - # config.formatters = [:dot] - - # Specify if you want color output from the formatters. - # config.color = true - - # Teaspoon pipes all console[log/debug/error] to $stdout. This is useful to catch places where you've forgotten to - # remove them, but in verbose applications this may not be desirable. - # config.suppress_log = false - - # COVERAGE REPORTS / THRESHOLD ASSERTIONS - # - # Coverage reports requires Istanbul (https://github.com/gotwarlost/istanbul) to add instrumentation to your code and - # display coverage statistics. - # - # Coverage configurations are similar to suites. You can define several, and use different ones under different - # conditions. - # - # To run with a specific coverage configuration - # - with the rake task: rake teaspoon USE_COVERAGE=[coverage_name] - # - with the cli: teaspoon --coverage=[coverage_name] - - # Specify that you always want a coverage configuration to be used. Otherwise, specify that you want coverage - # on the CLI. - # Set this to "true" or the name of your coverage config. - config.use_coverage = true - - # You can have multiple coverage configs by passing a name to config.coverage. - # e.g. config.coverage :ci do |coverage| - # The default coverage config name is :default. - config.coverage do |coverage| - # Which coverage reports Istanbul should generate. Correlates directly to what Istanbul supports. - # - # Available: text-summary, text, html, lcov, lcovonly, cobertura, teamcity - coverage.reports = ["text-summary", "html"] - - # The path that the coverage should be written to - when there's an artifact to write to disk. - # Note: Relative to `config.root`. - coverage.output_path = "coverage-javascript" - - # Assets to be ignored when generating coverage reports. Accepts an array of filenames or regular expressions. The - # default excludes assets from vendor, gems and support libraries. - coverage.ignore = [%r{vendor/}, %r{spec/}] - - # Various thresholds requirements can be defined, and those thresholds will be checked at the end of a run. If any - # aren't met the run will fail with a message. Thresholds can be defined as a percentage (0-100), or nil. - # coverage.statements = nil - # coverage.functions = nil - # coverage.branches = nil - # coverage.lines = nil - end -end -- cgit v1.2.1 From eb1bbe73d06dbb9419607c0882f2d6da7fe4428c Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 6 Jan 2017 12:46:56 -0600 Subject: fix spec_helper missing/broken references --- spec/javascripts/behaviors/autosize_spec.js | 1 + spec/javascripts/behaviors/quick_submit_spec.js | 2 +- spec/javascripts/behaviors/requires_input_spec.js | 2 +- spec/javascripts/boards/boards_store_spec.js.es6 | 1 + spec/javascripts/boards/issue_spec.js.es6 | 1 + spec/javascripts/boards/list_spec.js.es6 | 1 + spec/javascripts/datetime_utility_spec.js.es6 | 1 + spec/javascripts/diff_comments_store_spec.js.es6 | 1 + spec/javascripts/environments/environment_actions_spec.js.es6 | 2 +- spec/javascripts/environments/environment_external_url_spec.js.es6 | 2 +- spec/javascripts/environments/environment_item_spec.js.es6 | 2 +- spec/javascripts/environments/environment_rollback_spec.js.es6 | 2 +- spec/javascripts/environments/environment_stop_spec.js.es6 | 2 +- spec/javascripts/environments/environments_store_spec.js.es6 | 1 + spec/javascripts/extensions/array_spec.js.es6 | 1 + spec/javascripts/extensions/element_spec.js.es6 | 1 + spec/javascripts/extensions/jquery_spec.js | 1 + spec/javascripts/extensions/object_spec.js.es6 | 1 + spec/javascripts/graphs/stat_graph_contributors_graph_spec.js | 1 + spec/javascripts/graphs/stat_graph_contributors_util_spec.js | 1 + spec/javascripts/graphs/stat_graph_spec.js | 1 + spec/javascripts/header_spec.js | 1 + spec/javascripts/issuable_spec.js.es6 | 1 + spec/javascripts/lib/utils/common_utils_spec.js.es6 | 1 + spec/javascripts/merge_request_widget_spec.js | 1 + spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 | 1 + spec/javascripts/notes_spec.js | 1 + spec/javascripts/pipelines_spec.js.es6 | 1 + spec/javascripts/pretty_time_spec.js.es6 | 1 + spec/javascripts/search_autocomplete_spec.js | 1 + spec/javascripts/u2f/authenticate_spec.js | 2 +- spec/javascripts/u2f/register_spec.js | 2 +- spec/javascripts/vue_common_components/commit_spec.js.es6 | 2 +- 33 files changed, 33 insertions(+), 10 deletions(-) diff --git a/spec/javascripts/behaviors/autosize_spec.js b/spec/javascripts/behaviors/autosize_spec.js index e05793cf2e3..603f1ae5f3e 100644 --- a/spec/javascripts/behaviors/autosize_spec.js +++ b/spec/javascripts/behaviors/autosize_spec.js @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, comma-dangle, no-return-assign, padded-blocks, max-len */ +require('../spec_helper'); require('behaviors/autosize'); (function() { diff --git a/spec/javascripts/behaviors/quick_submit_spec.js b/spec/javascripts/behaviors/quick_submit_spec.js index 4a00b1b2d38..f7bf95daa6c 100644 --- a/spec/javascripts/behaviors/quick_submit_spec.js +++ b/spec/javascripts/behaviors/quick_submit_spec.js @@ -1,6 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, no-return-assign, comma-dangle, jasmine/no-spec-dupes, new-cap, padded-blocks, max-len */ -require('./spec_helper'); +require('../spec_helper'); require('behaviors/quick_submit'); (function() { diff --git a/spec/javascripts/behaviors/requires_input_spec.js b/spec/javascripts/behaviors/requires_input_spec.js index 44d91d41abf..40a113cded3 100644 --- a/spec/javascripts/behaviors/requires_input_spec.js +++ b/spec/javascripts/behaviors/requires_input_spec.js @@ -1,6 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, padded-blocks */ -require('./spec_helper'); +require('../spec_helper'); require('behaviors/requires_input'); (function() { diff --git a/spec/javascripts/boards/boards_store_spec.js.es6 b/spec/javascripts/boards/boards_store_spec.js.es6 index d995380c620..1df3e65fba5 100644 --- a/spec/javascripts/boards/boards_store_spec.js.es6 +++ b/spec/javascripts/boards/boards_store_spec.js.es6 @@ -6,6 +6,7 @@ /* global listObj */ /* global listObjDuplicate */ +require('../spec_helper'); require('jquery_ujs'); require('js.cookie'); require('vue'); diff --git a/spec/javascripts/boards/issue_spec.js.es6 b/spec/javascripts/boards/issue_spec.js.es6 index 2cdbdd725b1..98f09e77609 100644 --- a/spec/javascripts/boards/issue_spec.js.es6 +++ b/spec/javascripts/boards/issue_spec.js.es6 @@ -2,6 +2,7 @@ /* global BoardService */ /* global ListIssue */ +require('../spec_helper'); require('jquery_ujs'); require('js.cookie'); require('vue'); diff --git a/spec/javascripts/boards/list_spec.js.es6 b/spec/javascripts/boards/list_spec.js.es6 index dd82f482207..9f92854eff0 100644 --- a/spec/javascripts/boards/list_spec.js.es6 +++ b/spec/javascripts/boards/list_spec.js.es6 @@ -5,6 +5,7 @@ /* global List */ /* global listObj */ +require('../spec_helper'); require('jquery_ujs'); require('js.cookie'); require('vue'); diff --git a/spec/javascripts/datetime_utility_spec.js.es6 b/spec/javascripts/datetime_utility_spec.js.es6 index 713e7742988..d4f27d2691a 100644 --- a/spec/javascripts/datetime_utility_spec.js.es6 +++ b/spec/javascripts/datetime_utility_spec.js.es6 @@ -1,3 +1,4 @@ +require('./spec_helper'); require('lib/utils/datetime_utility'); (() => { diff --git a/spec/javascripts/diff_comments_store_spec.js.es6 b/spec/javascripts/diff_comments_store_spec.js.es6 index f27ba0f93f7..487f1ab8b5d 100644 --- a/spec/javascripts/diff_comments_store_spec.js.es6 +++ b/spec/javascripts/diff_comments_store_spec.js.es6 @@ -1,6 +1,7 @@ /* eslint-disable no-extra-semi, jasmine/no-global-setup, dot-notation, jasmine/no-expect-in-setup-teardown, max-len */ /* global CommentsStore */ +require('./spec_helper'); require('diff_notes/models/discussion'); require('diff_notes/models/note'); require('diff_notes/stores/comments'); diff --git a/spec/javascripts/environments/environment_actions_spec.js.es6 b/spec/javascripts/environments/environment_actions_spec.js.es6 index 34330f7bfd6..d2d644fc325 100644 --- a/spec/javascripts/environments/environment_actions_spec.js.es6 +++ b/spec/javascripts/environments/environment_actions_spec.js.es6 @@ -1,4 +1,4 @@ -require('./spec_helper'); +require('../spec_helper'); require('vue'); require('environments/components/environment_actions'); diff --git a/spec/javascripts/environments/environment_external_url_spec.js.es6 b/spec/javascripts/environments/environment_external_url_spec.js.es6 index 71785e7ecf1..42886302183 100644 --- a/spec/javascripts/environments/environment_external_url_spec.js.es6 +++ b/spec/javascripts/environments/environment_external_url_spec.js.es6 @@ -1,4 +1,4 @@ -require('./spec_helper'); +require('../spec_helper'); require('vue'); require('environments/components/environment_external_url'); diff --git a/spec/javascripts/environments/environment_item_spec.js.es6 b/spec/javascripts/environments/environment_item_spec.js.es6 index be753498269..2e0f676065c 100644 --- a/spec/javascripts/environments/environment_item_spec.js.es6 +++ b/spec/javascripts/environments/environment_item_spec.js.es6 @@ -1,4 +1,4 @@ -require('./spec_helper'); +require('../spec_helper'); require('vue'); require('timeago'); require('environments/components/environment_item'); diff --git a/spec/javascripts/environments/environment_rollback_spec.js.es6 b/spec/javascripts/environments/environment_rollback_spec.js.es6 index 72f44014258..46002ceef8b 100644 --- a/spec/javascripts/environments/environment_rollback_spec.js.es6 +++ b/spec/javascripts/environments/environment_rollback_spec.js.es6 @@ -1,4 +1,4 @@ -require('./spec_helper'); +require('../spec_helper'); require('vue'); require('environments/components/environment_rollback'); diff --git a/spec/javascripts/environments/environment_stop_spec.js.es6 b/spec/javascripts/environments/environment_stop_spec.js.es6 index 37ae970859c..7ab6cbbda6a 100644 --- a/spec/javascripts/environments/environment_stop_spec.js.es6 +++ b/spec/javascripts/environments/environment_stop_spec.js.es6 @@ -1,4 +1,4 @@ -require('./spec_helper'); +require('../spec_helper'); require('vue'); require('environments/components/environment_stop'); diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 index eefe87be5aa..dbc03bd8c4e 100644 --- a/spec/javascripts/environments/environments_store_spec.js.es6 +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -1,5 +1,6 @@ /* global environmentsList */ +require('../spec_helper'); require('vue'); require('environments/stores/environments_store'); require('./mock_data'); diff --git a/spec/javascripts/extensions/array_spec.js.es6 b/spec/javascripts/extensions/array_spec.js.es6 index 5396e0eb639..f35cda4cac7 100644 --- a/spec/javascripts/extensions/array_spec.js.es6 +++ b/spec/javascripts/extensions/array_spec.js.es6 @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, padded-blocks */ +require('../spec_helper'); require('extensions/array'); (function() { diff --git a/spec/javascripts/extensions/element_spec.js.es6 b/spec/javascripts/extensions/element_spec.js.es6 index 49544ae8b5c..fddd7600cb9 100644 --- a/spec/javascripts/extensions/element_spec.js.es6 +++ b/spec/javascripts/extensions/element_spec.js.es6 @@ -1,3 +1,4 @@ +require('../spec_helper'); require('extensions/element'); (() => { diff --git a/spec/javascripts/extensions/jquery_spec.js b/spec/javascripts/extensions/jquery_spec.js index 3163414b134..5f5bca4bc06 100644 --- a/spec/javascripts/extensions/jquery_spec.js +++ b/spec/javascripts/extensions/jquery_spec.js @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, padded-blocks */ +require('../spec_helper'); require('extensions/jquery'); (function() { diff --git a/spec/javascripts/extensions/object_spec.js.es6 b/spec/javascripts/extensions/object_spec.js.es6 index 77ffa1a35ae..25707be7bb4 100644 --- a/spec/javascripts/extensions/object_spec.js.es6 +++ b/spec/javascripts/extensions/object_spec.js.es6 @@ -1,3 +1,4 @@ +require('../spec_helper'); require('extensions/object'); describe('Object extensions', () => { diff --git a/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js b/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js index a914eda90bb..b4d278dfe88 100644 --- a/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js +++ b/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js @@ -3,6 +3,7 @@ /* global ContributorsGraph */ /* global ContributorsMasterGraph */ +require('../spec_helper'); require('graphs/stat_graph_contributors_graph'); describe("ContributorsGraph", function () { diff --git a/spec/javascripts/graphs/stat_graph_contributors_util_spec.js b/spec/javascripts/graphs/stat_graph_contributors_util_spec.js index 4f82e1c46db..8323fcff02d 100644 --- a/spec/javascripts/graphs/stat_graph_contributors_util_spec.js +++ b/spec/javascripts/graphs/stat_graph_contributors_util_spec.js @@ -1,6 +1,7 @@ /* eslint-disable quotes, padded-blocks, no-var, camelcase, object-curly-spacing, semi, indent, object-property-newline, comma-dangle, comma-spacing, spaced-comment, max-len, key-spacing, vars-on-top, quote-props, no-multi-spaces */ /* global ContributorsStatGraphUtil */ +require('../spec_helper'); require('graphs/stat_graph_contributors_util'); describe("ContributorsStatGraphUtil", function () { diff --git a/spec/javascripts/graphs/stat_graph_spec.js b/spec/javascripts/graphs/stat_graph_spec.js index a017f35831d..66c8c16a40f 100644 --- a/spec/javascripts/graphs/stat_graph_spec.js +++ b/spec/javascripts/graphs/stat_graph_spec.js @@ -1,6 +1,7 @@ /* eslint-disable quotes, padded-blocks, semi */ /* global StatGraph */ +require('../spec_helper'); require('graphs/stat_graph'); describe("StatGraph", function () { diff --git a/spec/javascripts/header_spec.js b/spec/javascripts/header_spec.js index cb12fa327d4..4e93e33d432 100644 --- a/spec/javascripts/header_spec.js +++ b/spec/javascripts/header_spec.js @@ -1,4 +1,5 @@ /* eslint-disable space-before-function-paren, padded-blocks, no-var */ + require('./spec_helper'); require('header'); require('lib/utils/text_utility'); diff --git a/spec/javascripts/issuable_spec.js.es6 b/spec/javascripts/issuable_spec.js.es6 index 2daadfa0c77..b5f4b3d6751 100644 --- a/spec/javascripts/issuable_spec.js.es6 +++ b/spec/javascripts/issuable_spec.js.es6 @@ -1,6 +1,7 @@ /* global Issuable */ /* global Turbolinks */ +require('./spec_helper'); require('issuable'); require('turbolinks'); diff --git a/spec/javascripts/lib/utils/common_utils_spec.js.es6 b/spec/javascripts/lib/utils/common_utils_spec.js.es6 index 46aa0702bda..02aabf202d0 100644 --- a/spec/javascripts/lib/utils/common_utils_spec.js.es6 +++ b/spec/javascripts/lib/utils/common_utils_spec.js.es6 @@ -1,3 +1,4 @@ +require('../../spec_helper'); require('lib/utils/common_utils'); (() => { diff --git a/spec/javascripts/merge_request_widget_spec.js b/spec/javascripts/merge_request_widget_spec.js index b29f5bad234..0ec119c94b3 100644 --- a/spec/javascripts/merge_request_widget_spec.js +++ b/spec/javascripts/merge_request_widget_spec.js @@ -1,5 +1,6 @@ /* eslint-disable space-before-function-paren, quotes, comma-dangle, dot-notation, indent, quote-props, no-var, padded-blocks, max-len */ +require('./spec_helper'); require('merge_request_widget'); require('lib/utils/datetime_utility'); diff --git a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 index 32b80a4f4bd..1faa1f88d70 100644 --- a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 +++ b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 @@ -1,5 +1,6 @@ /* eslint-disable no-new */ +require('./spec_helper'); require('flash'); require('mini_pipeline_graph_dropdown'); diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js index d3cf2f6a0bb..e257deac201 100644 --- a/spec/javascripts/notes_spec.js +++ b/spec/javascripts/notes_spec.js @@ -1,6 +1,7 @@ /* eslint-disable space-before-function-paren, no-unused-expressions, no-var, object-shorthand, comma-dangle, semi, padded-blocks, max-len */ /* global Notes */ +require('./spec_helper'); window._ = require('underscore'); require('notes'); require('vendor/autosize'); diff --git a/spec/javascripts/pipelines_spec.js.es6 b/spec/javascripts/pipelines_spec.js.es6 index 1bee64b814f..e51977ab720 100644 --- a/spec/javascripts/pipelines_spec.js.es6 +++ b/spec/javascripts/pipelines_spec.js.es6 @@ -1,3 +1,4 @@ +require('./spec_helper'); require('pipelines'); (() => { diff --git a/spec/javascripts/pretty_time_spec.js.es6 b/spec/javascripts/pretty_time_spec.js.es6 index 207d40983b4..249aa4817e9 100644 --- a/spec/javascripts/pretty_time_spec.js.es6 +++ b/spec/javascripts/pretty_time_spec.js.es6 @@ -1,3 +1,4 @@ +require('./spec_helper'); require('lib/utils/pretty_time'); (() => { diff --git a/spec/javascripts/search_autocomplete_spec.js b/spec/javascripts/search_autocomplete_spec.js index 2609ca4f53b..d919a754a75 100644 --- a/spec/javascripts/search_autocomplete_spec.js +++ b/spec/javascripts/search_autocomplete_spec.js @@ -1,4 +1,5 @@ /* eslint-disable space-before-function-paren, max-len, no-var, one-var, one-var-declaration-per-line, no-unused-expressions, consistent-return, no-param-reassign, default-case, no-return-assign, comma-dangle, object-shorthand, prefer-template, quotes, new-parens, vars-on-top, new-cap, padded-blocks, max-len */ + require('./spec_helper'); require('gl_dropdown'); require('search_autocomplete'); diff --git a/spec/javascripts/u2f/authenticate_spec.js b/spec/javascripts/u2f/authenticate_spec.js index 9cd59fb019e..a14f0e3c448 100644 --- a/spec/javascripts/u2f/authenticate_spec.js +++ b/spec/javascripts/u2f/authenticate_spec.js @@ -2,7 +2,7 @@ /* global MockU2FDevice */ /* global U2FAuthenticate */ -require('./spec_helper'); +require('../spec_helper'); require('u2f/authenticate'); require('u2f/util'); require('u2f/error'); diff --git a/spec/javascripts/u2f/register_spec.js b/spec/javascripts/u2f/register_spec.js index 36989bee2d2..157c8796fd5 100644 --- a/spec/javascripts/u2f/register_spec.js +++ b/spec/javascripts/u2f/register_spec.js @@ -2,7 +2,7 @@ /* global MockU2FDevice */ /* global U2FRegister */ -require('./spec_helper'); +require('../spec_helper'); require('u2f/register'); require('u2f/util'); require('u2f/error'); diff --git a/spec/javascripts/vue_common_components/commit_spec.js.es6 b/spec/javascripts/vue_common_components/commit_spec.js.es6 index 23ae7c4ba19..28ffc005001 100644 --- a/spec/javascripts/vue_common_components/commit_spec.js.es6 +++ b/spec/javascripts/vue_common_components/commit_spec.js.es6 @@ -1,4 +1,4 @@ -require('./spec_helper'); +require('../spec_helper'); require('vue_common_component/commit'); describe('Commit component', () => { -- cgit v1.2.1 From 7837fe46f0e73119aaaacebd14f794f3e0fbc865 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 6 Jan 2017 12:50:01 -0600 Subject: fix broken js.cookie imports --- spec/javascripts/activities_spec.js.es6 | 2 +- spec/javascripts/awards_handler_spec.js | 2 +- spec/javascripts/boards/boards_store_spec.js.es6 | 2 +- spec/javascripts/boards/issue_spec.js.es6 | 2 +- spec/javascripts/boards/list_spec.js.es6 | 2 +- spec/javascripts/dashboard_spec.js.es6 | 2 +- spec/javascripts/right_sidebar_spec.js | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/spec/javascripts/activities_spec.js.es6 b/spec/javascripts/activities_spec.js.es6 index 61fabd37170..6d625eeb973 100644 --- a/spec/javascripts/activities_spec.js.es6 +++ b/spec/javascripts/activities_spec.js.es6 @@ -1,7 +1,7 @@ /* eslint-disable no-unused-expressions, comma-spacing, prefer-const, no-prototype-builtins, semi, no-new, keyword-spacing, no-plusplus, no-shadow, max-len */ require('./spec_helper'); -require('vendor/js.cookie.js'); +window.Cookies = require('vendor/js.cookie'); require('vendor/jquery.endless-scroll.js'); require('pager'); require('activities'); diff --git a/spec/javascripts/awards_handler_spec.js b/spec/javascripts/awards_handler_spec.js index 88757e5c236..c256da072c0 100644 --- a/spec/javascripts/awards_handler_spec.js +++ b/spec/javascripts/awards_handler_spec.js @@ -3,7 +3,7 @@ require('./spec_helper'); require('awards_handler'); -require('vendor/js.cookie'); +window.Cookies = require('vendor/js.cookie'); require('./fixtures/emoji_menu'); (function() { diff --git a/spec/javascripts/boards/boards_store_spec.js.es6 b/spec/javascripts/boards/boards_store_spec.js.es6 index 1df3e65fba5..0a6842a0af2 100644 --- a/spec/javascripts/boards/boards_store_spec.js.es6 +++ b/spec/javascripts/boards/boards_store_spec.js.es6 @@ -8,7 +8,7 @@ require('../spec_helper'); require('jquery_ujs'); -require('js.cookie'); +window.Cookies = require('vendor/js.cookie'); require('vue'); require('vue-resource'); require('lib/utils/url_utility'); diff --git a/spec/javascripts/boards/issue_spec.js.es6 b/spec/javascripts/boards/issue_spec.js.es6 index 98f09e77609..6569f0f82f5 100644 --- a/spec/javascripts/boards/issue_spec.js.es6 +++ b/spec/javascripts/boards/issue_spec.js.es6 @@ -4,7 +4,7 @@ require('../spec_helper'); require('jquery_ujs'); -require('js.cookie'); +window.Cookies = require('vendor/js.cookie'); require('vue'); require('vue-resource'); require('lib/utils/url_utility'); diff --git a/spec/javascripts/boards/list_spec.js.es6 b/spec/javascripts/boards/list_spec.js.es6 index 9f92854eff0..189da6ea9fe 100644 --- a/spec/javascripts/boards/list_spec.js.es6 +++ b/spec/javascripts/boards/list_spec.js.es6 @@ -7,7 +7,7 @@ require('../spec_helper'); require('jquery_ujs'); -require('js.cookie'); +window.Cookies = require('vendor/js.cookie'); require('vue'); require('vue-resource'); require('lib/utils/url_utility'); diff --git a/spec/javascripts/dashboard_spec.js.es6 b/spec/javascripts/dashboard_spec.js.es6 index 4223215c096..7e9e622970d 100644 --- a/spec/javascripts/dashboard_spec.js.es6 +++ b/spec/javascripts/dashboard_spec.js.es6 @@ -2,7 +2,7 @@ require('./spec_helper'); require('sidebar'); -require('vendor/js.cookie'); +window.Cookies = require('vendor/js.cookie'); require('lib/utils/text_utility'); ((global) => { diff --git a/spec/javascripts/right_sidebar_spec.js b/spec/javascripts/right_sidebar_spec.js index e0343c19fbe..65730b42ea3 100644 --- a/spec/javascripts/right_sidebar_spec.js +++ b/spec/javascripts/right_sidebar_spec.js @@ -3,7 +3,7 @@ require('./spec_helper'); require('right_sidebar'); -require('vendor/js.cookie'); +window.Cookies = require('vendor/js.cookie'); require('extensions/jquery.js'); (function() { -- cgit v1.2.1 From 8b26f8edea98d3971e81ec4fa05a875a05e32d58 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 6 Jan 2017 15:48:23 -0600 Subject: correct misnamed require statements --- spec/javascripts/boards/boards_store_spec.js.es6 | 2 +- spec/javascripts/boards/issue_spec.js.es6 | 2 +- spec/javascripts/boards/list_spec.js.es6 | 2 +- spec/javascripts/environments/environment_item_spec.js.es6 | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/javascripts/boards/boards_store_spec.js.es6 b/spec/javascripts/boards/boards_store_spec.js.es6 index 0a6842a0af2..99020fa213f 100644 --- a/spec/javascripts/boards/boards_store_spec.js.es6 +++ b/spec/javascripts/boards/boards_store_spec.js.es6 @@ -7,7 +7,7 @@ /* global listObjDuplicate */ require('../spec_helper'); -require('jquery_ujs'); +require('jquery-ujs'); window.Cookies = require('vendor/js.cookie'); require('vue'); require('vue-resource'); diff --git a/spec/javascripts/boards/issue_spec.js.es6 b/spec/javascripts/boards/issue_spec.js.es6 index 6569f0f82f5..23bc4eb276f 100644 --- a/spec/javascripts/boards/issue_spec.js.es6 +++ b/spec/javascripts/boards/issue_spec.js.es6 @@ -3,7 +3,7 @@ /* global ListIssue */ require('../spec_helper'); -require('jquery_ujs'); +require('jquery-ujs'); window.Cookies = require('vendor/js.cookie'); require('vue'); require('vue-resource'); diff --git a/spec/javascripts/boards/list_spec.js.es6 b/spec/javascripts/boards/list_spec.js.es6 index 189da6ea9fe..11e7f25b83c 100644 --- a/spec/javascripts/boards/list_spec.js.es6 +++ b/spec/javascripts/boards/list_spec.js.es6 @@ -6,7 +6,7 @@ /* global listObj */ require('../spec_helper'); -require('jquery_ujs'); +require('jquery-ujs'); window.Cookies = require('vendor/js.cookie'); require('vue'); require('vue-resource'); diff --git a/spec/javascripts/environments/environment_item_spec.js.es6 b/spec/javascripts/environments/environment_item_spec.js.es6 index 2e0f676065c..6a697b45d67 100644 --- a/spec/javascripts/environments/environment_item_spec.js.es6 +++ b/spec/javascripts/environments/environment_item_spec.js.es6 @@ -1,6 +1,6 @@ require('../spec_helper'); require('vue'); -require('timeago'); +window.timeago = require('vendor/timeago'); require('environments/components/environment_item'); describe('Environment item', () => { -- cgit v1.2.1 From c2bd29ec7ba06d5aeeee9c054f5e90d3a740a5aa Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 6 Jan 2017 13:27:33 -0600 Subject: simplify and combine karma file patterns --- config/karma.config.js | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/config/karma.config.js b/config/karma.config.js index 478ef082547..0a3530b65ac 100644 --- a/config/karma.config.js +++ b/config/karma.config.js @@ -8,20 +8,13 @@ module.exports = function(config) { basePath: ROOT_PATH, frameworks: ['jquery-2.1.0', 'jasmine'], files: [ - 'spec/javascripts/*_spec.js', - 'spec/javascripts/*_spec.js.es6', - { pattern: 'spec/javascripts/fixtures/**/*.html', included: false, served: true }, - { pattern: 'spec/javascripts/fixtures/**/*.json', included: false, served: true }, + 'spec/javascripts/**/*_spec.js?(.es6)', + { pattern: 'spec/javascripts/fixtures/**/*@(.json|.html|.html.raw)', included: false }, ], preprocessors: { - 'spec/javascripts/*_spec.js': ['webpack'], - 'spec/javascripts/*_spec.js.es6': ['webpack'], - 'app/assets/javascripts/**/*.js': ['webpack'], - 'app/assets/javascripts/**/*.js.es6': ['webpack'], + 'spec/javascripts/**/*_spec.js?(.es6)': ['webpack'], }, - webpack: webpackConfig, - webpackMiddleware: { stats: 'errors-only' }, }); }; -- cgit v1.2.1 From 663936878f398710ed0fdd0f33b3c1b9efb4e1d0 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 6 Jan 2017 15:44:03 -0600 Subject: include common libraries within spec_helper --- config/webpack.config.js | 2 +- package.json | 1 - spec/javascripts/build_spec.js.es6 | 1 - spec/javascripts/gl_dropdown_spec.js.es6 | 1 - spec/javascripts/issuable_spec.js.es6 | 1 - spec/javascripts/notes_spec.js | 1 - spec/javascripts/project_title_spec.js | 1 - spec/javascripts/search_autocomplete_spec.js | 2 -- spec/javascripts/spec_helper.js | 19 +++++++++++++++++++ spec/javascripts/subbable_resource_spec.js.es6 | 1 - 10 files changed, 20 insertions(+), 10 deletions(-) diff --git a/config/webpack.config.js b/config/webpack.config.js index 5cba995888a..8dd9cf5b960 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -58,7 +58,7 @@ var config = { { test: /\.(js|es6)$/, loader: 'imports-loader', - query: '$=jquery,jQuery=jquery,this=>window' + query: 'this=>window' }, { test: /\.json$/, diff --git a/package.json b/package.json index ca767ebec9c..cea0ea4884c 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,6 @@ "jasmine-jquery": "^2.1.1", "karma": "^1.3.0", "karma-jasmine": "^1.1.0", - "karma-jquery": "^0.1.0", "karma-webpack": "^1.8.0" } } diff --git a/spec/javascripts/build_spec.js.es6 b/spec/javascripts/build_spec.js.es6 index 8b0c797647b..1821c44fdfb 100644 --- a/spec/javascripts/build_spec.js.es6 +++ b/spec/javascripts/build_spec.js.es6 @@ -7,7 +7,6 @@ require('lib/utils/datetime_utility'); require('build'); require('breakpoints'); require('vendor/jquery.nicescroll'); -require('vendor/turbolinks'); describe('Build', () => { const BUILD_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/builds/1`; diff --git a/spec/javascripts/gl_dropdown_spec.js.es6 b/spec/javascripts/gl_dropdown_spec.js.es6 index fac5b20ea7e..7b2b4771756 100644 --- a/spec/javascripts/gl_dropdown_spec.js.es6 +++ b/spec/javascripts/gl_dropdown_spec.js.es6 @@ -3,7 +3,6 @@ require('./spec_helper'); require('gl_dropdown'); -require('vendor/turbolinks'); require('lib/utils/common_utils'); require('lib/utils/type_utility'); diff --git a/spec/javascripts/issuable_spec.js.es6 b/spec/javascripts/issuable_spec.js.es6 index b5f4b3d6751..5d3269626af 100644 --- a/spec/javascripts/issuable_spec.js.es6 +++ b/spec/javascripts/issuable_spec.js.es6 @@ -3,7 +3,6 @@ require('./spec_helper'); require('issuable'); -require('turbolinks'); (() => { const BASE_URL = '/user/project/issues?scope=all&state=closed'; diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js index e257deac201..75f5192a54e 100644 --- a/spec/javascripts/notes_spec.js +++ b/spec/javascripts/notes_spec.js @@ -2,7 +2,6 @@ /* global Notes */ require('./spec_helper'); -window._ = require('underscore'); require('notes'); require('vendor/autosize'); require('gl_form'); diff --git a/spec/javascripts/project_title_spec.js b/spec/javascripts/project_title_spec.js index bc09bbbe512..a438b01fbce 100644 --- a/spec/javascripts/project_title_spec.js +++ b/spec/javascripts/project_title_spec.js @@ -2,7 +2,6 @@ /* global Project */ require('./spec_helper'); -require('bootstrap/js/dropdown'); require('select2/select2.js'); require('lib/utils/type_utility'); require('gl_dropdown'); diff --git a/spec/javascripts/search_autocomplete_spec.js b/spec/javascripts/search_autocomplete_spec.js index d919a754a75..4ac9117fd8a 100644 --- a/spec/javascripts/search_autocomplete_spec.js +++ b/spec/javascripts/search_autocomplete_spec.js @@ -6,8 +6,6 @@ require('search_autocomplete'); require('lib/utils/common_utils'); require('lib/utils/type_utility'); require('vendor/fuzzaldrin-plus'); -require('vendor/turbolinks'); -require('vendor/jquery.turbolinks'); (function() { var addBodyAttributes, assertLinks, dashboardIssuesPath, dashboardMRsPath, groupIssuesPath, groupMRsPath, groupName, mockDashboardOptions, mockGroupOptions, mockProjectOptions, projectIssuesPath, projectMRsPath, projectName, userId, widget; diff --git a/spec/javascripts/spec_helper.js b/spec/javascripts/spec_helper.js index b6dcdba927b..64f1ca4b80d 100644 --- a/spec/javascripts/spec_helper.js +++ b/spec/javascripts/spec_helper.js @@ -1,8 +1,27 @@ require('jasmine-jquery'); +// include common libraries +window.$ = window.jQuery = require('jquery'); +window._ = require('underscore'); +require('vendor/turbolinks'); +require('vendor/jquery.turbolinks'); +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'); + +// configure jasmine jasmine.getFixtures().fixturesPath = 'base/spec/javascripts/fixtures'; jasmine.getJSONFixtures().fixturesPath = 'base/spec/javascripts/fixtures'; +// stub expected globals window.gl = window.gl || {}; window.gl.TEST_HOST = 'http://test.host'; window.gon = window.gon || {}; diff --git a/spec/javascripts/subbable_resource_spec.js.es6 b/spec/javascripts/subbable_resource_spec.js.es6 index c24e860afd1..a70a1419792 100644 --- a/spec/javascripts/subbable_resource_spec.js.es6 +++ b/spec/javascripts/subbable_resource_spec.js.es6 @@ -1,7 +1,6 @@ /* eslint-disable max-len, arrow-parens, comma-dangle, no-plusplus */ require('./spec_helper'); -window._ = require('underscore'); require('subbable_resource'); /* -- cgit v1.2.1 From fc3f4f88e094a192dd825d5ce4ca9bb742c8b4d3 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 6 Jan 2017 16:06:14 -0600 Subject: correct vue require statements --- spec/javascripts/boards/boards_store_spec.js.es6 | 4 ++-- spec/javascripts/boards/issue_spec.js.es6 | 4 ++-- spec/javascripts/boards/list_spec.js.es6 | 4 ++-- spec/javascripts/environments/environment_actions_spec.js.es6 | 2 +- spec/javascripts/environments/environment_external_url_spec.js.es6 | 2 +- spec/javascripts/environments/environment_item_spec.js.es6 | 2 +- spec/javascripts/environments/environment_rollback_spec.js.es6 | 2 +- spec/javascripts/environments/environment_stop_spec.js.es6 | 2 +- spec/javascripts/environments/environments_store_spec.js.es6 | 2 +- 9 files changed, 12 insertions(+), 12 deletions(-) diff --git a/spec/javascripts/boards/boards_store_spec.js.es6 b/spec/javascripts/boards/boards_store_spec.js.es6 index 99020fa213f..c8de9ad79c3 100644 --- a/spec/javascripts/boards/boards_store_spec.js.es6 +++ b/spec/javascripts/boards/boards_store_spec.js.es6 @@ -9,8 +9,8 @@ require('../spec_helper'); require('jquery-ujs'); window.Cookies = require('vendor/js.cookie'); -require('vue'); -require('vue-resource'); +window.Vue = require('vue'); +window.Vue.use(require('vue-resource')); require('lib/utils/url_utility'); require('boards/models/issue'); require('boards/models/label'); diff --git a/spec/javascripts/boards/issue_spec.js.es6 b/spec/javascripts/boards/issue_spec.js.es6 index 23bc4eb276f..143315e4ac1 100644 --- a/spec/javascripts/boards/issue_spec.js.es6 +++ b/spec/javascripts/boards/issue_spec.js.es6 @@ -5,8 +5,8 @@ require('../spec_helper'); require('jquery-ujs'); window.Cookies = require('vendor/js.cookie'); -require('vue'); -require('vue-resource'); +window.Vue = require('vue'); +window.Vue.use(require('vue-resource')); require('lib/utils/url_utility'); require('boards/models/issue'); require('boards/models/label'); diff --git a/spec/javascripts/boards/list_spec.js.es6 b/spec/javascripts/boards/list_spec.js.es6 index 11e7f25b83c..ab04e7b5896 100644 --- a/spec/javascripts/boards/list_spec.js.es6 +++ b/spec/javascripts/boards/list_spec.js.es6 @@ -8,8 +8,8 @@ require('../spec_helper'); require('jquery-ujs'); window.Cookies = require('vendor/js.cookie'); -require('vue'); -require('vue-resource'); +window.Vue = require('vue'); +window.Vue.use(require('vue-resource')); require('lib/utils/url_utility'); require('boards/models/issue'); require('boards/models/label'); diff --git a/spec/javascripts/environments/environment_actions_spec.js.es6 b/spec/javascripts/environments/environment_actions_spec.js.es6 index d2d644fc325..8d3539b29a5 100644 --- a/spec/javascripts/environments/environment_actions_spec.js.es6 +++ b/spec/javascripts/environments/environment_actions_spec.js.es6 @@ -1,5 +1,5 @@ require('../spec_helper'); -require('vue'); +window.Vue = require('vue'); require('environments/components/environment_actions'); describe('Actions Component', () => { diff --git a/spec/javascripts/environments/environment_external_url_spec.js.es6 b/spec/javascripts/environments/environment_external_url_spec.js.es6 index 42886302183..01264781a68 100644 --- a/spec/javascripts/environments/environment_external_url_spec.js.es6 +++ b/spec/javascripts/environments/environment_external_url_spec.js.es6 @@ -1,5 +1,5 @@ require('../spec_helper'); -require('vue'); +window.Vue = require('vue'); require('environments/components/environment_external_url'); describe('External URL Component', () => { diff --git a/spec/javascripts/environments/environment_item_spec.js.es6 b/spec/javascripts/environments/environment_item_spec.js.es6 index 6a697b45d67..56c718eb501 100644 --- a/spec/javascripts/environments/environment_item_spec.js.es6 +++ b/spec/javascripts/environments/environment_item_spec.js.es6 @@ -1,5 +1,5 @@ require('../spec_helper'); -require('vue'); +window.Vue = require('vue'); window.timeago = require('vendor/timeago'); require('environments/components/environment_item'); diff --git a/spec/javascripts/environments/environment_rollback_spec.js.es6 b/spec/javascripts/environments/environment_rollback_spec.js.es6 index 46002ceef8b..5c378901608 100644 --- a/spec/javascripts/environments/environment_rollback_spec.js.es6 +++ b/spec/javascripts/environments/environment_rollback_spec.js.es6 @@ -1,5 +1,5 @@ require('../spec_helper'); -require('vue'); +window.Vue = require('vue'); require('environments/components/environment_rollback'); describe('Rollback Component', () => { diff --git a/spec/javascripts/environments/environment_stop_spec.js.es6 b/spec/javascripts/environments/environment_stop_spec.js.es6 index 7ab6cbbda6a..96c738f42d6 100644 --- a/spec/javascripts/environments/environment_stop_spec.js.es6 +++ b/spec/javascripts/environments/environment_stop_spec.js.es6 @@ -1,5 +1,5 @@ require('../spec_helper'); -require('vue'); +window.Vue = require('vue'); require('environments/components/environment_stop'); describe('Stop Component', () => { diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 index dbc03bd8c4e..8c113b5679e 100644 --- a/spec/javascripts/environments/environments_store_spec.js.es6 +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -1,7 +1,7 @@ /* global environmentsList */ require('../spec_helper'); -require('vue'); +window.Vue = require('vue'); require('environments/stores/environments_store'); require('./mock_data'); -- cgit v1.2.1 From 05b95e712d1ea70d8658de42f7c87661e6937976 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Sat, 7 Jan 2017 01:48:34 -0600 Subject: update vue library to match vendors directory --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index cea0ea4884c..ef16a371f91 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "select2": "3.5.2-browserify", "stats-webpack-plugin": "^0.4.2", "underscore": "1.8.3", - "vue": "1.0.26", + "vue": "2.0.3", "vue-resource": "0.9.3", "webpack": "^1.13.2", "webpack-dev-server": "^1.16.2" -- cgit v1.2.1 From 52c6702ec708deedef189784cdcb39564b2dcf52 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 6 Jan 2017 17:21:54 -0600 Subject: include spec_helper within karma config rather than each individual test --- config/karma.config.js | 5 +++-- spec/javascripts/abuse_reports_spec.js.es6 | 1 - spec/javascripts/activities_spec.js.es6 | 1 - spec/javascripts/awards_handler_spec.js | 1 - spec/javascripts/behaviors/autosize_spec.js | 1 - spec/javascripts/behaviors/quick_submit_spec.js | 1 - spec/javascripts/behaviors/requires_input_spec.js | 1 - spec/javascripts/boards/boards_store_spec.js.es6 | 1 - spec/javascripts/boards/issue_spec.js.es6 | 1 - spec/javascripts/boards/list_spec.js.es6 | 1 - spec/javascripts/bootstrap_linked_tabs_spec.js.es6 | 1 - spec/javascripts/build_spec.js.es6 | 1 - spec/javascripts/dashboard_spec.js.es6 | 1 - spec/javascripts/datetime_utility_spec.js.es6 | 1 - spec/javascripts/diff_comments_store_spec.js.es6 | 1 - spec/javascripts/environments/environment_actions_spec.js.es6 | 1 - spec/javascripts/environments/environment_external_url_spec.js.es6 | 1 - spec/javascripts/environments/environment_item_spec.js.es6 | 1 - spec/javascripts/environments/environment_rollback_spec.js.es6 | 1 - spec/javascripts/environments/environment_stop_spec.js.es6 | 1 - spec/javascripts/environments/environments_store_spec.js.es6 | 1 - spec/javascripts/extensions/array_spec.js.es6 | 1 - spec/javascripts/extensions/element_spec.js.es6 | 1 - spec/javascripts/extensions/jquery_spec.js | 1 - spec/javascripts/extensions/object_spec.js.es6 | 1 - spec/javascripts/gl_dropdown_spec.js.es6 | 1 - spec/javascripts/gl_field_errors_spec.js.es6 | 1 - spec/javascripts/graphs/stat_graph_contributors_graph_spec.js | 1 - spec/javascripts/graphs/stat_graph_contributors_util_spec.js | 1 - spec/javascripts/graphs/stat_graph_spec.js | 1 - spec/javascripts/header_spec.js | 1 - spec/javascripts/issuable_spec.js.es6 | 1 - spec/javascripts/issue_spec.js | 1 - spec/javascripts/labels_issue_sidebar_spec.js.es6 | 1 - spec/javascripts/lib/utils/common_utils_spec.js.es6 | 1 - spec/javascripts/line_highlighter_spec.js | 1 - spec/javascripts/merge_request_spec.js | 1 - spec/javascripts/merge_request_tabs_spec.js | 1 - spec/javascripts/merge_request_widget_spec.js | 1 - spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 | 1 - spec/javascripts/new_branch_spec.js | 1 - spec/javascripts/notes_spec.js | 1 - spec/javascripts/pipelines_spec.js.es6 | 1 - spec/javascripts/pretty_time_spec.js.es6 | 1 - spec/javascripts/project_title_spec.js | 1 - spec/javascripts/right_sidebar_spec.js | 1 - spec/javascripts/search_autocomplete_spec.js | 1 - spec/javascripts/shortcuts_issuable_spec.js | 1 - spec/javascripts/signin_tabs_memoizer_spec.js.es6 | 1 - spec/javascripts/smart_interval_spec.js.es6 | 1 - spec/javascripts/subbable_resource_spec.js.es6 | 1 - spec/javascripts/syntax_highlight_spec.js | 1 - spec/javascripts/u2f/authenticate_spec.js | 1 - spec/javascripts/u2f/register_spec.js | 1 - spec/javascripts/vue_common_components/commit_spec.js.es6 | 1 - spec/javascripts/zen_mode_spec.js | 1 - 56 files changed, 3 insertions(+), 57 deletions(-) diff --git a/config/karma.config.js b/config/karma.config.js index 0a3530b65ac..96d33490b37 100644 --- a/config/karma.config.js +++ b/config/karma.config.js @@ -6,13 +6,14 @@ var ROOT_PATH = path.resolve(__dirname, '..'); module.exports = function(config) { config.set({ basePath: ROOT_PATH, - frameworks: ['jquery-2.1.0', 'jasmine'], + frameworks: ['jasmine'], files: [ + 'spec/javascripts/spec_helper.js', 'spec/javascripts/**/*_spec.js?(.es6)', { pattern: 'spec/javascripts/fixtures/**/*@(.json|.html|.html.raw)', included: false }, ], preprocessors: { - 'spec/javascripts/**/*_spec.js?(.es6)': ['webpack'], + 'spec/javascripts/**/*.js?(.es6)': ['webpack'], }, webpack: webpackConfig, webpackMiddleware: { stats: 'errors-only' }, diff --git a/spec/javascripts/abuse_reports_spec.js.es6 b/spec/javascripts/abuse_reports_spec.js.es6 index dadee40f9b9..f4b6c9deae5 100644 --- a/spec/javascripts/abuse_reports_spec.js.es6 +++ b/spec/javascripts/abuse_reports_spec.js.es6 @@ -1,4 +1,3 @@ -require('./spec_helper'); require('lib/utils/text_utility'); require('abuse_reports'); diff --git a/spec/javascripts/activities_spec.js.es6 b/spec/javascripts/activities_spec.js.es6 index 6d625eeb973..feba184dbb0 100644 --- a/spec/javascripts/activities_spec.js.es6 +++ b/spec/javascripts/activities_spec.js.es6 @@ -1,6 +1,5 @@ /* eslint-disable no-unused-expressions, comma-spacing, prefer-const, no-prototype-builtins, semi, no-new, keyword-spacing, no-plusplus, no-shadow, max-len */ -require('./spec_helper'); window.Cookies = require('vendor/js.cookie'); require('vendor/jquery.endless-scroll.js'); require('pager'); diff --git a/spec/javascripts/awards_handler_spec.js b/spec/javascripts/awards_handler_spec.js index c256da072c0..65efa3df90b 100644 --- a/spec/javascripts/awards_handler_spec.js +++ b/spec/javascripts/awards_handler_spec.js @@ -1,7 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-unused-expressions, comma-dangle, new-parens, no-unused-vars, quotes, jasmine/no-spec-dupes, prefer-template, padded-blocks, max-len */ /* global AwardsHandler */ -require('./spec_helper'); require('awards_handler'); window.Cookies = require('vendor/js.cookie'); require('./fixtures/emoji_menu'); diff --git a/spec/javascripts/behaviors/autosize_spec.js b/spec/javascripts/behaviors/autosize_spec.js index 603f1ae5f3e..e05793cf2e3 100644 --- a/spec/javascripts/behaviors/autosize_spec.js +++ b/spec/javascripts/behaviors/autosize_spec.js @@ -1,6 +1,5 @@ /* eslint-disable space-before-function-paren, no-var, comma-dangle, no-return-assign, padded-blocks, max-len */ -require('../spec_helper'); require('behaviors/autosize'); (function() { diff --git a/spec/javascripts/behaviors/quick_submit_spec.js b/spec/javascripts/behaviors/quick_submit_spec.js index f7bf95daa6c..c7c6f6393a6 100644 --- a/spec/javascripts/behaviors/quick_submit_spec.js +++ b/spec/javascripts/behaviors/quick_submit_spec.js @@ -1,6 +1,5 @@ /* eslint-disable space-before-function-paren, no-var, no-return-assign, comma-dangle, jasmine/no-spec-dupes, new-cap, padded-blocks, max-len */ -require('../spec_helper'); require('behaviors/quick_submit'); (function() { diff --git a/spec/javascripts/behaviors/requires_input_spec.js b/spec/javascripts/behaviors/requires_input_spec.js index 40a113cded3..793405cd197 100644 --- a/spec/javascripts/behaviors/requires_input_spec.js +++ b/spec/javascripts/behaviors/requires_input_spec.js @@ -1,6 +1,5 @@ /* eslint-disable space-before-function-paren, no-var, padded-blocks */ -require('../spec_helper'); require('behaviors/requires_input'); (function() { diff --git a/spec/javascripts/boards/boards_store_spec.js.es6 b/spec/javascripts/boards/boards_store_spec.js.es6 index c8de9ad79c3..7817e7c1b92 100644 --- a/spec/javascripts/boards/boards_store_spec.js.es6 +++ b/spec/javascripts/boards/boards_store_spec.js.es6 @@ -6,7 +6,6 @@ /* global listObj */ /* global listObjDuplicate */ -require('../spec_helper'); require('jquery-ujs'); window.Cookies = require('vendor/js.cookie'); window.Vue = require('vue'); diff --git a/spec/javascripts/boards/issue_spec.js.es6 b/spec/javascripts/boards/issue_spec.js.es6 index 143315e4ac1..cf2485bff8d 100644 --- a/spec/javascripts/boards/issue_spec.js.es6 +++ b/spec/javascripts/boards/issue_spec.js.es6 @@ -2,7 +2,6 @@ /* global BoardService */ /* global ListIssue */ -require('../spec_helper'); require('jquery-ujs'); window.Cookies = require('vendor/js.cookie'); window.Vue = require('vue'); diff --git a/spec/javascripts/boards/list_spec.js.es6 b/spec/javascripts/boards/list_spec.js.es6 index ab04e7b5896..65094642b64 100644 --- a/spec/javascripts/boards/list_spec.js.es6 +++ b/spec/javascripts/boards/list_spec.js.es6 @@ -5,7 +5,6 @@ /* global List */ /* global listObj */ -require('../spec_helper'); require('jquery-ujs'); window.Cookies = require('vendor/js.cookie'); window.Vue = require('vue'); diff --git a/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 b/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 index b6d223dcb80..f73bb5c6fed 100644 --- a/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 +++ b/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 @@ -1,4 +1,3 @@ -require('./spec_helper'); require('lib/utils/bootstrap_linked_tabs'); (() => { diff --git a/spec/javascripts/build_spec.js.es6 b/spec/javascripts/build_spec.js.es6 index 1821c44fdfb..41a3e614cd1 100644 --- a/spec/javascripts/build_spec.js.es6 +++ b/spec/javascripts/build_spec.js.es6 @@ -2,7 +2,6 @@ /* global Build */ /* global Turbolinks */ -require('./spec_helper'); require('lib/utils/datetime_utility'); require('build'); require('breakpoints'); diff --git a/spec/javascripts/dashboard_spec.js.es6 b/spec/javascripts/dashboard_spec.js.es6 index 7e9e622970d..5fb101fd584 100644 --- a/spec/javascripts/dashboard_spec.js.es6 +++ b/spec/javascripts/dashboard_spec.js.es6 @@ -1,6 +1,5 @@ /* eslint-disable no-new, padded-blocks */ -require('./spec_helper'); require('sidebar'); window.Cookies = require('vendor/js.cookie'); require('lib/utils/text_utility'); diff --git a/spec/javascripts/datetime_utility_spec.js.es6 b/spec/javascripts/datetime_utility_spec.js.es6 index d4f27d2691a..713e7742988 100644 --- a/spec/javascripts/datetime_utility_spec.js.es6 +++ b/spec/javascripts/datetime_utility_spec.js.es6 @@ -1,4 +1,3 @@ -require('./spec_helper'); require('lib/utils/datetime_utility'); (() => { diff --git a/spec/javascripts/diff_comments_store_spec.js.es6 b/spec/javascripts/diff_comments_store_spec.js.es6 index 487f1ab8b5d..f27ba0f93f7 100644 --- a/spec/javascripts/diff_comments_store_spec.js.es6 +++ b/spec/javascripts/diff_comments_store_spec.js.es6 @@ -1,7 +1,6 @@ /* eslint-disable no-extra-semi, jasmine/no-global-setup, dot-notation, jasmine/no-expect-in-setup-teardown, max-len */ /* global CommentsStore */ -require('./spec_helper'); require('diff_notes/models/discussion'); require('diff_notes/models/note'); require('diff_notes/stores/comments'); diff --git a/spec/javascripts/environments/environment_actions_spec.js.es6 b/spec/javascripts/environments/environment_actions_spec.js.es6 index 8d3539b29a5..304c3dccd1e 100644 --- a/spec/javascripts/environments/environment_actions_spec.js.es6 +++ b/spec/javascripts/environments/environment_actions_spec.js.es6 @@ -1,4 +1,3 @@ -require('../spec_helper'); window.Vue = require('vue'); require('environments/components/environment_actions'); diff --git a/spec/javascripts/environments/environment_external_url_spec.js.es6 b/spec/javascripts/environments/environment_external_url_spec.js.es6 index 01264781a68..d50971583a1 100644 --- a/spec/javascripts/environments/environment_external_url_spec.js.es6 +++ b/spec/javascripts/environments/environment_external_url_spec.js.es6 @@ -1,4 +1,3 @@ -require('../spec_helper'); window.Vue = require('vue'); require('environments/components/environment_external_url'); diff --git a/spec/javascripts/environments/environment_item_spec.js.es6 b/spec/javascripts/environments/environment_item_spec.js.es6 index 56c718eb501..f6079afd617 100644 --- a/spec/javascripts/environments/environment_item_spec.js.es6 +++ b/spec/javascripts/environments/environment_item_spec.js.es6 @@ -1,4 +1,3 @@ -require('../spec_helper'); window.Vue = require('vue'); window.timeago = require('vendor/timeago'); require('environments/components/environment_item'); diff --git a/spec/javascripts/environments/environment_rollback_spec.js.es6 b/spec/javascripts/environments/environment_rollback_spec.js.es6 index 5c378901608..87ffd76c152 100644 --- a/spec/javascripts/environments/environment_rollback_spec.js.es6 +++ b/spec/javascripts/environments/environment_rollback_spec.js.es6 @@ -1,4 +1,3 @@ -require('../spec_helper'); window.Vue = require('vue'); require('environments/components/environment_rollback'); diff --git a/spec/javascripts/environments/environment_stop_spec.js.es6 b/spec/javascripts/environments/environment_stop_spec.js.es6 index 96c738f42d6..b0b8f355fde 100644 --- a/spec/javascripts/environments/environment_stop_spec.js.es6 +++ b/spec/javascripts/environments/environment_stop_spec.js.es6 @@ -1,4 +1,3 @@ -require('../spec_helper'); window.Vue = require('vue'); require('environments/components/environment_stop'); diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 index 8c113b5679e..bcbe214eb05 100644 --- a/spec/javascripts/environments/environments_store_spec.js.es6 +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -1,6 +1,5 @@ /* global environmentsList */ -require('../spec_helper'); window.Vue = require('vue'); require('environments/stores/environments_store'); require('./mock_data'); diff --git a/spec/javascripts/extensions/array_spec.js.es6 b/spec/javascripts/extensions/array_spec.js.es6 index f35cda4cac7..5396e0eb639 100644 --- a/spec/javascripts/extensions/array_spec.js.es6 +++ b/spec/javascripts/extensions/array_spec.js.es6 @@ -1,6 +1,5 @@ /* eslint-disable space-before-function-paren, no-var, padded-blocks */ -require('../spec_helper'); require('extensions/array'); (function() { diff --git a/spec/javascripts/extensions/element_spec.js.es6 b/spec/javascripts/extensions/element_spec.js.es6 index fddd7600cb9..49544ae8b5c 100644 --- a/spec/javascripts/extensions/element_spec.js.es6 +++ b/spec/javascripts/extensions/element_spec.js.es6 @@ -1,4 +1,3 @@ -require('../spec_helper'); require('extensions/element'); (() => { diff --git a/spec/javascripts/extensions/jquery_spec.js b/spec/javascripts/extensions/jquery_spec.js index 5f5bca4bc06..3163414b134 100644 --- a/spec/javascripts/extensions/jquery_spec.js +++ b/spec/javascripts/extensions/jquery_spec.js @@ -1,6 +1,5 @@ /* eslint-disable space-before-function-paren, no-var, padded-blocks */ -require('../spec_helper'); require('extensions/jquery'); (function() { diff --git a/spec/javascripts/extensions/object_spec.js.es6 b/spec/javascripts/extensions/object_spec.js.es6 index 25707be7bb4..77ffa1a35ae 100644 --- a/spec/javascripts/extensions/object_spec.js.es6 +++ b/spec/javascripts/extensions/object_spec.js.es6 @@ -1,4 +1,3 @@ -require('../spec_helper'); require('extensions/object'); describe('Object extensions', () => { diff --git a/spec/javascripts/gl_dropdown_spec.js.es6 b/spec/javascripts/gl_dropdown_spec.js.es6 index 7b2b4771756..1f4d7a4eb07 100644 --- a/spec/javascripts/gl_dropdown_spec.js.es6 +++ b/spec/javascripts/gl_dropdown_spec.js.es6 @@ -1,7 +1,6 @@ /* eslint-disable comma-dangle, prefer-const, no-param-reassign, no-plusplus, semi, no-unused-expressions, arrow-spacing, max-len */ /* global Turbolinks */ -require('./spec_helper'); require('gl_dropdown'); require('lib/utils/common_utils'); require('lib/utils/type_utility'); diff --git a/spec/javascripts/gl_field_errors_spec.js.es6 b/spec/javascripts/gl_field_errors_spec.js.es6 index 763e1bb5685..53f7e576394 100644 --- a/spec/javascripts/gl_field_errors_spec.js.es6 +++ b/spec/javascripts/gl_field_errors_spec.js.es6 @@ -1,6 +1,5 @@ /* eslint-disable space-before-function-paren, arrow-body-style, indent, padded-blocks */ -require('./spec_helper'); require('gl_field_errors'); ((global) => { diff --git a/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js b/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js index b4d278dfe88..a914eda90bb 100644 --- a/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js +++ b/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js @@ -3,7 +3,6 @@ /* global ContributorsGraph */ /* global ContributorsMasterGraph */ -require('../spec_helper'); require('graphs/stat_graph_contributors_graph'); describe("ContributorsGraph", function () { diff --git a/spec/javascripts/graphs/stat_graph_contributors_util_spec.js b/spec/javascripts/graphs/stat_graph_contributors_util_spec.js index 8323fcff02d..4f82e1c46db 100644 --- a/spec/javascripts/graphs/stat_graph_contributors_util_spec.js +++ b/spec/javascripts/graphs/stat_graph_contributors_util_spec.js @@ -1,7 +1,6 @@ /* eslint-disable quotes, padded-blocks, no-var, camelcase, object-curly-spacing, semi, indent, object-property-newline, comma-dangle, comma-spacing, spaced-comment, max-len, key-spacing, vars-on-top, quote-props, no-multi-spaces */ /* global ContributorsStatGraphUtil */ -require('../spec_helper'); require('graphs/stat_graph_contributors_util'); describe("ContributorsStatGraphUtil", function () { diff --git a/spec/javascripts/graphs/stat_graph_spec.js b/spec/javascripts/graphs/stat_graph_spec.js index 66c8c16a40f..a017f35831d 100644 --- a/spec/javascripts/graphs/stat_graph_spec.js +++ b/spec/javascripts/graphs/stat_graph_spec.js @@ -1,7 +1,6 @@ /* eslint-disable quotes, padded-blocks, semi */ /* global StatGraph */ -require('../spec_helper'); require('graphs/stat_graph'); describe("StatGraph", function () { diff --git a/spec/javascripts/header_spec.js b/spec/javascripts/header_spec.js index 4e93e33d432..570d0ab78cb 100644 --- a/spec/javascripts/header_spec.js +++ b/spec/javascripts/header_spec.js @@ -1,6 +1,5 @@ /* eslint-disable space-before-function-paren, padded-blocks, no-var */ -require('./spec_helper'); require('header'); require('lib/utils/text_utility'); diff --git a/spec/javascripts/issuable_spec.js.es6 b/spec/javascripts/issuable_spec.js.es6 index 5d3269626af..eaf155f1606 100644 --- a/spec/javascripts/issuable_spec.js.es6 +++ b/spec/javascripts/issuable_spec.js.es6 @@ -1,7 +1,6 @@ /* global Issuable */ /* global Turbolinks */ -require('./spec_helper'); require('issuable'); (() => { diff --git a/spec/javascripts/issue_spec.js b/spec/javascripts/issue_spec.js index 126b3682d5d..2938d69e94c 100644 --- a/spec/javascripts/issue_spec.js +++ b/spec/javascripts/issue_spec.js @@ -1,7 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-use-before-define, indent, no-trailing-spaces, comma-dangle, padded-blocks, max-len */ /* global Issue */ -require('./spec_helper'); require('lib/utils/text_utility'); require('issue'); diff --git a/spec/javascripts/labels_issue_sidebar_spec.js.es6 b/spec/javascripts/labels_issue_sidebar_spec.js.es6 index 885e975c32b..ac3b4e8e0f6 100644 --- a/spec/javascripts/labels_issue_sidebar_spec.js.es6 +++ b/spec/javascripts/labels_issue_sidebar_spec.js.es6 @@ -2,7 +2,6 @@ /* global IssuableContext */ /* global LabelsSelect */ -require('./spec_helper'); require('lib/utils/type_utility'); require('gl_dropdown'); require('select2'); diff --git a/spec/javascripts/lib/utils/common_utils_spec.js.es6 b/spec/javascripts/lib/utils/common_utils_spec.js.es6 index 02aabf202d0..46aa0702bda 100644 --- a/spec/javascripts/lib/utils/common_utils_spec.js.es6 +++ b/spec/javascripts/lib/utils/common_utils_spec.js.es6 @@ -1,4 +1,3 @@ -require('../../spec_helper'); require('lib/utils/common_utils'); (() => { diff --git a/spec/javascripts/line_highlighter_spec.js b/spec/javascripts/line_highlighter_spec.js index fb549b846e0..afc51e6682a 100644 --- a/spec/javascripts/line_highlighter_spec.js +++ b/spec/javascripts/line_highlighter_spec.js @@ -1,7 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, no-param-reassign, quotes, prefer-template, no-else-return, new-cap, dot-notation, no-return-assign, comma-dangle, no-new, one-var, one-var-declaration-per-line, no-plusplus, jasmine/no-spec-dupes, no-underscore-dangle, padded-blocks, max-len */ /* global LineHighlighter */ -require('./spec_helper'); require('line_highlighter'); (function() { diff --git a/spec/javascripts/merge_request_spec.js b/spec/javascripts/merge_request_spec.js index bbfa6aa67a5..5f98edc3bb0 100644 --- a/spec/javascripts/merge_request_spec.js +++ b/spec/javascripts/merge_request_spec.js @@ -1,7 +1,6 @@ /* eslint-disable space-before-function-paren, no-return-assign, padded-blocks */ /* global MergeRequest */ -require('./spec_helper'); require('merge_request'); (function() { diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js index a8fa47cdd57..5f53334f44c 100644 --- a/spec/javascripts/merge_request_tabs_spec.js +++ b/spec/javascripts/merge_request_tabs_spec.js @@ -1,6 +1,5 @@ /* eslint-disable no-var, comma-dangle, object-shorthand */ -require('./spec_helper'); require('merge_request_tabs'); require('breakpoints'); require('lib/utils/common_utils'); diff --git a/spec/javascripts/merge_request_widget_spec.js b/spec/javascripts/merge_request_widget_spec.js index 0ec119c94b3..b29f5bad234 100644 --- a/spec/javascripts/merge_request_widget_spec.js +++ b/spec/javascripts/merge_request_widget_spec.js @@ -1,6 +1,5 @@ /* eslint-disable space-before-function-paren, quotes, comma-dangle, dot-notation, indent, quote-props, no-var, padded-blocks, max-len */ -require('./spec_helper'); require('merge_request_widget'); require('lib/utils/datetime_utility'); diff --git a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 index 1faa1f88d70..32b80a4f4bd 100644 --- a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 +++ b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 @@ -1,6 +1,5 @@ /* eslint-disable no-new */ -require('./spec_helper'); require('flash'); require('mini_pipeline_graph_dropdown'); diff --git a/spec/javascripts/new_branch_spec.js b/spec/javascripts/new_branch_spec.js index 8d8c8ec9b0d..40c6b6d3999 100644 --- a/spec/javascripts/new_branch_spec.js +++ b/spec/javascripts/new_branch_spec.js @@ -1,7 +1,6 @@ /* eslint-disable space-before-function-paren, one-var, no-var, one-var-declaration-per-line, no-return-assign, quotes, padded-blocks, max-len */ /* global NewBranchForm */ -require('./spec_helper'); require('jquery-ui/ui/autocomplete'); require('new_branch_form'); diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js index 75f5192a54e..0b2ac007495 100644 --- a/spec/javascripts/notes_spec.js +++ b/spec/javascripts/notes_spec.js @@ -1,7 +1,6 @@ /* eslint-disable space-before-function-paren, no-unused-expressions, no-var, object-shorthand, comma-dangle, semi, padded-blocks, max-len */ /* global Notes */ -require('./spec_helper'); require('notes'); require('vendor/autosize'); require('gl_form'); diff --git a/spec/javascripts/pipelines_spec.js.es6 b/spec/javascripts/pipelines_spec.js.es6 index e51977ab720..1bee64b814f 100644 --- a/spec/javascripts/pipelines_spec.js.es6 +++ b/spec/javascripts/pipelines_spec.js.es6 @@ -1,4 +1,3 @@ -require('./spec_helper'); require('pipelines'); (() => { diff --git a/spec/javascripts/pretty_time_spec.js.es6 b/spec/javascripts/pretty_time_spec.js.es6 index 249aa4817e9..207d40983b4 100644 --- a/spec/javascripts/pretty_time_spec.js.es6 +++ b/spec/javascripts/pretty_time_spec.js.es6 @@ -1,4 +1,3 @@ -require('./spec_helper'); require('lib/utils/pretty_time'); (() => { diff --git a/spec/javascripts/project_title_spec.js b/spec/javascripts/project_title_spec.js index a438b01fbce..a774b978458 100644 --- a/spec/javascripts/project_title_spec.js +++ b/spec/javascripts/project_title_spec.js @@ -1,7 +1,6 @@ /* eslint-disable space-before-function-paren, no-unused-expressions, no-return-assign, no-param-reassign, no-var, new-cap, wrap-iife, no-unused-vars, quotes, jasmine/no-expect-in-setup-teardown, padded-blocks, max-len */ /* global Project */ -require('./spec_helper'); require('select2/select2.js'); require('lib/utils/type_utility'); require('gl_dropdown'); diff --git a/spec/javascripts/right_sidebar_spec.js b/spec/javascripts/right_sidebar_spec.js index 65730b42ea3..026ae04eb21 100644 --- a/spec/javascripts/right_sidebar_spec.js +++ b/spec/javascripts/right_sidebar_spec.js @@ -1,7 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, new-parens, no-return-assign, new-cap, vars-on-top, semi, padded-blocks, max-len */ /* global Sidebar */ -require('./spec_helper'); require('right_sidebar'); window.Cookies = require('vendor/js.cookie'); require('extensions/jquery.js'); diff --git a/spec/javascripts/search_autocomplete_spec.js b/spec/javascripts/search_autocomplete_spec.js index 4ac9117fd8a..8d7f48eabc5 100644 --- a/spec/javascripts/search_autocomplete_spec.js +++ b/spec/javascripts/search_autocomplete_spec.js @@ -1,6 +1,5 @@ /* eslint-disable space-before-function-paren, max-len, no-var, one-var, one-var-declaration-per-line, no-unused-expressions, consistent-return, no-param-reassign, default-case, no-return-assign, comma-dangle, object-shorthand, prefer-template, quotes, new-parens, vars-on-top, new-cap, padded-blocks, max-len */ -require('./spec_helper'); require('gl_dropdown'); require('search_autocomplete'); require('lib/utils/common_utils'); diff --git a/spec/javascripts/shortcuts_issuable_spec.js b/spec/javascripts/shortcuts_issuable_spec.js index e6605c46bfc..65c4f42e3b8 100644 --- a/spec/javascripts/shortcuts_issuable_spec.js +++ b/spec/javascripts/shortcuts_issuable_spec.js @@ -1,7 +1,6 @@ /* eslint-disable space-before-function-paren, no-return-assign, no-var, quotes, padded-blocks */ /* global ShortcutsIssuable */ -require('./spec_helper'); require('shortcuts_issuable'); (function() { diff --git a/spec/javascripts/signin_tabs_memoizer_spec.js.es6 b/spec/javascripts/signin_tabs_memoizer_spec.js.es6 index f7aa3e663f9..b34942d78d1 100644 --- a/spec/javascripts/signin_tabs_memoizer_spec.js.es6 +++ b/spec/javascripts/signin_tabs_memoizer_spec.js.es6 @@ -1,4 +1,3 @@ -require('./spec_helper'); require('signin_tabs_memoizer'); ((global) => { diff --git a/spec/javascripts/smart_interval_spec.js.es6 b/spec/javascripts/smart_interval_spec.js.es6 index 23cf8689585..3075965d7f9 100644 --- a/spec/javascripts/smart_interval_spec.js.es6 +++ b/spec/javascripts/smart_interval_spec.js.es6 @@ -1,4 +1,3 @@ -require('./spec_helper'); require('smart_interval'); (() => { diff --git a/spec/javascripts/subbable_resource_spec.js.es6 b/spec/javascripts/subbable_resource_spec.js.es6 index a70a1419792..1434ae8364d 100644 --- a/spec/javascripts/subbable_resource_spec.js.es6 +++ b/spec/javascripts/subbable_resource_spec.js.es6 @@ -1,6 +1,5 @@ /* eslint-disable max-len, arrow-parens, comma-dangle, no-plusplus */ -require('./spec_helper'); require('subbable_resource'); /* diff --git a/spec/javascripts/syntax_highlight_spec.js b/spec/javascripts/syntax_highlight_spec.js index c06339fa709..b5e869e2169 100644 --- a/spec/javascripts/syntax_highlight_spec.js +++ b/spec/javascripts/syntax_highlight_spec.js @@ -1,6 +1,5 @@ /* eslint-disable space-before-function-paren, no-var, no-return-assign, quotes, padded-blocks */ -require('./spec_helper'); require('syntax_highlight'); (function() { diff --git a/spec/javascripts/u2f/authenticate_spec.js b/spec/javascripts/u2f/authenticate_spec.js index a14f0e3c448..22cea407943 100644 --- a/spec/javascripts/u2f/authenticate_spec.js +++ b/spec/javascripts/u2f/authenticate_spec.js @@ -2,7 +2,6 @@ /* global MockU2FDevice */ /* global U2FAuthenticate */ -require('../spec_helper'); require('u2f/authenticate'); require('u2f/util'); require('u2f/error'); diff --git a/spec/javascripts/u2f/register_spec.js b/spec/javascripts/u2f/register_spec.js index 157c8796fd5..17b3732975b 100644 --- a/spec/javascripts/u2f/register_spec.js +++ b/spec/javascripts/u2f/register_spec.js @@ -2,7 +2,6 @@ /* global MockU2FDevice */ /* global U2FRegister */ -require('../spec_helper'); require('u2f/register'); require('u2f/util'); require('u2f/error'); diff --git a/spec/javascripts/vue_common_components/commit_spec.js.es6 b/spec/javascripts/vue_common_components/commit_spec.js.es6 index 28ffc005001..12d8c411847 100644 --- a/spec/javascripts/vue_common_components/commit_spec.js.es6 +++ b/spec/javascripts/vue_common_components/commit_spec.js.es6 @@ -1,4 +1,3 @@ -require('../spec_helper'); require('vue_common_component/commit'); describe('Commit component', () => { diff --git a/spec/javascripts/zen_mode_spec.js b/spec/javascripts/zen_mode_spec.js index 2c790b193b0..7fe2ab68c75 100644 --- a/spec/javascripts/zen_mode_spec.js +++ b/spec/javascripts/zen_mode_spec.js @@ -3,7 +3,6 @@ /* global Mousetrap */ /* global ZenMode */ -require('./spec_helper'); require('zen_mode'); (function() { -- cgit v1.2.1 From b0341c14d0657b41203b7e5d6d6cbeb64d67b387 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 6 Jan 2017 17:30:54 -0600 Subject: move additional libraries into spec_helper --- spec/javascripts/activities_spec.js.es6 | 1 - spec/javascripts/awards_handler_spec.js | 1 - spec/javascripts/boards/boards_store_spec.js.es6 | 4 ---- spec/javascripts/boards/issue_spec.js.es6 | 4 ---- spec/javascripts/boards/list_spec.js.es6 | 4 ---- spec/javascripts/dashboard_spec.js.es6 | 1 - spec/javascripts/environments/environment_actions_spec.js.es6 | 1 - spec/javascripts/environments/environment_external_url_spec.js.es6 | 1 - spec/javascripts/environments/environment_item_spec.js.es6 | 1 - spec/javascripts/environments/environment_rollback_spec.js.es6 | 1 - spec/javascripts/environments/environment_stop_spec.js.es6 | 1 - spec/javascripts/environments/environments_store_spec.js.es6 | 1 - spec/javascripts/right_sidebar_spec.js | 1 - spec/javascripts/spec_helper.js | 4 ++++ 14 files changed, 4 insertions(+), 22 deletions(-) diff --git a/spec/javascripts/activities_spec.js.es6 b/spec/javascripts/activities_spec.js.es6 index feba184dbb0..cf57ca34a79 100644 --- a/spec/javascripts/activities_spec.js.es6 +++ b/spec/javascripts/activities_spec.js.es6 @@ -1,6 +1,5 @@ /* eslint-disable no-unused-expressions, comma-spacing, prefer-const, no-prototype-builtins, semi, no-new, keyword-spacing, no-plusplus, no-shadow, max-len */ -window.Cookies = require('vendor/js.cookie'); require('vendor/jquery.endless-scroll.js'); require('pager'); require('activities'); diff --git a/spec/javascripts/awards_handler_spec.js b/spec/javascripts/awards_handler_spec.js index 65efa3df90b..6950e7a2ce4 100644 --- a/spec/javascripts/awards_handler_spec.js +++ b/spec/javascripts/awards_handler_spec.js @@ -2,7 +2,6 @@ /* global AwardsHandler */ require('awards_handler'); -window.Cookies = require('vendor/js.cookie'); require('./fixtures/emoji_menu'); (function() { diff --git a/spec/javascripts/boards/boards_store_spec.js.es6 b/spec/javascripts/boards/boards_store_spec.js.es6 index 7817e7c1b92..a94f107f67c 100644 --- a/spec/javascripts/boards/boards_store_spec.js.es6 +++ b/spec/javascripts/boards/boards_store_spec.js.es6 @@ -6,10 +6,6 @@ /* global listObj */ /* global listObjDuplicate */ -require('jquery-ujs'); -window.Cookies = require('vendor/js.cookie'); -window.Vue = require('vue'); -window.Vue.use(require('vue-resource')); require('lib/utils/url_utility'); require('boards/models/issue'); require('boards/models/label'); diff --git a/spec/javascripts/boards/issue_spec.js.es6 b/spec/javascripts/boards/issue_spec.js.es6 index cf2485bff8d..2f38bea7d48 100644 --- a/spec/javascripts/boards/issue_spec.js.es6 +++ b/spec/javascripts/boards/issue_spec.js.es6 @@ -2,10 +2,6 @@ /* global BoardService */ /* global ListIssue */ -require('jquery-ujs'); -window.Cookies = require('vendor/js.cookie'); -window.Vue = require('vue'); -window.Vue.use(require('vue-resource')); require('lib/utils/url_utility'); require('boards/models/issue'); require('boards/models/label'); diff --git a/spec/javascripts/boards/list_spec.js.es6 b/spec/javascripts/boards/list_spec.js.es6 index 65094642b64..edd472573de 100644 --- a/spec/javascripts/boards/list_spec.js.es6 +++ b/spec/javascripts/boards/list_spec.js.es6 @@ -5,10 +5,6 @@ /* global List */ /* global listObj */ -require('jquery-ujs'); -window.Cookies = require('vendor/js.cookie'); -window.Vue = require('vue'); -window.Vue.use(require('vue-resource')); require('lib/utils/url_utility'); require('boards/models/issue'); require('boards/models/label'); diff --git a/spec/javascripts/dashboard_spec.js.es6 b/spec/javascripts/dashboard_spec.js.es6 index 5fb101fd584..b9e819aa218 100644 --- a/spec/javascripts/dashboard_spec.js.es6 +++ b/spec/javascripts/dashboard_spec.js.es6 @@ -1,7 +1,6 @@ /* eslint-disable no-new, padded-blocks */ require('sidebar'); -window.Cookies = require('vendor/js.cookie'); require('lib/utils/text_utility'); ((global) => { diff --git a/spec/javascripts/environments/environment_actions_spec.js.es6 b/spec/javascripts/environments/environment_actions_spec.js.es6 index 304c3dccd1e..c02c2e10b9a 100644 --- a/spec/javascripts/environments/environment_actions_spec.js.es6 +++ b/spec/javascripts/environments/environment_actions_spec.js.es6 @@ -1,4 +1,3 @@ -window.Vue = require('vue'); require('environments/components/environment_actions'); describe('Actions Component', () => { diff --git a/spec/javascripts/environments/environment_external_url_spec.js.es6 b/spec/javascripts/environments/environment_external_url_spec.js.es6 index d50971583a1..5270ebef0ae 100644 --- a/spec/javascripts/environments/environment_external_url_spec.js.es6 +++ b/spec/javascripts/environments/environment_external_url_spec.js.es6 @@ -1,4 +1,3 @@ -window.Vue = require('vue'); require('environments/components/environment_external_url'); describe('External URL Component', () => { diff --git a/spec/javascripts/environments/environment_item_spec.js.es6 b/spec/javascripts/environments/environment_item_spec.js.es6 index f6079afd617..400850db028 100644 --- a/spec/javascripts/environments/environment_item_spec.js.es6 +++ b/spec/javascripts/environments/environment_item_spec.js.es6 @@ -1,4 +1,3 @@ -window.Vue = require('vue'); window.timeago = require('vendor/timeago'); require('environments/components/environment_item'); diff --git a/spec/javascripts/environments/environment_rollback_spec.js.es6 b/spec/javascripts/environments/environment_rollback_spec.js.es6 index 87ffd76c152..96d80d59b9a 100644 --- a/spec/javascripts/environments/environment_rollback_spec.js.es6 +++ b/spec/javascripts/environments/environment_rollback_spec.js.es6 @@ -1,4 +1,3 @@ -window.Vue = require('vue'); require('environments/components/environment_rollback'); describe('Rollback Component', () => { diff --git a/spec/javascripts/environments/environment_stop_spec.js.es6 b/spec/javascripts/environments/environment_stop_spec.js.es6 index b0b8f355fde..a243b967425 100644 --- a/spec/javascripts/environments/environment_stop_spec.js.es6 +++ b/spec/javascripts/environments/environment_stop_spec.js.es6 @@ -1,4 +1,3 @@ -window.Vue = require('vue'); require('environments/components/environment_stop'); describe('Stop Component', () => { diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 index bcbe214eb05..090179ce873 100644 --- a/spec/javascripts/environments/environments_store_spec.js.es6 +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -1,6 +1,5 @@ /* global environmentsList */ -window.Vue = require('vue'); require('environments/stores/environments_store'); require('./mock_data'); diff --git a/spec/javascripts/right_sidebar_spec.js b/spec/javascripts/right_sidebar_spec.js index 026ae04eb21..db6b7244135 100644 --- a/spec/javascripts/right_sidebar_spec.js +++ b/spec/javascripts/right_sidebar_spec.js @@ -2,7 +2,6 @@ /* global Sidebar */ require('right_sidebar'); -window.Cookies = require('vendor/js.cookie'); require('extensions/jquery.js'); (function() { diff --git a/spec/javascripts/spec_helper.js b/spec/javascripts/spec_helper.js index 64f1ca4b80d..b55f08e3311 100644 --- a/spec/javascripts/spec_helper.js +++ b/spec/javascripts/spec_helper.js @@ -3,6 +3,10 @@ require('jasmine-jquery'); // include common libraries window.$ = window.jQuery = require('jquery'); window._ = require('underscore'); +window.Cookies = require('vendor/js.cookie'); +window.Vue = require('vue'); +window.Vue.use(require('vue-resource')); +require('jquery-ujs'); require('vendor/turbolinks'); require('vendor/jquery.turbolinks'); require('bootstrap/js/affix'); -- cgit v1.2.1 From a8078d629e50ec1ea0e562e24e7bd7ea8931d896 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 6 Jan 2017 18:19:42 -0600 Subject: migrate all tests into a single webpack bundle --- config/karma.config.js | 3 +-- spec/javascripts/.eslintrc | 5 +++-- spec/javascripts/spec_helper.js | 31 ------------------------------ spec/javascripts/test_bundle.js | 42 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 46 insertions(+), 35 deletions(-) delete mode 100644 spec/javascripts/spec_helper.js create mode 100644 spec/javascripts/test_bundle.js diff --git a/config/karma.config.js b/config/karma.config.js index 96d33490b37..b317c3f00b2 100644 --- a/config/karma.config.js +++ b/config/karma.config.js @@ -8,8 +8,7 @@ module.exports = function(config) { basePath: ROOT_PATH, frameworks: ['jasmine'], files: [ - 'spec/javascripts/spec_helper.js', - 'spec/javascripts/**/*_spec.js?(.es6)', + 'spec/javascripts/test_bundle.js', { pattern: 'spec/javascripts/fixtures/**/*@(.json|.html|.html.raw)', included: false }, ], preprocessors: { diff --git a/spec/javascripts/.eslintrc b/spec/javascripts/.eslintrc index dcbcd014dc3..b3d191e15ab 100644 --- a/spec/javascripts/.eslintrc +++ b/spec/javascripts/.eslintrc @@ -22,7 +22,8 @@ }, "plugins": ["jasmine"], "rules": { - "prefer-arrow-callback": 0, - "func-names": 0 + "func-names": 0, + "no-console": 0, + "prefer-arrow-callback": 0 } } diff --git a/spec/javascripts/spec_helper.js b/spec/javascripts/spec_helper.js deleted file mode 100644 index b55f08e3311..00000000000 --- a/spec/javascripts/spec_helper.js +++ /dev/null @@ -1,31 +0,0 @@ -require('jasmine-jquery'); - -// include common libraries -window.$ = window.jQuery = require('jquery'); -window._ = require('underscore'); -window.Cookies = require('vendor/js.cookie'); -window.Vue = require('vue'); -window.Vue.use(require('vue-resource')); -require('jquery-ujs'); -require('vendor/turbolinks'); -require('vendor/jquery.turbolinks'); -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'); - -// configure jasmine -jasmine.getFixtures().fixturesPath = 'base/spec/javascripts/fixtures'; -jasmine.getJSONFixtures().fixturesPath = 'base/spec/javascripts/fixtures'; - -// stub expected globals -window.gl = window.gl || {}; -window.gl.TEST_HOST = 'http://test.host'; -window.gon = window.gon || {}; diff --git a/spec/javascripts/test_bundle.js b/spec/javascripts/test_bundle.js new file mode 100644 index 00000000000..cbe8abbbc08 --- /dev/null +++ b/spec/javascripts/test_bundle.js @@ -0,0 +1,42 @@ +// enable test fixtures +require('jasmine-jquery'); + +jasmine.getFixtures().fixturesPath = 'base/spec/javascripts/fixtures'; +jasmine.getJSONFixtures().fixturesPath = 'base/spec/javascripts/fixtures'; + +// include common libraries +window.$ = window.jQuery = require('jquery'); +window._ = require('underscore'); +window.Cookies = require('vendor/js.cookie'); +window.Vue = require('vue'); +window.Vue.use(require('vue-resource')); +require('jquery-ujs'); +require('vendor/turbolinks'); +require('vendor/jquery.turbolinks'); +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'); + +// stub expected globals +window.gl = window.gl || {}; +window.gl.TEST_HOST = 'http://test.host'; +window.gon = window.gon || {}; + +// render all of our tests +const testsContext = require.context('.', true, /_spec$/); +testsContext.keys().forEach(function (path) { + try { + testsContext(path); + } catch (err) { + console.error('[ERROR] WITH SPEC FILE: ', path); + console.error(err); + } +}); -- cgit v1.2.1 From 8d2099cb53e933e94ebc17e9c186c0f4ece107cb Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Mon, 9 Jan 2017 17:23:54 -0600 Subject: use ~ to reference non-local scripts instead of resolve.root --- config/webpack.config.js | 6 ++---- spec/javascripts/abuse_reports_spec.js.es6 | 4 ++-- spec/javascripts/activities_spec.js.es6 | 4 ++-- spec/javascripts/awards_handler_spec.js | 2 +- spec/javascripts/behaviors/autosize_spec.js | 2 +- spec/javascripts/behaviors/quick_submit_spec.js | 2 +- spec/javascripts/behaviors/requires_input_spec.js | 2 +- spec/javascripts/boards/boards_store_spec.js.es6 | 14 +++++++------- spec/javascripts/boards/issue_spec.js.es6 | 14 +++++++------- spec/javascripts/boards/list_spec.js.es6 | 14 +++++++------- spec/javascripts/bootstrap_linked_tabs_spec.js.es6 | 2 +- spec/javascripts/build_spec.js.es6 | 6 +++--- spec/javascripts/dashboard_spec.js.es6 | 4 ++-- spec/javascripts/datetime_utility_spec.js.es6 | 2 +- spec/javascripts/diff_comments_store_spec.js.es6 | 6 +++--- .../environments/environment_actions_spec.js.es6 | 2 +- .../environments/environment_external_url_spec.js.es6 | 2 +- spec/javascripts/environments/environment_item_spec.js.es6 | 2 +- .../environments/environment_rollback_spec.js.es6 | 2 +- spec/javascripts/environments/environment_stop_spec.js.es6 | 2 +- .../environments/environments_store_spec.js.es6 | 2 +- spec/javascripts/extensions/array_spec.js.es6 | 2 +- spec/javascripts/extensions/element_spec.js.es6 | 2 +- spec/javascripts/extensions/jquery_spec.js | 2 +- spec/javascripts/extensions/object_spec.js.es6 | 2 +- spec/javascripts/gl_dropdown_spec.js.es6 | 6 +++--- spec/javascripts/gl_field_errors_spec.js.es6 | 2 +- .../graphs/stat_graph_contributors_graph_spec.js | 2 +- .../graphs/stat_graph_contributors_util_spec.js | 2 +- spec/javascripts/graphs/stat_graph_spec.js | 2 +- spec/javascripts/header_spec.js | 4 ++-- spec/javascripts/issuable_spec.js.es6 | 2 +- spec/javascripts/issue_spec.js | 4 ++-- spec/javascripts/labels_issue_sidebar_spec.js.es6 | 14 +++++++------- spec/javascripts/lib/utils/common_utils_spec.js.es6 | 2 +- spec/javascripts/line_highlighter_spec.js | 2 +- spec/javascripts/merge_request_spec.js | 2 +- spec/javascripts/merge_request_tabs_spec.js | 6 +++--- spec/javascripts/merge_request_widget_spec.js | 4 ++-- spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 | 4 ++-- spec/javascripts/new_branch_spec.js | 2 +- spec/javascripts/notes_spec.js | 6 +++--- spec/javascripts/pipelines_spec.js.es6 | 2 +- spec/javascripts/pretty_time_spec.js.es6 | 2 +- spec/javascripts/project_title_spec.js | 10 +++++----- spec/javascripts/right_sidebar_spec.js | 4 ++-- spec/javascripts/search_autocomplete_spec.js | 8 ++++---- spec/javascripts/shortcuts_issuable_spec.js | 2 +- spec/javascripts/signin_tabs_memoizer_spec.js.es6 | 2 +- spec/javascripts/smart_interval_spec.js.es6 | 2 +- spec/javascripts/subbable_resource_spec.js.es6 | 2 +- spec/javascripts/syntax_highlight_spec.js | 2 +- spec/javascripts/u2f/authenticate_spec.js | 6 +++--- spec/javascripts/u2f/register_spec.js | 6 +++--- spec/javascripts/vue_common_components/commit_spec.js.es6 | 2 +- spec/javascripts/zen_mode_spec.js | 2 +- 56 files changed, 110 insertions(+), 112 deletions(-) diff --git a/config/webpack.config.js b/config/webpack.config.js index 8dd9cf5b960..4060228c94b 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -82,15 +82,13 @@ var config = { resolve: { extensions: ['', '.js', '.es6', '.js.es6'], alias: { + '~': path.join(ROOT_PATH, 'app/assets/javascripts'), 'bootstrap/js': 'bootstrap-sass/assets/javascripts/bootstrap', 'emoji-aliases$': path.join(ROOT_PATH, 'fixtures/emojis/aliases.json'), 'vendor': path.join(ROOT_PATH, 'vendor/assets/javascripts'), 'vue$': 'vue/dist/vue.js', 'vue-resource$': 'vue-resource/dist/vue-resource.js' - }, - root: [ - path.join(ROOT_PATH, 'app/assets/javascripts'), - ], + } } } diff --git a/spec/javascripts/abuse_reports_spec.js.es6 b/spec/javascripts/abuse_reports_spec.js.es6 index f4b6c9deae5..6e23a7a0b56 100644 --- a/spec/javascripts/abuse_reports_spec.js.es6 +++ b/spec/javascripts/abuse_reports_spec.js.es6 @@ -1,5 +1,5 @@ -require('lib/utils/text_utility'); -require('abuse_reports'); +require('~/lib/utils/text_utility'); +require('~/abuse_reports'); ((global) => { describe('Abuse Reports', () => { diff --git a/spec/javascripts/activities_spec.js.es6 b/spec/javascripts/activities_spec.js.es6 index cf57ca34a79..aba16a03ce2 100644 --- a/spec/javascripts/activities_spec.js.es6 +++ b/spec/javascripts/activities_spec.js.es6 @@ -1,8 +1,8 @@ /* eslint-disable no-unused-expressions, comma-spacing, prefer-const, no-prototype-builtins, semi, no-new, keyword-spacing, no-plusplus, no-shadow, max-len */ require('vendor/jquery.endless-scroll.js'); -require('pager'); -require('activities'); +require('~/pager'); +require('~/activities'); (() => { window.gon || (window.gon = {}); diff --git a/spec/javascripts/awards_handler_spec.js b/spec/javascripts/awards_handler_spec.js index 6950e7a2ce4..672f6f33ad3 100644 --- a/spec/javascripts/awards_handler_spec.js +++ b/spec/javascripts/awards_handler_spec.js @@ -1,7 +1,7 @@ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-unused-expressions, comma-dangle, new-parens, no-unused-vars, quotes, jasmine/no-spec-dupes, prefer-template, padded-blocks, max-len */ /* global AwardsHandler */ -require('awards_handler'); +require('~/awards_handler'); require('./fixtures/emoji_menu'); (function() { diff --git a/spec/javascripts/behaviors/autosize_spec.js b/spec/javascripts/behaviors/autosize_spec.js index e05793cf2e3..3b29579e70e 100644 --- a/spec/javascripts/behaviors/autosize_spec.js +++ b/spec/javascripts/behaviors/autosize_spec.js @@ -1,6 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, comma-dangle, no-return-assign, padded-blocks, max-len */ -require('behaviors/autosize'); +require('~/behaviors/autosize'); (function() { describe('Autosize behavior', function() { diff --git a/spec/javascripts/behaviors/quick_submit_spec.js b/spec/javascripts/behaviors/quick_submit_spec.js index c7c6f6393a6..247eb5f70ea 100644 --- a/spec/javascripts/behaviors/quick_submit_spec.js +++ b/spec/javascripts/behaviors/quick_submit_spec.js @@ -1,6 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, no-return-assign, comma-dangle, jasmine/no-spec-dupes, new-cap, padded-blocks, max-len */ -require('behaviors/quick_submit'); +require('~/behaviors/quick_submit'); (function() { describe('Quick Submit behavior', function() { diff --git a/spec/javascripts/behaviors/requires_input_spec.js b/spec/javascripts/behaviors/requires_input_spec.js index 793405cd197..fd098196e7d 100644 --- a/spec/javascripts/behaviors/requires_input_spec.js +++ b/spec/javascripts/behaviors/requires_input_spec.js @@ -1,6 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, padded-blocks */ -require('behaviors/requires_input'); +require('~/behaviors/requires_input'); (function() { describe('requiresInput', function() { diff --git a/spec/javascripts/boards/boards_store_spec.js.es6 b/spec/javascripts/boards/boards_store_spec.js.es6 index a94f107f67c..8f8f6d22066 100644 --- a/spec/javascripts/boards/boards_store_spec.js.es6 +++ b/spec/javascripts/boards/boards_store_spec.js.es6 @@ -6,13 +6,13 @@ /* global listObj */ /* global listObjDuplicate */ -require('lib/utils/url_utility'); -require('boards/models/issue'); -require('boards/models/label'); -require('boards/models/list'); -require('boards/models/user'); -require('boards/services/board_service'); -require('boards/stores/boards_store'); +require('~/lib/utils/url_utility'); +require('~/boards/models/issue'); +require('~/boards/models/label'); +require('~/boards/models/list'); +require('~/boards/models/user'); +require('~/boards/services/board_service'); +require('~/boards/stores/boards_store'); require('./mock_data'); describe('Store', () => { diff --git a/spec/javascripts/boards/issue_spec.js.es6 b/spec/javascripts/boards/issue_spec.js.es6 index 2f38bea7d48..5514f34c828 100644 --- a/spec/javascripts/boards/issue_spec.js.es6 +++ b/spec/javascripts/boards/issue_spec.js.es6 @@ -2,13 +2,13 @@ /* global BoardService */ /* global ListIssue */ -require('lib/utils/url_utility'); -require('boards/models/issue'); -require('boards/models/label'); -require('boards/models/list'); -require('boards/models/user'); -require('boards/services/board_service'); -require('boards/stores/boards_store'); +require('~/lib/utils/url_utility'); +require('~/boards/models/issue'); +require('~/boards/models/label'); +require('~/boards/models/list'); +require('~/boards/models/user'); +require('~/boards/services/board_service'); +require('~/boards/stores/boards_store'); require('./mock_data'); describe('Issue model', () => { diff --git a/spec/javascripts/boards/list_spec.js.es6 b/spec/javascripts/boards/list_spec.js.es6 index edd472573de..31b49e3e27a 100644 --- a/spec/javascripts/boards/list_spec.js.es6 +++ b/spec/javascripts/boards/list_spec.js.es6 @@ -5,13 +5,13 @@ /* global List */ /* global listObj */ -require('lib/utils/url_utility'); -require('boards/models/issue'); -require('boards/models/label'); -require('boards/models/list'); -require('boards/models/user'); -require('boards/services/board_service'); -require('boards/stores/boards_store'); +require('~/lib/utils/url_utility'); +require('~/boards/models/issue'); +require('~/boards/models/label'); +require('~/boards/models/list'); +require('~/boards/models/user'); +require('~/boards/services/board_service'); +require('~/boards/stores/boards_store'); require('./mock_data'); describe('List model', () => { diff --git a/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 b/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 index f73bb5c6fed..bb2545cddf9 100644 --- a/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 +++ b/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 @@ -1,4 +1,4 @@ -require('lib/utils/bootstrap_linked_tabs'); +require('~/lib/utils/bootstrap_linked_tabs'); (() => { describe('Linked Tabs', () => { diff --git a/spec/javascripts/build_spec.js.es6 b/spec/javascripts/build_spec.js.es6 index 41a3e614cd1..d2a093df146 100644 --- a/spec/javascripts/build_spec.js.es6 +++ b/spec/javascripts/build_spec.js.es6 @@ -2,9 +2,9 @@ /* global Build */ /* global Turbolinks */ -require('lib/utils/datetime_utility'); -require('build'); -require('breakpoints'); +require('~/lib/utils/datetime_utility'); +require('~/build'); +require('~/breakpoints'); require('vendor/jquery.nicescroll'); describe('Build', () => { diff --git a/spec/javascripts/dashboard_spec.js.es6 b/spec/javascripts/dashboard_spec.js.es6 index b9e819aa218..501380693d4 100644 --- a/spec/javascripts/dashboard_spec.js.es6 +++ b/spec/javascripts/dashboard_spec.js.es6 @@ -1,7 +1,7 @@ /* eslint-disable no-new, padded-blocks */ -require('sidebar'); -require('lib/utils/text_utility'); +require('~/sidebar'); +require('~/lib/utils/text_utility'); ((global) => { describe('Dashboard', () => { diff --git a/spec/javascripts/datetime_utility_spec.js.es6 b/spec/javascripts/datetime_utility_spec.js.es6 index 713e7742988..d5eec10be42 100644 --- a/spec/javascripts/datetime_utility_spec.js.es6 +++ b/spec/javascripts/datetime_utility_spec.js.es6 @@ -1,4 +1,4 @@ -require('lib/utils/datetime_utility'); +require('~/lib/utils/datetime_utility'); (() => { describe('Date time utils', () => { diff --git a/spec/javascripts/diff_comments_store_spec.js.es6 b/spec/javascripts/diff_comments_store_spec.js.es6 index f27ba0f93f7..cf2f17de5ee 100644 --- a/spec/javascripts/diff_comments_store_spec.js.es6 +++ b/spec/javascripts/diff_comments_store_spec.js.es6 @@ -1,9 +1,9 @@ /* eslint-disable no-extra-semi, jasmine/no-global-setup, dot-notation, jasmine/no-expect-in-setup-teardown, max-len */ /* global CommentsStore */ -require('diff_notes/models/discussion'); -require('diff_notes/models/note'); -require('diff_notes/stores/comments'); +require('~/diff_notes/models/discussion'); +require('~/diff_notes/models/note'); +require('~/diff_notes/stores/comments'); (() => { function createDiscussion(noteId = 1, resolved = true) { diff --git a/spec/javascripts/environments/environment_actions_spec.js.es6 b/spec/javascripts/environments/environment_actions_spec.js.es6 index c02c2e10b9a..b1838045a06 100644 --- a/spec/javascripts/environments/environment_actions_spec.js.es6 +++ b/spec/javascripts/environments/environment_actions_spec.js.es6 @@ -1,4 +1,4 @@ -require('environments/components/environment_actions'); +require('~/environments/components/environment_actions'); describe('Actions Component', () => { preloadFixtures('static/environments/element.html.raw'); diff --git a/spec/javascripts/environments/environment_external_url_spec.js.es6 b/spec/javascripts/environments/environment_external_url_spec.js.es6 index 5270ebef0ae..a6a587e69f5 100644 --- a/spec/javascripts/environments/environment_external_url_spec.js.es6 +++ b/spec/javascripts/environments/environment_external_url_spec.js.es6 @@ -1,4 +1,4 @@ -require('environments/components/environment_external_url'); +require('~/environments/components/environment_external_url'); describe('External URL Component', () => { preloadFixtures('static/environments/element.html.raw'); diff --git a/spec/javascripts/environments/environment_item_spec.js.es6 b/spec/javascripts/environments/environment_item_spec.js.es6 index 400850db028..9858f346c83 100644 --- a/spec/javascripts/environments/environment_item_spec.js.es6 +++ b/spec/javascripts/environments/environment_item_spec.js.es6 @@ -1,5 +1,5 @@ window.timeago = require('vendor/timeago'); -require('environments/components/environment_item'); +require('~/environments/components/environment_item'); describe('Environment item', () => { preloadFixtures('static/environments/table.html.raw'); diff --git a/spec/javascripts/environments/environment_rollback_spec.js.es6 b/spec/javascripts/environments/environment_rollback_spec.js.es6 index 96d80d59b9a..8c7e1e912b4 100644 --- a/spec/javascripts/environments/environment_rollback_spec.js.es6 +++ b/spec/javascripts/environments/environment_rollback_spec.js.es6 @@ -1,4 +1,4 @@ -require('environments/components/environment_rollback'); +require('~/environments/components/environment_rollback'); describe('Rollback Component', () => { preloadFixtures('static/environments/element.html.raw'); diff --git a/spec/javascripts/environments/environment_stop_spec.js.es6 b/spec/javascripts/environments/environment_stop_spec.js.es6 index a243b967425..2dfce5ba824 100644 --- a/spec/javascripts/environments/environment_stop_spec.js.es6 +++ b/spec/javascripts/environments/environment_stop_spec.js.es6 @@ -1,4 +1,4 @@ -require('environments/components/environment_stop'); +require('~/environments/components/environment_stop'); describe('Stop Component', () => { preloadFixtures('static/environments/element.html.raw'); diff --git a/spec/javascripts/environments/environments_store_spec.js.es6 b/spec/javascripts/environments/environments_store_spec.js.es6 index 090179ce873..9a8300d3832 100644 --- a/spec/javascripts/environments/environments_store_spec.js.es6 +++ b/spec/javascripts/environments/environments_store_spec.js.es6 @@ -1,6 +1,6 @@ /* global environmentsList */ -require('environments/stores/environments_store'); +require('~/environments/stores/environments_store'); require('./mock_data'); (() => { diff --git a/spec/javascripts/extensions/array_spec.js.es6 b/spec/javascripts/extensions/array_spec.js.es6 index 5396e0eb639..75372266808 100644 --- a/spec/javascripts/extensions/array_spec.js.es6 +++ b/spec/javascripts/extensions/array_spec.js.es6 @@ -1,6 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, padded-blocks */ -require('extensions/array'); +require('~/extensions/array'); (function() { describe('Array extensions', function() { diff --git a/spec/javascripts/extensions/element_spec.js.es6 b/spec/javascripts/extensions/element_spec.js.es6 index 49544ae8b5c..2d8a128ed33 100644 --- a/spec/javascripts/extensions/element_spec.js.es6 +++ b/spec/javascripts/extensions/element_spec.js.es6 @@ -1,4 +1,4 @@ -require('extensions/element'); +require('~/extensions/element'); (() => { describe('Element extensions', function () { diff --git a/spec/javascripts/extensions/jquery_spec.js b/spec/javascripts/extensions/jquery_spec.js index 3163414b134..298832f6985 100644 --- a/spec/javascripts/extensions/jquery_spec.js +++ b/spec/javascripts/extensions/jquery_spec.js @@ -1,6 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, padded-blocks */ -require('extensions/jquery'); +require('~/extensions/jquery'); (function() { describe('jQuery extensions', function() { diff --git a/spec/javascripts/extensions/object_spec.js.es6 b/spec/javascripts/extensions/object_spec.js.es6 index 77ffa1a35ae..2467ed78459 100644 --- a/spec/javascripts/extensions/object_spec.js.es6 +++ b/spec/javascripts/extensions/object_spec.js.es6 @@ -1,4 +1,4 @@ -require('extensions/object'); +require('~/extensions/object'); describe('Object extensions', () => { describe('assign', () => { diff --git a/spec/javascripts/gl_dropdown_spec.js.es6 b/spec/javascripts/gl_dropdown_spec.js.es6 index 1f4d7a4eb07..b079aae13c3 100644 --- a/spec/javascripts/gl_dropdown_spec.js.es6 +++ b/spec/javascripts/gl_dropdown_spec.js.es6 @@ -1,9 +1,9 @@ /* eslint-disable comma-dangle, prefer-const, no-param-reassign, no-plusplus, semi, no-unused-expressions, arrow-spacing, max-len */ /* global Turbolinks */ -require('gl_dropdown'); -require('lib/utils/common_utils'); -require('lib/utils/type_utility'); +require('~/gl_dropdown'); +require('~/lib/utils/common_utils'); +require('~/lib/utils/type_utility'); (() => { const NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-link'; diff --git a/spec/javascripts/gl_field_errors_spec.js.es6 b/spec/javascripts/gl_field_errors_spec.js.es6 index 53f7e576394..51ba59df671 100644 --- a/spec/javascripts/gl_field_errors_spec.js.es6 +++ b/spec/javascripts/gl_field_errors_spec.js.es6 @@ -1,6 +1,6 @@ /* eslint-disable space-before-function-paren, arrow-body-style, indent, padded-blocks */ -require('gl_field_errors'); +require('~/gl_field_errors'); ((global) => { preloadFixtures('static/gl_field_errors.html.raw'); diff --git a/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js b/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js index a914eda90bb..88aaaa0471b 100644 --- a/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js +++ b/spec/javascripts/graphs/stat_graph_contributors_graph_spec.js @@ -3,7 +3,7 @@ /* global ContributorsGraph */ /* global ContributorsMasterGraph */ -require('graphs/stat_graph_contributors_graph'); +require('~/graphs/stat_graph_contributors_graph'); describe("ContributorsGraph", function () { describe("#set_x_domain", function () { diff --git a/spec/javascripts/graphs/stat_graph_contributors_util_spec.js b/spec/javascripts/graphs/stat_graph_contributors_util_spec.js index 4f82e1c46db..671b0ae391c 100644 --- a/spec/javascripts/graphs/stat_graph_contributors_util_spec.js +++ b/spec/javascripts/graphs/stat_graph_contributors_util_spec.js @@ -1,7 +1,7 @@ /* eslint-disable quotes, padded-blocks, no-var, camelcase, object-curly-spacing, semi, indent, object-property-newline, comma-dangle, comma-spacing, spaced-comment, max-len, key-spacing, vars-on-top, quote-props, no-multi-spaces */ /* global ContributorsStatGraphUtil */ -require('graphs/stat_graph_contributors_util'); +require('~/graphs/stat_graph_contributors_util'); describe("ContributorsStatGraphUtil", function () { diff --git a/spec/javascripts/graphs/stat_graph_spec.js b/spec/javascripts/graphs/stat_graph_spec.js index a017f35831d..5b3b7c9222a 100644 --- a/spec/javascripts/graphs/stat_graph_spec.js +++ b/spec/javascripts/graphs/stat_graph_spec.js @@ -1,7 +1,7 @@ /* eslint-disable quotes, padded-blocks, semi */ /* global StatGraph */ -require('graphs/stat_graph'); +require('~/graphs/stat_graph'); describe("StatGraph", function () { diff --git a/spec/javascripts/header_spec.js b/spec/javascripts/header_spec.js index 570d0ab78cb..a281502b6ba 100644 --- a/spec/javascripts/header_spec.js +++ b/spec/javascripts/header_spec.js @@ -1,7 +1,7 @@ /* eslint-disable space-before-function-paren, padded-blocks, no-var */ -require('header'); -require('lib/utils/text_utility'); +require('~/header'); +require('~/lib/utils/text_utility'); (function() { diff --git a/spec/javascripts/issuable_spec.js.es6 b/spec/javascripts/issuable_spec.js.es6 index eaf155f1606..d846c242b1e 100644 --- a/spec/javascripts/issuable_spec.js.es6 +++ b/spec/javascripts/issuable_spec.js.es6 @@ -1,7 +1,7 @@ /* global Issuable */ /* global Turbolinks */ -require('issuable'); +require('~/issuable'); (() => { const BASE_URL = '/user/project/issues?scope=all&state=closed'; diff --git a/spec/javascripts/issue_spec.js b/spec/javascripts/issue_spec.js index 2938d69e94c..d1d6d5e22cb 100644 --- a/spec/javascripts/issue_spec.js +++ b/spec/javascripts/issue_spec.js @@ -1,8 +1,8 @@ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-use-before-define, indent, no-trailing-spaces, comma-dangle, padded-blocks, max-len */ /* global Issue */ -require('lib/utils/text_utility'); -require('issue'); +require('~/lib/utils/text_utility'); +require('~/issue'); (function() { var INVALID_URL = 'http://goesnowhere.nothing/whereami'; diff --git a/spec/javascripts/labels_issue_sidebar_spec.js.es6 b/spec/javascripts/labels_issue_sidebar_spec.js.es6 index ac3b4e8e0f6..61ccef42cd8 100644 --- a/spec/javascripts/labels_issue_sidebar_spec.js.es6 +++ b/spec/javascripts/labels_issue_sidebar_spec.js.es6 @@ -2,15 +2,15 @@ /* global IssuableContext */ /* global LabelsSelect */ -require('lib/utils/type_utility'); -require('gl_dropdown'); +require('~/lib/utils/type_utility'); +require('~/gl_dropdown'); require('select2'); require('vendor/jquery.nicescroll'); -require('api'); -require('create_label'); -require('issuable_context'); -require('users_select'); -require('labels_select'); +require('~/api'); +require('~/create_label'); +require('~/issuable_context'); +require('~/users_select'); +require('~/labels_select'); (() => { let saveLabelCount = 0; diff --git a/spec/javascripts/lib/utils/common_utils_spec.js.es6 b/spec/javascripts/lib/utils/common_utils_spec.js.es6 index 46aa0702bda..58fb54077f5 100644 --- a/spec/javascripts/lib/utils/common_utils_spec.js.es6 +++ b/spec/javascripts/lib/utils/common_utils_spec.js.es6 @@ -1,4 +1,4 @@ -require('lib/utils/common_utils'); +require('~/lib/utils/common_utils'); (() => { describe('common_utils', () => { diff --git a/spec/javascripts/line_highlighter_spec.js b/spec/javascripts/line_highlighter_spec.js index afc51e6682a..be80e06af53 100644 --- a/spec/javascripts/line_highlighter_spec.js +++ b/spec/javascripts/line_highlighter_spec.js @@ -1,7 +1,7 @@ /* eslint-disable space-before-function-paren, no-var, no-param-reassign, quotes, prefer-template, no-else-return, new-cap, dot-notation, no-return-assign, comma-dangle, no-new, one-var, one-var-declaration-per-line, no-plusplus, jasmine/no-spec-dupes, no-underscore-dangle, padded-blocks, max-len */ /* global LineHighlighter */ -require('line_highlighter'); +require('~/line_highlighter'); (function() { describe('LineHighlighter', function() { diff --git a/spec/javascripts/merge_request_spec.js b/spec/javascripts/merge_request_spec.js index 5f98edc3bb0..f87e87f4204 100644 --- a/spec/javascripts/merge_request_spec.js +++ b/spec/javascripts/merge_request_spec.js @@ -1,7 +1,7 @@ /* eslint-disable space-before-function-paren, no-return-assign, padded-blocks */ /* global MergeRequest */ -require('merge_request'); +require('~/merge_request'); (function() { describe('MergeRequest', function() { diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js index 5f53334f44c..114b7cca61e 100644 --- a/spec/javascripts/merge_request_tabs_spec.js +++ b/spec/javascripts/merge_request_tabs_spec.js @@ -1,8 +1,8 @@ /* eslint-disable no-var, comma-dangle, object-shorthand */ -require('merge_request_tabs'); -require('breakpoints'); -require('lib/utils/common_utils'); +require('~/merge_request_tabs'); +require('~/breakpoints'); +require('~/lib/utils/common_utils'); require('vendor/jquery.scrollTo'); (function () { diff --git a/spec/javascripts/merge_request_widget_spec.js b/spec/javascripts/merge_request_widget_spec.js index b29f5bad234..c09cea28696 100644 --- a/spec/javascripts/merge_request_widget_spec.js +++ b/spec/javascripts/merge_request_widget_spec.js @@ -1,7 +1,7 @@ /* eslint-disable space-before-function-paren, quotes, comma-dangle, dot-notation, indent, quote-props, no-var, padded-blocks, max-len */ -require('merge_request_widget'); -require('lib/utils/datetime_utility'); +require('~/merge_request_widget'); +require('~/lib/utils/datetime_utility'); (function() { describe('MergeRequestWidget', function() { diff --git a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 index 32b80a4f4bd..a6994f6edf4 100644 --- a/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 +++ b/spec/javascripts/mini_pipeline_graph_dropdown_spec.js.es6 @@ -1,7 +1,7 @@ /* eslint-disable no-new */ -require('flash'); -require('mini_pipeline_graph_dropdown'); +require('~/flash'); +require('~/mini_pipeline_graph_dropdown'); (() => { describe('Mini Pipeline Graph Dropdown', () => { diff --git a/spec/javascripts/new_branch_spec.js b/spec/javascripts/new_branch_spec.js index 40c6b6d3999..0fdfa4d037b 100644 --- a/spec/javascripts/new_branch_spec.js +++ b/spec/javascripts/new_branch_spec.js @@ -2,7 +2,7 @@ /* global NewBranchForm */ require('jquery-ui/ui/autocomplete'); -require('new_branch_form'); +require('~/new_branch_form'); (function() { describe('Branch', function() { diff --git a/spec/javascripts/notes_spec.js b/spec/javascripts/notes_spec.js index 0b2ac007495..295b44a3e74 100644 --- a/spec/javascripts/notes_spec.js +++ b/spec/javascripts/notes_spec.js @@ -1,10 +1,10 @@ /* eslint-disable space-before-function-paren, no-unused-expressions, no-var, object-shorthand, comma-dangle, semi, padded-blocks, max-len */ /* global Notes */ -require('notes'); +require('~/notes'); require('vendor/autosize'); -require('gl_form'); -require('lib/utils/text_utility'); +require('~/gl_form'); +require('~/lib/utils/text_utility'); (function() { window.gon || (window.gon = {}); diff --git a/spec/javascripts/pipelines_spec.js.es6 b/spec/javascripts/pipelines_spec.js.es6 index 1bee64b814f..6120ca5543d 100644 --- a/spec/javascripts/pipelines_spec.js.es6 +++ b/spec/javascripts/pipelines_spec.js.es6 @@ -1,4 +1,4 @@ -require('pipelines'); +require('~/pipelines'); (() => { describe('Pipelines', () => { diff --git a/spec/javascripts/pretty_time_spec.js.es6 b/spec/javascripts/pretty_time_spec.js.es6 index 207d40983b4..fe5317e05b1 100644 --- a/spec/javascripts/pretty_time_spec.js.es6 +++ b/spec/javascripts/pretty_time_spec.js.es6 @@ -1,4 +1,4 @@ -require('lib/utils/pretty_time'); +require('~/lib/utils/pretty_time'); (() => { const PrettyTime = gl.PrettyTime; diff --git a/spec/javascripts/project_title_spec.js b/spec/javascripts/project_title_spec.js index a774b978458..ab0808bab18 100644 --- a/spec/javascripts/project_title_spec.js +++ b/spec/javascripts/project_title_spec.js @@ -2,11 +2,11 @@ /* global Project */ require('select2/select2.js'); -require('lib/utils/type_utility'); -require('gl_dropdown'); -require('api'); -require('project_select'); -require('project'); +require('~/lib/utils/type_utility'); +require('~/gl_dropdown'); +require('~/api'); +require('~/project_select'); +require('~/project'); (function() { window.gon || (window.gon = {}); diff --git a/spec/javascripts/right_sidebar_spec.js b/spec/javascripts/right_sidebar_spec.js index db6b7244135..2a711b15133 100644 --- a/spec/javascripts/right_sidebar_spec.js +++ b/spec/javascripts/right_sidebar_spec.js @@ -1,8 +1,8 @@ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, new-parens, no-return-assign, new-cap, vars-on-top, semi, padded-blocks, max-len */ /* global Sidebar */ -require('right_sidebar'); -require('extensions/jquery.js'); +require('~/right_sidebar'); +require('~/extensions/jquery.js'); (function() { var $aside, $icon, $labelsIcon, $page, $toggle, assertSidebarState; diff --git a/spec/javascripts/search_autocomplete_spec.js b/spec/javascripts/search_autocomplete_spec.js index 8d7f48eabc5..08d9b775940 100644 --- a/spec/javascripts/search_autocomplete_spec.js +++ b/spec/javascripts/search_autocomplete_spec.js @@ -1,9 +1,9 @@ /* eslint-disable space-before-function-paren, max-len, no-var, one-var, one-var-declaration-per-line, no-unused-expressions, consistent-return, no-param-reassign, default-case, no-return-assign, comma-dangle, object-shorthand, prefer-template, quotes, new-parens, vars-on-top, new-cap, padded-blocks, max-len */ -require('gl_dropdown'); -require('search_autocomplete'); -require('lib/utils/common_utils'); -require('lib/utils/type_utility'); +require('~/gl_dropdown'); +require('~/search_autocomplete'); +require('~/lib/utils/common_utils'); +require('~/lib/utils/type_utility'); require('vendor/fuzzaldrin-plus'); (function() { diff --git a/spec/javascripts/shortcuts_issuable_spec.js b/spec/javascripts/shortcuts_issuable_spec.js index 65c4f42e3b8..7c577cc1b38 100644 --- a/spec/javascripts/shortcuts_issuable_spec.js +++ b/spec/javascripts/shortcuts_issuable_spec.js @@ -1,7 +1,7 @@ /* eslint-disable space-before-function-paren, no-return-assign, no-var, quotes, padded-blocks */ /* global ShortcutsIssuable */ -require('shortcuts_issuable'); +require('~/shortcuts_issuable'); (function() { describe('ShortcutsIssuable', function() { diff --git a/spec/javascripts/signin_tabs_memoizer_spec.js.es6 b/spec/javascripts/signin_tabs_memoizer_spec.js.es6 index b34942d78d1..d83d9a57b42 100644 --- a/spec/javascripts/signin_tabs_memoizer_spec.js.es6 +++ b/spec/javascripts/signin_tabs_memoizer_spec.js.es6 @@ -1,4 +1,4 @@ -require('signin_tabs_memoizer'); +require('~/signin_tabs_memoizer'); ((global) => { describe('SigninTabsMemoizer', () => { diff --git a/spec/javascripts/smart_interval_spec.js.es6 b/spec/javascripts/smart_interval_spec.js.es6 index 3075965d7f9..0c8051810cc 100644 --- a/spec/javascripts/smart_interval_spec.js.es6 +++ b/spec/javascripts/smart_interval_spec.js.es6 @@ -1,4 +1,4 @@ -require('smart_interval'); +require('~/smart_interval'); (() => { const DEFAULT_MAX_INTERVAL = 100; diff --git a/spec/javascripts/subbable_resource_spec.js.es6 b/spec/javascripts/subbable_resource_spec.js.es6 index 1434ae8364d..ef1b32c2d19 100644 --- a/spec/javascripts/subbable_resource_spec.js.es6 +++ b/spec/javascripts/subbable_resource_spec.js.es6 @@ -1,6 +1,6 @@ /* eslint-disable max-len, arrow-parens, comma-dangle, no-plusplus */ -require('subbable_resource'); +require('~/subbable_resource'); /* * Test that each rest verb calls the publish and subscribe function and passes the correct value back diff --git a/spec/javascripts/syntax_highlight_spec.js b/spec/javascripts/syntax_highlight_spec.js index b5e869e2169..6c953f1b71c 100644 --- a/spec/javascripts/syntax_highlight_spec.js +++ b/spec/javascripts/syntax_highlight_spec.js @@ -1,6 +1,6 @@ /* eslint-disable space-before-function-paren, no-var, no-return-assign, quotes, padded-blocks */ -require('syntax_highlight'); +require('~/syntax_highlight'); (function() { describe('Syntax Highlighter', function() { diff --git a/spec/javascripts/u2f/authenticate_spec.js b/spec/javascripts/u2f/authenticate_spec.js index 22cea407943..e5948131744 100644 --- a/spec/javascripts/u2f/authenticate_spec.js +++ b/spec/javascripts/u2f/authenticate_spec.js @@ -2,9 +2,9 @@ /* global MockU2FDevice */ /* global U2FAuthenticate */ -require('u2f/authenticate'); -require('u2f/util'); -require('u2f/error'); +require('~/u2f/authenticate'); +require('~/u2f/util'); +require('~/u2f/error'); require('vendor/u2f'); require('./mock_u2f_device'); diff --git a/spec/javascripts/u2f/register_spec.js b/spec/javascripts/u2f/register_spec.js index 17b3732975b..50522ff2391 100644 --- a/spec/javascripts/u2f/register_spec.js +++ b/spec/javascripts/u2f/register_spec.js @@ -2,9 +2,9 @@ /* global MockU2FDevice */ /* global U2FRegister */ -require('u2f/register'); -require('u2f/util'); -require('u2f/error'); +require('~/u2f/register'); +require('~/u2f/util'); +require('~/u2f/error'); require('vendor/u2f'); require('./mock_u2f_device'); diff --git a/spec/javascripts/vue_common_components/commit_spec.js.es6 b/spec/javascripts/vue_common_components/commit_spec.js.es6 index 12d8c411847..bbd914de4ea 100644 --- a/spec/javascripts/vue_common_components/commit_spec.js.es6 +++ b/spec/javascripts/vue_common_components/commit_spec.js.es6 @@ -1,4 +1,4 @@ -require('vue_common_component/commit'); +require('~/vue_common_component/commit'); describe('Commit component', () => { let props; diff --git a/spec/javascripts/zen_mode_spec.js b/spec/javascripts/zen_mode_spec.js index 7fe2ab68c75..7a68356376f 100644 --- a/spec/javascripts/zen_mode_spec.js +++ b/spec/javascripts/zen_mode_spec.js @@ -3,7 +3,7 @@ /* global Mousetrap */ /* global ZenMode */ -require('zen_mode'); +require('~/zen_mode'); (function() { var enterZen, escapeKeydown, exitZen; -- cgit v1.2.1 From 970155a3f47ee90d6bfab8d0b5b63f103b832cbd Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Sat, 7 Jan 2017 01:27:37 -0600 Subject: fix globals within boards_bundle mock data --- spec/javascripts/boards/mock_data.js.es6 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/javascripts/boards/mock_data.js.es6 b/spec/javascripts/boards/mock_data.js.es6 index 8d3e2237fda..7a399b307ad 100644 --- a/spec/javascripts/boards/mock_data.js.es6 +++ b/spec/javascripts/boards/mock_data.js.es6 @@ -56,3 +56,8 @@ const boardsMockInterceptor = (request, next) => { status: 200 })); }; + +window.listObj = listObj; +window.listObjDuplicate = listObjDuplicate; +window.BoardsMockData = BoardsMockData; +window.boardsMockInterceptor = boardsMockInterceptor; -- cgit v1.2.1 From 31af0fbaf83c5a4e4dbcaabf0819084b13d07233 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Sat, 7 Jan 2017 01:36:19 -0600 Subject: improve sourcemap generation --- config/karma.config.js | 2 +- config/webpack.config.js | 3 ++- package.json | 3 ++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/config/karma.config.js b/config/karma.config.js index b317c3f00b2..545390a5a1e 100644 --- a/config/karma.config.js +++ b/config/karma.config.js @@ -12,7 +12,7 @@ module.exports = function(config) { { pattern: 'spec/javascripts/fixtures/**/*@(.json|.html|.html.raw)', included: false }, ], preprocessors: { - 'spec/javascripts/**/*.js?(.es6)': ['webpack'], + 'spec/javascripts/**/*.js?(.es6)': ['webpack', 'sourcemap'], }, webpack: webpackConfig, webpackMiddleware: { stats: 'errors-only' }, diff --git a/config/webpack.config.js b/config/webpack.config.js index 4060228c94b..f363a9fc4a9 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -40,7 +40,7 @@ var config = { filename: IS_PRODUCTION ? '[name]-[chunkhash].js' : '[name].js' }, - devtool: 'source-map', + devtool: 'inline-source-map', module: { loaders: [ @@ -93,6 +93,7 @@ var config = { } if (IS_PRODUCTION) { + config.devtool = 'source-map'; config.plugins.push( new webpack.NoErrorsPlugin(), new webpack.optimize.UglifyJsPlugin({ diff --git a/package.json b/package.json index ef16a371f91..4ce08487c3d 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "underscore": "1.8.3", "vue": "2.0.3", "vue-resource": "0.9.3", - "webpack": "^1.13.2", + "webpack": "^1.14.0", "webpack-dev-server": "^1.16.2" }, "devDependencies": { @@ -41,6 +41,7 @@ "jasmine-jquery": "^2.1.1", "karma": "^1.3.0", "karma-jasmine": "^1.1.0", + "karma-sourcemap-loader": "^0.3.7", "karma-webpack": "^1.8.0" } } -- cgit v1.2.1 From 80917acd7ef8ce43fce0e657f9538ae79c537729 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Sat, 7 Jan 2017 01:38:36 -0600 Subject: prevent karma from reloading on save until webpack is ready --- config/karma.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/karma.config.js b/config/karma.config.js index 545390a5a1e..5c3d454addf 100644 --- a/config/karma.config.js +++ b/config/karma.config.js @@ -8,7 +8,7 @@ module.exports = function(config) { basePath: ROOT_PATH, frameworks: ['jasmine'], files: [ - 'spec/javascripts/test_bundle.js', + { pattern: 'spec/javascripts/test_bundle.js', watched: false }, { pattern: 'spec/javascripts/fixtures/**/*@(.json|.html|.html.raw)', included: false }, ], preprocessors: { -- cgit v1.2.1 From 8dc13eca9a4865bbd2afb5ef2ca9697a2324a88e Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Sat, 7 Jan 2017 01:46:55 -0600 Subject: fix failing tests --- app/assets/javascripts/gl_dropdown.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js index bb516b3d2df..a669d8bd4e2 100644 --- a/app/assets/javascripts/gl_dropdown.js +++ b/app/assets/javascripts/gl_dropdown.js @@ -251,7 +251,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'); } }; -- cgit v1.2.1 From 19b94e715d7a0409d2f39b2efae306d0c202ee66 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Sat, 7 Jan 2017 01:47:45 -0600 Subject: fix globals within environments_bundle mock data --- spec/javascripts/environments/mock_data.js.es6 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/spec/javascripts/environments/mock_data.js.es6 b/spec/javascripts/environments/mock_data.js.es6 index bc5f6246cba..563414d0b1a 100644 --- a/spec/javascripts/environments/mock_data.js.es6 +++ b/spec/javascripts/environments/mock_data.js.es6 @@ -134,3 +134,5 @@ const environmentsList = [ updated_at: '2016-11-07T11:11:16.525Z', }, ]; + +window.environmentsList = environmentsList; -- cgit v1.2.1 From 707bcbba4baf62b77bde16086828681902669d38 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Sat, 7 Jan 2017 01:51:35 -0600 Subject: fix failing tests for merge_request_widget_spec.js --- app/assets/javascripts/merge_request_widget.js.es6 | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/assets/javascripts/merge_request_widget.js.es6 b/app/assets/javascripts/merge_request_widget.js.es6 index 0305aeb07d9..c3a4306316b 100644 --- a/app/assets/javascripts/merge_request_widget.js.es6 +++ b/app/assets/javascripts/merge_request_widget.js.es6 @@ -4,6 +4,8 @@ /* 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++) { if (i in this && this[i] === item) return i; } return -1; }; -- cgit v1.2.1 From e3ff5ff42698cecf17eb9cd59231c16132bb3e79 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Mon, 9 Jan 2017 13:17:48 -0600 Subject: ensire u2f object is accessible in a commonJS environment --- vendor/assets/javascripts/u2f.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vendor/assets/javascripts/u2f.js b/vendor/assets/javascripts/u2f.js index e666b136051..a33e5e0ade9 100644 --- a/vendor/assets/javascripts/u2f.js +++ b/vendor/assets/javascripts/u2f.js @@ -745,4 +745,6 @@ u2f.getApiVersion = function(callback, opt_timeoutSeconds) { }; port.postMessage(req); }); -}; \ No newline at end of file +}; + +window.u2f || (window.u2f = u2f); -- cgit v1.2.1 From 5f2d1712180b5b56f486b1b2e0888e7acf094451 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Mon, 9 Jan 2017 13:18:21 -0600 Subject: prevent u2f authenticate test from auto-submitting a form --- spec/javascripts/u2f/authenticate_spec.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/javascripts/u2f/authenticate_spec.js b/spec/javascripts/u2f/authenticate_spec.js index e5948131744..ddbc1455057 100644 --- a/spec/javascripts/u2f/authenticate_spec.js +++ b/spec/javascripts/u2f/authenticate_spec.js @@ -25,19 +25,20 @@ require('./mock_u2f_device'); document.querySelector('#js-login-2fa-device'), document.querySelector('.js-2fa-form') ); + + // bypass automatic form submission within renderAuthenticated + spyOn(this.component, 'renderAuthenticated').and.returnValue(true); + return this.component.start(); }); it('allows authenticating via a U2F device', function() { - var authenticatedMessage, deviceResponse, inProgressMessage; + var inProgressMessage; inProgressMessage = this.container.find("p"); expect(inProgressMessage.text()).toContain("Trying to communicate with your device"); this.u2fDevice.respondToAuthenticateRequest({ deviceData: "this is data from the device" }); - authenticatedMessage = this.container.find("p"); - deviceResponse = this.container.find('#js-device-response'); - expect(authenticatedMessage.text()).toContain('We heard back from your U2F device. You have been authenticated.'); - return expect(deviceResponse.val()).toBe('{"deviceData":"this is data from the device"}'); + expect(this.component.renderAuthenticated).toHaveBeenCalledWith('{"deviceData":"this is data from the device"}'); }); return describe("errors", function() { it("displays an error message", function() { @@ -51,7 +52,7 @@ require('./mock_u2f_device'); return expect(errorMessage.text()).toContain("There was a problem communicating with your device"); }); return it("allows retrying authentication after an error", function() { - var authenticatedMessage, retryButton, setupButton; + var retryButton, setupButton; setupButton = this.container.find("#js-login-u2f-device"); setupButton.trigger('click'); this.u2fDevice.respondToAuthenticateRequest({ @@ -64,8 +65,7 @@ require('./mock_u2f_device'); this.u2fDevice.respondToAuthenticateRequest({ deviceData: "this is data from the device" }); - authenticatedMessage = this.container.find("p"); - return expect(authenticatedMessage.text()).toContain("We heard back from your U2F device. You have been authenticated."); + expect(this.component.renderAuthenticated).toHaveBeenCalledWith('{"deviceData":"this is data from the device"}'); }); }); }); -- cgit v1.2.1 From 5ffbb5dee58dcc5541a06a17700c87b62c4c31d8 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Mon, 9 Jan 2017 13:50:13 -0600 Subject: bypass buggy "focus" event in Chrome --- spec/javascripts/shortcuts_issuable_spec.js | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/spec/javascripts/shortcuts_issuable_spec.js b/spec/javascripts/shortcuts_issuable_spec.js index 7c577cc1b38..3f7f6cf0113 100644 --- a/spec/javascripts/shortcuts_issuable_spec.js +++ b/spec/javascripts/shortcuts_issuable_spec.js @@ -50,13 +50,8 @@ require('~/shortcuts_issuable'); return expect(triggered).toBe(true); }); return it('triggers `focus`', function() { - var focused; - focused = false; - $(this.selector).on('focus', function() { - return focused = true; - }); this.shortcut.replyWithSelectedText(); - return expect(focused).toBe(true); + expect(document.activeElement).toBe(document.querySelector(this.selector)); }); }); describe('with a one-line selection', function() { -- cgit v1.2.1 From d2649bf8e3d55e28e453f891faa92745267affe5 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Mon, 9 Jan 2017 16:33:56 -0600 Subject: bypass Chrome "focus" event bugs and prevent Turbolinks from triggering --- spec/javascripts/search_autocomplete_spec.js | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/spec/javascripts/search_autocomplete_spec.js b/spec/javascripts/search_autocomplete_spec.js index 08d9b775940..d564a49517b 100644 --- a/spec/javascripts/search_autocomplete_spec.js +++ b/spec/javascripts/search_autocomplete_spec.js @@ -112,13 +112,15 @@ require('vendor/fuzzaldrin-plus'); preloadFixtures('static/search_autocomplete.html.raw'); beforeEach(function() { loadFixtures('static/search_autocomplete.html.raw'); - return widget = new gl.SearchAutocomplete; + widget = new gl.SearchAutocomplete; + // Prevent turbolinks from triggering within gl_dropdown + spyOn(window.Turbolinks, 'visit').and.returnValue(true); }); it('should show Dashboard specific dropdown menu', function() { var list; addBodyAttributes(); mockDashboardOptions(); - widget.searchInput.focus(); + widget.searchInput.triggerHandler('focus'); list = widget.wrap.find('.dropdown-menu').find('ul'); return assertLinks(list, dashboardIssuesPath, dashboardMRsPath); }); @@ -126,7 +128,7 @@ require('vendor/fuzzaldrin-plus'); var list; addBodyAttributes('group'); mockGroupOptions(); - widget.searchInput.focus(); + widget.searchInput.triggerHandler('focus'); list = widget.wrap.find('.dropdown-menu').find('ul'); return assertLinks(list, groupIssuesPath, groupMRsPath); }); @@ -134,7 +136,7 @@ require('vendor/fuzzaldrin-plus'); var list; addBodyAttributes('project'); mockProjectOptions(); - widget.searchInput.focus(); + widget.searchInput.triggerHandler('focus'); list = widget.wrap.find('.dropdown-menu').find('ul'); return assertLinks(list, projectIssuesPath, projectMRsPath); }); @@ -143,7 +145,7 @@ require('vendor/fuzzaldrin-plus'); addBodyAttributes('project'); mockProjectOptions(); widget.searchInput.val('help'); - widget.searchInput.focus(); + widget.searchInput.triggerHandler('focus'); list = widget.wrap.find('.dropdown-menu').find('ul'); link = "a[href='" + projectIssuesPath + "/?assignee_id=" + userId + "']"; return expect(list.find(link).length).toBe(0); @@ -154,7 +156,7 @@ require('vendor/fuzzaldrin-plus'); addBodyAttributes(); mockDashboardOptions(true); var submitSpy = spyOnEvent('form', 'submit'); - widget.searchInput.focus(); + widget.searchInput.triggerHandler('focus'); widget.wrap.trigger($.Event('keydown', { which: DOWN })); var enterKeyEvent = $.Event('keydown', { which: ENTER }); widget.searchInput.trigger(enterKeyEvent); -- cgit v1.2.1 From bdcb81be95b3287e14cf23b2f1d0849b24077360 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Mon, 9 Jan 2017 16:35:58 -0600 Subject: remove teaspoon-specific test --- spec/javascripts/lib/utils/common_utils_spec.js.es6 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/javascripts/lib/utils/common_utils_spec.js.es6 b/spec/javascripts/lib/utils/common_utils_spec.js.es6 index 58fb54077f5..e33360a1875 100644 --- a/spec/javascripts/lib/utils/common_utils_spec.js.es6 +++ b/spec/javascripts/lib/utils/common_utils_spec.js.es6 @@ -10,9 +10,9 @@ require('~/lib/utils/common_utils'); // IE11 will return a relative pathname while other browsers will return a full pathname. // parseUrl uses an anchor element for parsing an url. With relative urls, the anchor // element will create an absolute url relative to the current execution context. - // The JavaScript test suite is executed at '/teaspoon' which will lead to an absolute - // url starting with '/teaspoon'. - expect(gl.utils.parseUrl('" test="asf"').pathname).toEqual('/teaspoon/%22%20test=%22asf%22'); + // The JavaScript test suite is executed at '/' which will lead to an absolute url + // starting with '/'. + expect(gl.utils.parseUrl('" test="asf"').pathname).toEqual('/%22%20test=%22asf%22'); }); }); describe('gl.utils.parseUrlPathname', () => { -- cgit v1.2.1 From 5bb258cd8fbc051aa65fca133578eb30761b5ca1 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 13 Jan 2017 11:04:41 -0500 Subject: phantomJS doesn't allow us to spyOn history.replaceState --- spec/javascripts/bootstrap_linked_tabs_spec.js.es6 | 20 ++++++++++++++------ spec/javascripts/gl_dropdown_spec.js.es6 | 1 + .../javascripts/lib/utils/common_utils_spec.js.es6 | 2 +- spec/javascripts/merge_request_tabs_spec.js | 22 +++++++++++++++------- spec/javascripts/pipelines_spec.js.es6 | 5 +++++ spec/javascripts/project_title_spec.js | 2 ++ spec/javascripts/right_sidebar_spec.js | 2 ++ 7 files changed, 40 insertions(+), 14 deletions(-) diff --git a/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 b/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 index bb2545cddf9..54055b04f62 100644 --- a/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 +++ b/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 @@ -1,6 +1,10 @@ require('~/lib/utils/bootstrap_linked_tabs'); (() => { + // TODO: remove this hack! + // PhantomJS causes spyOn to panic because replaceState isn't "writable" + const phantomjs = !Object.getOwnPropertyDescriptor(window.history, 'replaceState').writable; + describe('Linked Tabs', () => { preloadFixtures('static/linked_tabs.html.raw'); @@ -10,7 +14,9 @@ require('~/lib/utils/bootstrap_linked_tabs'); describe('when is initialized', () => { beforeEach(() => { - spyOn(window.history, 'replaceState').and.callFake(function () {}); + if (!phantomjs) { + spyOn(window.history, 'replaceState').and.callFake(function () {}); + } }); it('should activate the tab correspondent to the given action', () => { @@ -36,7 +42,7 @@ require('~/lib/utils/bootstrap_linked_tabs'); describe('on click', () => { it('should change the url according to the clicked tab', () => { - const historySpy = spyOn(history, 'replaceState').and.callFake(() => {}); + const historySpy = !phantomjs && spyOn(history, 'replaceState').and.callFake(() => {}); const linkedTabs = new window.gl.LinkedTabs({ // eslint-disable-line action: 'show', @@ -49,10 +55,12 @@ require('~/lib/utils/bootstrap_linked_tabs'); secondTab.click(); - expect(historySpy).toHaveBeenCalledWith({ - turbolinks: true, - url: newState, - }, document.title, newState); + if (historySpy) { + expect(historySpy).toHaveBeenCalledWith({ + turbolinks: true, + url: newState, + }, document.title, newState); + } }); }); }); diff --git a/spec/javascripts/gl_dropdown_spec.js.es6 b/spec/javascripts/gl_dropdown_spec.js.es6 index b079aae13c3..c60fbd73c63 100644 --- a/spec/javascripts/gl_dropdown_spec.js.es6 +++ b/spec/javascripts/gl_dropdown_spec.js.es6 @@ -42,6 +42,7 @@ require('~/lib/utils/type_utility'); describe('Dropdown', function describeDropdown() { preloadFixtures('static/gl_dropdown.html.raw'); + loadJSONFixtures('projects.json'); function initDropDown(hasRemote, isFilterable) { this.dropdownButtonElement = $('#js-project-dropdown', this.dropdownContainerElement).glDropdown({ diff --git a/spec/javascripts/lib/utils/common_utils_spec.js.es6 b/spec/javascripts/lib/utils/common_utils_spec.js.es6 index a54bb9bb444..bd9c82121a6 100644 --- a/spec/javascripts/lib/utils/common_utils_spec.js.es6 +++ b/spec/javascripts/lib/utils/common_utils_spec.js.es6 @@ -12,7 +12,7 @@ require('~/lib/utils/common_utils'); // element will create an absolute url relative to the current execution context. // The JavaScript test suite is executed at '/' which will lead to an absolute url // starting with '/'. - expect(gl.utils.parseUrl('" test="asf"').pathname).toEqual('/%22%20test=%22asf%22'); + expect(gl.utils.parseUrl('" test="asf"').pathname).toContain('/%22%20test=%22asf%22'); }); }); diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js index 114b7cca61e..377acd5a3aa 100644 --- a/spec/javascripts/merge_request_tabs_spec.js +++ b/spec/javascripts/merge_request_tabs_spec.js @@ -6,6 +6,10 @@ require('~/lib/utils/common_utils'); require('vendor/jquery.scrollTo'); (function () { + // TODO: remove this hack! + // PhantomJS causes spyOn to panic because replaceState isn't "writable" + const phantomjs = !Object.getOwnPropertyDescriptor(window.history, 'replaceState').writable; + describe('MergeRequestTabs', function () { var stubLocation = {}; var setLocation = function (stubs) { @@ -22,9 +26,11 @@ require('vendor/jquery.scrollTo'); this.class = new gl.MergeRequestTabs({ stubLocation: stubLocation }); setLocation(); - this.spies = { - history: spyOn(window.history, 'replaceState').and.callFake(function () {}) - }; + if (!phantomjs) { + this.spies = { + history: spyOn(window.history, 'replaceState').and.callFake(function () {}) + }; + } }); describe('#activateTab', function () { @@ -98,10 +104,12 @@ require('vendor/jquery.scrollTo'); pathname: '/foo/bar/merge_requests/1' }); newState = this.subject('commits'); - expect(this.spies.history).toHaveBeenCalledWith({ - turbolinks: true, - url: newState - }, document.title, newState); + if (!phantomjs) { + expect(this.spies.history).toHaveBeenCalledWith({ + turbolinks: true, + url: newState + }, document.title, newState); + } }); it('treats "show" like "notes"', function () { setLocation({ diff --git a/spec/javascripts/pipelines_spec.js.es6 b/spec/javascripts/pipelines_spec.js.es6 index 6120ca5543d..72770a702d3 100644 --- a/spec/javascripts/pipelines_spec.js.es6 +++ b/spec/javascripts/pipelines_spec.js.es6 @@ -1,5 +1,10 @@ require('~/pipelines'); +// Fix for phantomJS +if (!Element.prototype.matches && Element.prototype.webkitMatchesSelector) { + Element.prototype.matches = Element.prototype.webkitMatchesSelector; +} + (() => { describe('Pipelines', () => { preloadFixtures('static/pipeline_graph.html.raw'); diff --git a/spec/javascripts/project_title_spec.js b/spec/javascripts/project_title_spec.js index ab0808bab18..fa59a937c8e 100644 --- a/spec/javascripts/project_title_spec.js +++ b/spec/javascripts/project_title_spec.js @@ -15,6 +15,8 @@ require('~/project'); describe('Project Title', function() { preloadFixtures('static/project_title.html.raw'); + loadJSONFixtures('projects.json'); + beforeEach(function() { loadFixtures('static/project_title.html.raw'); return this.project = new Project(); diff --git a/spec/javascripts/right_sidebar_spec.js b/spec/javascripts/right_sidebar_spec.js index 2a711b15133..3b00f15795c 100644 --- a/spec/javascripts/right_sidebar_spec.js +++ b/spec/javascripts/right_sidebar_spec.js @@ -34,6 +34,8 @@ require('~/extensions/jquery.js'); describe('RightSidebar', function() { var fixtureName = 'issues/open-issue.html.raw'; preloadFixtures(fixtureName); + loadJSONFixtures('todos.json'); + beforeEach(function() { loadFixtures(fixtureName); this.sidebar = new Sidebar; -- cgit v1.2.1 From 60339e044b0909e31e385bcc687f6bdf60b049b2 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 13 Jan 2017 11:05:09 -0500 Subject: phantomJS requires "use strict" for polyfill to properly work --- app/assets/javascripts/extensions/array.js.es6 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/assets/javascripts/extensions/array.js.es6 b/app/assets/javascripts/extensions/array.js.es6 index 717566a4715..8956e303488 100644 --- a/app/assets/javascripts/extensions/array.js.es6 +++ b/app/assets/javascripts/extensions/array.js.es6 @@ -1,4 +1,7 @@ -/* eslint-disable no-extend-native, func-names, space-before-function-paren, semi, space-infix-ops, max-len */ +/* eslint-disable no-extend-native, func-names, space-before-function-paren, semi, space-infix-ops, strict, max-len */ + +'use strict'; + Array.prototype.first = function() { return this[0]; } -- cgit v1.2.1 From 8a643c8fcd15e23a3b97ddc03a161ce3c8451099 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 13 Jan 2017 11:05:26 -0500 Subject: add phantomJS to karma config --- config/karma.config.js | 1 + package.json | 1 + 2 files changed, 2 insertions(+) diff --git a/config/karma.config.js b/config/karma.config.js index 5c3d454addf..44229e2ee88 100644 --- a/config/karma.config.js +++ b/config/karma.config.js @@ -6,6 +6,7 @@ var ROOT_PATH = path.resolve(__dirname, '..'); module.exports = function(config) { config.set({ basePath: ROOT_PATH, + browsers: ['PhantomJS'], frameworks: ['jasmine'], files: [ { pattern: 'spec/javascripts/test_bundle.js', watched: false }, diff --git a/package.json b/package.json index 4ce08487c3d..fe48fa152c1 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,7 @@ "jasmine-jquery": "^2.1.1", "karma": "^1.3.0", "karma-jasmine": "^1.1.0", + "karma-phantomjs-launcher": "^1.0.2", "karma-sourcemap-loader": "^0.3.7", "karma-webpack": "^1.8.0" } -- cgit v1.2.1 From fc4fcf33bfa3279bb0a81aac8498ada67b5e309b Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Fri, 13 Jan 2017 11:11:35 -0500 Subject: Added gzip compression --- config/webpack.config.js | 6 +++++- package.json | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/config/webpack.config.js b/config/webpack.config.js index bd5863689fd..e9b63eb3bca 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -3,6 +3,7 @@ var path = require('path'); var webpack = require('webpack'); var StatsPlugin = require('stats-webpack-plugin'); +var CompressionPlugin = require("compression-webpack-plugin"); var IS_PRODUCTION = process.env.NODE_ENV === 'production'; var IS_DEV_SERVER = process.argv[1].indexOf('webpack-dev-server') !== -1; @@ -79,7 +80,10 @@ var config = { chunks: false, modules: false, assets: true - }) + }), + new CompressionPlugin({ + asset: '[path].gz[query]', + }), ], resolve: { diff --git a/package.json b/package.json index fe48fa152c1..73fb487b973 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "babel-core": "^5.8.38", "babel-loader": "^5.4.2", "bootstrap-sass": "3.3.6", + "compression-webpack-plugin": "^0.3.2", "d3": "3.5.11", "dropzone": "4.2.0", "exports-loader": "^0.6.3", -- cgit v1.2.1 From 2ee2daa4b91f255218d6f68befa8395d2c62bb3a Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 13 Jan 2017 11:27:19 -0500 Subject: more post-merge fixes --- app/assets/javascripts/application.js | 2 +- .../javascripts/vue_pipelines_index/index.js.es6 | 2 +- config/webpack.config.js | 2 +- .../filtered_search/dropdown_utils_spec.js.es6 | 8 ++++---- .../filtered_search_dropdown_manager_spec.js.es6 | 6 +++--- .../filtered_search_token_keys_spec.js.es6 | 4 ++-- .../filtered_search_tokenizer_spec.js.es6 | 6 +++--- spec/javascripts/lib/utils/text_utility_spec.js.es6 | 2 +- spec/javascripts/vue_pagination/pagination_spec.js.es6 | 18 ++++++++---------- 9 files changed, 24 insertions(+), 26 deletions(-) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 952b295566e..98042106111 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -54,8 +54,8 @@ 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('.', false, /^\.\/(?!application).*\.(js|es6)$/)); requireAll(require.context('./droplab', false, /^\.\/.*\.(js|es6)$/)); +requireAll(require.context('.', false, /^\.\/(?!application).*\.(js|es6)$/)); require('vendor/fuzzaldrin-plus'); window.ES6Promise = require('vendor/es6-promise.auto'); window.ES6Promise.polyfill(); diff --git a/app/assets/javascripts/vue_pipelines_index/index.js.es6 b/app/assets/javascripts/vue_pipelines_index/index.js.es6 index 46626cb1445..2015c0e581c 100644 --- a/app/assets/javascripts/vue_pipelines_index/index.js.es6 +++ b/app/assets/javascripts/vue_pipelines_index/index.js.es6 @@ -1,7 +1,7 @@ /* global Vue, VueResource, gl */ window.Vue = require('vue'); window.Vue.use(require('vue-resource')); -require('../vue_common_component/commit') +require('../vue_common_component/commit'); require('../boards/vue_resource_interceptor'); require('./status'); require('./store'); diff --git a/config/webpack.config.js b/config/webpack.config.js index e9b63eb3bca..0b40e2c6190 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -35,7 +35,7 @@ var config = { lib_chart: './lib/chart.js', lib_d3: './lib/d3.js', vue_pagination: './vue_pagination/index.js', - vue_pipelines: './vue_pipelines_index/index.js', + vue_pipelines: './vue_pipelines_index/index.js', }, output: { diff --git a/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6 b/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6 index ce61b73aa8a..96f33427213 100644 --- a/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6 +++ b/spec/javascripts/filtered_search/dropdown_utils_spec.js.es6 @@ -1,7 +1,7 @@ -//= require extensions/array -//= require filtered_search/dropdown_utils -//= require filtered_search/filtered_search_tokenizer -//= require filtered_search/filtered_search_dropdown_manager +require('~/extensions/array'); +require('~/filtered_search/dropdown_utils'); +require('~/filtered_search/filtered_search_tokenizer'); +require('~/filtered_search/filtered_search_dropdown_manager'); (() => { describe('Dropdown Utils', () => { diff --git a/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js.es6 b/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js.es6 index d0d27ceb4a6..0bc6689eba5 100644 --- a/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js.es6 +++ b/spec/javascripts/filtered_search/filtered_search_dropdown_manager_spec.js.es6 @@ -1,6 +1,6 @@ -//= require extensions/array -//= require filtered_search/filtered_search_tokenizer -//= require filtered_search/filtered_search_dropdown_manager +require('~/extensions/array'); +require('~/filtered_search/filtered_search_tokenizer'); +require('~/filtered_search/filtered_search_dropdown_manager'); (() => { describe('Filtered Search Dropdown Manager', () => { diff --git a/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js.es6 b/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js.es6 index 6df7c0e44ef..7df9d9ec1cb 100644 --- a/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js.es6 +++ b/spec/javascripts/filtered_search/filtered_search_token_keys_spec.js.es6 @@ -1,5 +1,5 @@ -//= require extensions/array -//= require filtered_search/filtered_search_token_keys +require('~/extensions/array'); +require('~/filtered_search/filtered_search_token_keys'); (() => { describe('Filtered Search Token Keys', () => { diff --git a/spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js.es6 b/spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js.es6 index ac7f8e9cbcd..84c0e9cbfe2 100644 --- a/spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js.es6 +++ b/spec/javascripts/filtered_search/filtered_search_tokenizer_spec.js.es6 @@ -1,6 +1,6 @@ -//= require extensions/array -//= require filtered_search/filtered_search_token_keys -//= require filtered_search/filtered_search_tokenizer +require('~/extensions/array'); +require('~/filtered_search/filtered_search_token_keys'); +require('~/filtered_search/filtered_search_tokenizer'); (() => { describe('Filtered Search Tokenizer', () => { diff --git a/spec/javascripts/lib/utils/text_utility_spec.js.es6 b/spec/javascripts/lib/utils/text_utility_spec.js.es6 index e97356b65d5..976e24c4ea5 100644 --- a/spec/javascripts/lib/utils/text_utility_spec.js.es6 +++ b/spec/javascripts/lib/utils/text_utility_spec.js.es6 @@ -1,4 +1,4 @@ -//= require lib/utils/text_utility +require('~/lib/utils/text_utility'); (() => { describe('text_utility', () => { diff --git a/spec/javascripts/vue_pagination/pagination_spec.js.es6 b/spec/javascripts/vue_pagination/pagination_spec.js.es6 index 1a7f2bb5fb8..8935c474ee5 100644 --- a/spec/javascripts/vue_pagination/pagination_spec.js.es6 +++ b/spec/javascripts/vue_pagination/pagination_spec.js.es6 @@ -1,7 +1,5 @@ -//= require vue -//= require lib/utils/common_utils -//= require vue_pagination/index -/* global fixture, gl */ +require('~/lib/utils/common_utils'); +require('~/vue_pagination/index'); describe('Pagination component', () => { let component; @@ -17,7 +15,7 @@ describe('Pagination component', () => { }; it('should render and start at page 1', () => { - fixture.set('
    '); + setFixtures('
    '); component = new window.gl.VueGlPagination({ el: document.querySelector('.test-pagination-container'), @@ -40,7 +38,7 @@ describe('Pagination component', () => { }); it('should go to the previous page', () => { - fixture.set('
    '); + setFixtures('
    '); component = new window.gl.VueGlPagination({ el: document.querySelector('.test-pagination-container'), @@ -61,7 +59,7 @@ describe('Pagination component', () => { }); it('should go to the next page', () => { - fixture.set('
    '); + setFixtures('
    '); component = new window.gl.VueGlPagination({ el: document.querySelector('.test-pagination-container'), @@ -82,7 +80,7 @@ describe('Pagination component', () => { }); it('should go to the last page', () => { - fixture.set('
    '); + setFixtures('
    '); component = new window.gl.VueGlPagination({ el: document.querySelector('.test-pagination-container'), @@ -103,7 +101,7 @@ describe('Pagination component', () => { }); it('should go to the first page', () => { - fixture.set('
    '); + setFixtures('
    '); component = new window.gl.VueGlPagination({ el: document.querySelector('.test-pagination-container'), @@ -124,7 +122,7 @@ describe('Pagination component', () => { }); it('should do nothing', () => { - fixture.set('
    '); + setFixtures('
    '); component = new window.gl.VueGlPagination({ el: document.querySelector('.test-pagination-container'), -- cgit v1.2.1 From 6ad01a49d478460905da4596ad22061fa85d6873 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 13 Jan 2017 12:51:19 -0500 Subject: rewrite test which relied on teaspoon quirk --- spec/javascripts/lib/utils/common_utils_spec.js.es6 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/spec/javascripts/lib/utils/common_utils_spec.js.es6 b/spec/javascripts/lib/utils/common_utils_spec.js.es6 index bd9c82121a6..9e8456c03aa 100644 --- a/spec/javascripts/lib/utils/common_utils_spec.js.es6 +++ b/spec/javascripts/lib/utils/common_utils_spec.js.es6 @@ -42,9 +42,13 @@ require('~/lib/utils/common_utils'); }); describe('gl.utils.getParameterByName', () => { + beforeEach(() => { + window.history.pushState({}, null, '?scope=all&p=2'); + }); + it('should return valid parameter', () => { - const value = gl.utils.getParameterByName('reporter'); - expect(value).toBe('Console'); + const value = gl.utils.getParameterByName('scope'); + expect(value).toBe('all'); }); it('should return invalid parameter', () => { -- cgit v1.2.1 From 55fc4e8fd88e3ac813ba87ef6ec8f2d73354520d Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Fri, 13 Jan 2017 19:49:14 -0500 Subject: fix requireAll within filtered search bundle --- .../javascripts/filtered_search/filtered_search_bundle.js | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/filtered_search/filtered_search_bundle.js b/app/assets/javascripts/filtered_search/filtered_search_bundle.js index b4186f8376a..392f1835966 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_bundle.js +++ b/app/assets/javascripts/filtered_search/filtered_search_bundle.js @@ -1,9 +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. - // - function requireAll(context) { return context.keys().map(context); } +function requireAll(context) { return context.keys().map(context); } - requireAll(require.context('./', true, /^\.\/.*\.(js|es6)$/)); +requireAll(require.context('./', true, /^\.\/(?!filtered_search_bundle).*\.(js|es6)$/)); -- cgit v1.2.1 From 0ef0ead559300dca22ae0b6a792a1660424aa564 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Sat, 14 Jan 2017 14:50:22 -0500 Subject: fix missing components in cycle_analytics_bundle --- app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6 b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6 index 3b2f5efa27d..c41c57c1dcd 100644 --- a/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6 +++ b/app/assets/javascripts/cycle_analytics/cycle_analytics_bundle.js.es6 @@ -7,7 +7,7 @@ window.Cookies = require('vendor/js.cookie'); function requireAll(context) { return context.keys().map(context); } requireAll(require.context('./svg', false, /^\.\/.*\.(js|es6)$/)); -requireAll(require.context('.', false, /^\.\/(?!cycle_analytics_bundle).*\.(js|es6)$/)); +requireAll(require.context('.', true, /^\.\/(?!cycle_analytics_bundle).*\.(js|es6)$/)); $(() => { const OVERVIEW_DIALOG_COOKIE = 'cycle_analytics_help_dismissed'; -- cgit v1.2.1 From 8425e647fbd34c4c28d1d9df8fdf6495085a1f89 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Sat, 14 Jan 2017 15:17:04 -0500 Subject: add dependency license approvals see: https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/7288#note_21415733 --- config/dependency_decisions.yml | 121 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 111 insertions(+), 10 deletions(-) diff --git a/config/dependency_decisions.yml b/config/dependency_decisions.yml index c11296975b7..aabe859730a 100644 --- a/config/dependency_decisions.yml +++ b/config/dependency_decisions.yml @@ -1,9 +1,9 @@ --- -# IGNORED GROUPS AND GEMS - - :ignore_group - development - :who: Connor Shea - :why: Development gems are not distributed with the final product and are therefore exempt. + :why: Development gems are not distributed with the final product and are therefore + exempt. :versions: [] :when: 2016-04-17 21:27:01.054140000 Z - - :ignore_group @@ -18,8 +18,6 @@ :why: Bundler is MIT licensed but will sometimes fail in CI. :versions: [] :when: 2016-05-02 06:42:08.045090000 Z - -# LICENSE WHITELIST - - :whitelist - MIT - :who: Connor Shea @@ -86,9 +84,6 @@ :why: https://opensource.org/licenses/BSD-2-Clause :versions: [] :when: 2016-07-26 21:24:07.248480000 Z - - -# LICENSE BLACKLIST - - :blacklist - GPLv2 - :who: Connor Shea @@ -107,9 +102,6 @@ :why: The OSL license is a copyleft license :versions: [] :when: 2016-10-28 11:02:15.540105000 Z - - -# GEM LICENSES - - :license - raphael-rails - MIT @@ -201,3 +193,112 @@ :why: https://github.com/jmcnevin/rubypants/blob/master/LICENSE.rdoc :versions: [] :when: 2016-05-02 05:56:50.696858000 Z +- - :approve + - after + - :who: Matt Lee + :why: https://github.com/Raynos/after/blob/master/LICENCE + :versions: [] + :when: 2017-01-14 20:00:32.473125000 Z +- - :approve + - amdefine + - :who: Matt Lee + :why: MIT License + :versions: [] + :when: 2017-01-14 20:08:31.810633000 Z +- - :approve + - base64id + - :who: Matt Lee + :why: https://github.com/faeldt/base64id/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:08:33.174760000 Z +- - :approve + - blob + - :who: Matt Lee + :why: https://github.com/webmodules/blob/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:08:34.564048000 Z +- - :approve + - callsite + - :who: Matt Lee + :why: https://github.com/tj/callsite/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:08:35.976025000 Z +- - :approve + - component-bind + - :who: Matt Lee + :why: https://github.com/component/bind/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:08:37.291219000 Z +- - :approve + - component-inherit + - :who: Matt Lee + :why: https://github.com/component/inherit/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:10:41.804804000 Z +- - :approve + - fsevents + - :who: Matt Lee + :why: https://github.com/strongloop/fsevents/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:50:20.037775000 Z +- - :approve + - indexof + - :who: Matt Lee + :why: https://github.com/component/indexof/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:10:43.209900000 Z +- - :approve + - is-integer + - :who: Matt Lee + :why: https://github.com/parshap/js-is-integer/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:10:44.540916000 Z +- - :approve + - jsonify + - :who: Matt Lee + :why: Public Domain - no formal license on this one. probably okay as its been + the same for along time. would prefer to see CC0 + :versions: [] + :when: 2017-01-14 20:10:45.857261000 Z +- - :approve + - object-component + - :who: Matt Lee + :why: https://github.com/component/object/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:10:47.190148000 Z +- - :approve + - optimist + - :who: Matt Lee + :why: https://github.com/substack/node-optimist/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:10:48.563077000 Z +- - :approve + - path-is-inside + - :who: Matt Lee + :why: https://github.com/domenic/path-is-inside/blob/master/LICENSE.txt + :versions: [] + :when: 2017-01-14 20:10:49.910497000 Z +- - :approve + - rc + - :who: Matt Lee + :why: https://github.com/dominictarr/rc/blob/master/LICENSE.MIT + :versions: [] + :when: 2017-01-14 20:10:51.244695000 Z +- - :approve + - ripemd160 + - :who: Matt Lee + :why: https://github.com/crypto-browserify/ripemd160/blob/master/LICENSE.md + :versions: [] + :when: 2017-01-14 20:10:52.560282000 Z +- - :approve + - select2 + - :who: Matt Lee + :why: https://github.com/select2/select2/blob/master/LICENSE.md + :versions: [] + :when: 2017-01-14 20:10:53.909618000 Z +- - :approve + - tweetnacl + - :who: Matt Lee + :why: https://github.com/dchest/tweetnacl-js/blob/master/LICENSE + :versions: [] + :when: 2017-01-14 20:10:57.812077000 Z -- cgit v1.2.1 From c9dbd5f5130ea45ba83b0047bec47d222629c782 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Sun, 15 Jan 2017 01:44:47 -0500 Subject: optimize gitlab ci to only run npm install once --- .gitlab-ci.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index a038af69665..6d77d94637a 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -24,7 +24,6 @@ before_script: - '[ "$USE_BUNDLE_INSTALL" != "true" ] || retry bundle install --without postgres production --jobs $(nproc) $FLAGS' - retry gem install knapsack - '[ "$SETUP_DB" != "true" ] || bundle exec rake db:drop db:create db:schema:load db:migrate add_limits_mysql' - - npm install stages: - prepare @@ -109,12 +108,14 @@ setup-test-env: <<: *dedicated-runner stage: prepare script: + - npm install - bundle exec rake webpack:compile - bundle exec rake assets:precompile 2>/dev/null - bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init' artifacts: expire_in: 7d paths: + - node_modules - public/assets - tmp/tests @@ -235,7 +236,7 @@ spinach 9 10 ruby21: *spinach-knapsack-ruby21 script: - bundle exec $CI_BUILD_NAME -rubocop: +rubocop: <<: *ruby-static-analysis <<: *dedicated-runner stage: test @@ -298,7 +299,7 @@ karma: cache: paths: - vendor/ruby - - node_modules/ + - node_modules stage: test <<: *use-db <<: *dedicated-runner -- cgit v1.2.1 From 7c29f03e23c0a87b1dc9dacda173f40de17378eb Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Wed, 18 Jan 2017 13:25:10 -0600 Subject: ensure click event is bound only once --- app/assets/javascripts/diff.js.es6 | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/diff.js.es6 b/app/assets/javascripts/diff.js.es6 index 5e1a4c948aa..328d383a060 100644 --- a/app/assets/javascripts/diff.js.es6 +++ b/app/assets/javascripts/diff.js.es6 @@ -2,6 +2,7 @@ (() => { const UNFOLD_COUNT = 20; + let isBound = false; class Diff { constructor() { @@ -15,10 +16,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(); } -- cgit v1.2.1 From bc0a82334af7ef3a49067277cc5b7a7f3889658e Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Wed, 18 Jan 2017 13:55:46 -0600 Subject: ensure last line in diff block is contained within a table row element --- app/views/projects/diffs/_parallel_view.html.haml | 3 ++- app/views/projects/diffs/_text_file.html.haml | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml index b087485aa17..a25d7834c29 100644 --- a/app/views/projects/diffs/_parallel_view.html.haml +++ b/app/views/projects/diffs/_parallel_view.html.haml @@ -38,4 +38,5 @@ - if discussion_left || discussion_right = render "discussions/parallel_diff_discussion", discussion_left: discussion_left, discussion_right: discussion_right - if !diff_file.new_file && last_line > 0 - = diff_match_line last_line, last_line, bottom: true, view: :parallel + %tr.line_holder.parallel + = diff_match_line last_line, last_line, bottom: true, view: :parallel diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml index f1d2d4bf268..fa1b5d5f8ac 100644 --- a/app/views/projects/diffs/_text_file.html.haml +++ b/app/views/projects/diffs/_text_file.html.haml @@ -13,4 +13,5 @@ - last_line = diff_file.highlighted_diff_lines.last.new_pos - if !diff_file.new_file && last_line > 0 - = diff_match_line last_line, last_line, bottom: true + %tr.line_holder + = diff_match_line last_line, last_line, bottom: true -- cgit v1.2.1 From ece2e80bf88c594b454d8dce9d040f99725ef535 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Wed, 18 Jan 2017 15:03:12 -0600 Subject: ensure linenumber data attribute is correct for the last line in a diff chunk --- app/views/projects/blob/diff.html.haml | 2 +- app/views/projects/diffs/_parallel_view.html.haml | 7 +++---- app/views/projects/diffs/_text_file.html.haml | 7 +++---- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/app/views/projects/blob/diff.html.haml b/app/views/projects/blob/diff.html.haml index 538f8591f13..3b1a2e54ec2 100644 --- a/app/views/projects/blob/diff.html.haml +++ b/app/views/projects/blob/diff.html.haml @@ -27,4 +27,4 @@ - if @form.unfold? && @form.bottom? && @form.to < @blob.loc %tr.line_holder{ id: @form.to, class: line_class } - = diff_match_line @form.to, @form.to, text: @match_line, view: diff_view, bottom: true + = diff_match_line @form.to - @form.offset, @form.to, text: @match_line, view: diff_view, bottom: true diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml index a25d7834c29..8145d66f192 100644 --- a/app/views/projects/diffs/_parallel_view.html.haml +++ b/app/views/projects/diffs/_parallel_view.html.haml @@ -1,11 +1,9 @@ / Side-by-side diff view .text-file.diff-wrap-lines.code.js-syntax-highlight{ data: diff_view_data } %table - - last_line = 0 - diff_file.parallel_diff_lines.each do |line| - left = line[:left] - right = line[:right] - - last_line = right.new_pos if right %tr.line_holder.parallel - if left - if left.meta? @@ -37,6 +35,7 @@ - discussion_left, discussion_right = parallel_diff_discussions(left, right, diff_file) - if discussion_left || discussion_right = render "discussions/parallel_diff_discussion", discussion_left: discussion_left, discussion_right: discussion_right - - if !diff_file.new_file && last_line > 0 + - if !diff_file.new_file && diff_file.diff_lines.any? + - last_line = diff_file.diff_lines.last %tr.line_holder.parallel - = diff_match_line last_line, last_line, bottom: true, view: :parallel + = diff_match_line last_line.old_pos, last_line.new_pos, bottom: true, view: :parallel diff --git a/app/views/projects/diffs/_text_file.html.haml b/app/views/projects/diffs/_text_file.html.haml index fa1b5d5f8ac..2eea1db169a 100644 --- a/app/views/projects/diffs/_text_file.html.haml +++ b/app/views/projects/diffs/_text_file.html.haml @@ -4,14 +4,13 @@ %a.show-suppressed-diff.js-show-suppressed-diff Changes suppressed. Click to show. %table.text-file.code.js-syntax-highlight{ data: diff_view_data, class: too_big ? 'hide' : '' } - - last_line = 0 - discussions = @grouped_diff_discussions unless @diff_notes_disabled = render partial: "projects/diffs/line", collection: diff_file.highlighted_diff_lines, as: :line, locals: { diff_file: diff_file, discussions: discussions } - - last_line = diff_file.highlighted_diff_lines.last.new_pos - - if !diff_file.new_file && last_line > 0 + - if !diff_file.new_file && diff_file.highlighted_diff_lines.any? + - last_line = diff_file.highlighted_diff_lines.last %tr.line_holder - = diff_match_line last_line, last_line, bottom: true + = diff_match_line last_line.old_pos, last_line.new_pos, bottom: true -- cgit v1.2.1 From 7c583293cda3be8def5c665000a540124c838122 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Wed, 18 Jan 2017 16:40:34 -0600 Subject: prevent nonewline type diff lines from containing unfolding link --- app/views/projects/diffs/_parallel_view.html.haml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/app/views/projects/diffs/_parallel_view.html.haml b/app/views/projects/diffs/_parallel_view.html.haml index b087485aa17..cbd021487ef 100644 --- a/app/views/projects/diffs/_parallel_view.html.haml +++ b/app/views/projects/diffs/_parallel_view.html.haml @@ -8,8 +8,12 @@ - last_line = right.new_pos if right %tr.line_holder.parallel - if left - - if left.meta? + - case left.type + - when 'match' = diff_match_line left.old_pos, nil, text: left.text, view: :parallel + - when 'nonewline' + %td.old_line.diff-line-num + %td.line_content.match= left.text - else - left_line_code = diff_file.line_code(left) - left_position = diff_file.position(left) @@ -21,8 +25,12 @@ %td.line_content.parallel - if right - - if right.meta? + - case right.type + - when 'match' = diff_match_line nil, right.new_pos, text: left.text, view: :parallel + - when 'nonewline' + %td.new_line.diff-line-num + %td.line_content.match= right.text - else - right_line_code = diff_file.line_code(right) - right_position = diff_file.position(right) -- cgit v1.2.1 From c5b7cc54e9bfceda7d48b1f15bcf064a0d96c07d Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Thu, 19 Jan 2017 09:41:38 +0000 Subject: Use webpack_port file if it exists --- config/environments/development.rb | 4 ++++ config/webpack.config.js | 9 ++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/config/environments/development.rb b/config/environments/development.rb index 168c434f261..f8cf196bc7c 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,4 +1,6 @@ Rails.application.configure do + WEBPACK_DEV_PORT = `cat ../webpack_port 2>/dev/null || echo '3808'`.to_i + # Settings specified here will take precedence over those in config/application.rb # In the development environment your application's code is reloaded on @@ -24,6 +26,8 @@ Rails.application.configure do # Enable webpack dev server config.webpack.dev_server.enabled = true + config.webpack.dev_server.port = WEBPACK_DEV_PORT + config.webpack.dev_server.manifest_port = WEBPACK_DEV_PORT # Do not compress assets config.assets.compress = false diff --git a/config/webpack.config.js b/config/webpack.config.js index 762147e8b06..bddd181b452 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -1,5 +1,6 @@ 'use strict'; +var fs = require('fs'); var path = require('path'); var webpack = require('webpack'); var StatsPlugin = require('stats-webpack-plugin'); @@ -10,7 +11,13 @@ var IS_DEV_SERVER = process.argv[1].indexOf('webpack-dev-server') !== -1; var ROOT_PATH = path.resolve(__dirname, '..'); // must match config.webpack.dev_server.port -var DEV_SERVER_PORT = 3808; +var DEV_SERVER_PORT; + +try { + DEV_SERVER_PORT = parseInt(fs.readFileSync('../webpack_port'), 10); +} catch (e) { + DEV_SERVER_PORT = 3808; +} var config = { context: path.join(ROOT_PATH, 'app/assets/javascripts'), -- cgit v1.2.1 From a5f7934420e1d26682700e02aa8fc9333e808f47 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Sat, 28 Jan 2017 10:20:17 -0600 Subject: remove sprockets-es6 and execjs dependencies --- Gemfile | 1 - Gemfile.lock | 9 --------- 2 files changed, 10 deletions(-) diff --git a/Gemfile b/Gemfile index f7886b1ff6a..e38dcae70ce 100644 --- a/Gemfile +++ b/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' diff --git a/Gemfile.lock b/Gemfile.lock index 25c722165cf..b1ef956c32c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -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) @@ -733,10 +729,6 @@ GEM 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) @@ -986,7 +978,6 @@ DEPENDENCIES spring-commands-rspec (~> 1.0.4) spring-commands-spinach (~> 1.1.0) sprockets (~> 3.7.0) - sprockets-es6 (~> 0.9.2) stackprof (~> 0.2.10) state_machines-activerecord (~> 0.4.0) sys-filesystem (~> 1.1.6) -- cgit v1.2.1 From 7c5d4942742cf8d5c942fba0888eaab5e1133fb4 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Sat, 28 Jan 2017 11:38:30 -0600 Subject: fix frontend tests --- spec/javascripts/commits_spec.js.es6 | 20 ++++++++++++++++---- .../filtered_search_manager_spec.js.es6 | 11 +++++------ 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/spec/javascripts/commits_spec.js.es6 b/spec/javascripts/commits_spec.js.es6 index bb9a9072f3a..05260760c43 100644 --- a/spec/javascripts/commits_spec.js.es6 +++ b/spec/javascripts/commits_spec.js.es6 @@ -1,10 +1,19 @@ /* global CommitsList */ -//= require jquery.endless-scroll -//= require pager -//= require commits +require('vendor/jquery.endless-scroll'); +require('~/pager'); +require('~/commits'); (() => { + // TODO: remove this hack! + // PhantomJS causes spyOn to panic because replaceState isn't "writable" + let phantomjs; + try { + phantomjs = !Object.getOwnPropertyDescriptor(window.history, 'replaceState').writable; + } catch (err) { + phantomjs = false; + } + describe('Commits List', () => { beforeEach(() => { setFixtures(` @@ -25,7 +34,10 @@ beforeEach(() => { CommitsList.init(25); CommitsList.searchField.val(''); - spyOn(history, 'replaceState').and.stub(); + + if (!phantomjs) { + spyOn(history, 'replaceState').and.stub(); + } ajaxSpy = spyOn(jQuery, 'ajax').and.callFake((req) => { req.success({ data: '
  • Result
  • ', diff --git a/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6 b/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6 index c8b5c2b36ad..1a06b60b2c2 100644 --- a/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6 +++ b/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6 @@ -1,11 +1,10 @@ /* global Turbolinks */ -//= require turbolinks -//= require lib/utils/common_utils -//= require filtered_search/filtered_search_token_keys -//= require filtered_search/filtered_search_tokenizer -//= require filtered_search/filtered_search_dropdown_manager -//= require filtered_search/filtered_search_manager +require('~/lib/utils/common_utils'); +require('~/filtered_search/filtered_search_token_keys'); +require('~/filtered_search/filtered_search_tokenizer'); +require('~/filtered_search/filtered_search_dropdown_manager'); +require('~/filtered_search/filtered_search_manager'); (() => { describe('Filtered Search Manager', () => { -- cgit v1.2.1 From abb122a44f750f8f4f5a784acb6e53db0743b789 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Sat, 28 Jan 2017 11:42:48 -0600 Subject: update rake tasks --- .gitlab-ci.yml | 3 +-- lib/tasks/gitlab/assets.rake | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 588f5b59e4c..1772fda9225 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -108,8 +108,7 @@ setup-test-env: stage: prepare script: - npm install - - bundle exec rake webpack:compile - - bundle exec rake gitlab:assets:compile 2>/dev/null + - bundle exec rake gitlab:assets:compile - bundle exec ruby -Ispec -e 'require "spec_helper" ; TestEnv.init' artifacts: expire_in: 7d diff --git a/lib/tasks/gitlab/assets.rake b/lib/tasks/gitlab/assets.rake index 5d884bf9f66..b6ef8260191 100644 --- a/lib/tasks/gitlab/assets.rake +++ b/lib/tasks/gitlab/assets.rake @@ -3,6 +3,7 @@ namespace :gitlab do desc 'GitLab | Assets | Compile all frontend assets' task :compile do Rake::Task['assets:precompile'].invoke + Rake::Task['webpack:compile'].invoke Rake::Task['gitlab:assets:fix_urls'].invoke end -- cgit v1.2.1 From 3ee67bcf25d87dff35b3f8fcfb16345b36b3d58f Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Sat, 28 Jan 2017 12:13:34 -0600 Subject: fix duplicate data-toggle attribute --- app/assets/javascripts/vue_pipelines_index/pipeline_actions.js.es6 | 2 -- 1 file changed, 2 deletions(-) diff --git a/app/assets/javascripts/vue_pipelines_index/pipeline_actions.js.es6 b/app/assets/javascripts/vue_pipelines_index/pipeline_actions.js.es6 index b195b0ef3ba..a7176e27ea1 100644 --- a/app/assets/javascripts/vue_pipelines_index/pipeline_actions.js.es6 +++ b/app/assets/javascripts/vue_pipelines_index/pipeline_actions.js.es6 @@ -28,7 +28,6 @@ data-toggle="dropdown" title="Manual build" data-placement="top" - data-toggle="dropdown" aria-label="Manual build" > @@ -54,7 +53,6 @@ data-toggle="dropdown" title="Artifacts" data-placement="top" - data-toggle="dropdown" aria-label="Artifacts" > -- cgit v1.2.1 From 5e1243b0d6d53abc70733d9cf15cbd3ca2b4bf29 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Sat, 28 Jan 2017 15:41:40 -0600 Subject: fix test failure for merge request widget --- .../merge_requests/widget/open/_merge_when_build_succeeds.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml index f70cd09c5f4..648a1e4cf33 100644 --- a/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml +++ b/app/views/projects/merge_requests/widget/open/_merge_when_build_succeeds.html.haml @@ -1,5 +1,5 @@ - content_for :page_specific_javascripts do - = page_specific_javascript_tag('merge_request_widget/ci_bundle.js') + = page_specific_javascript_bundle_tag('merge_request_widget') %h4 Set by #{link_to_member(@project, @merge_request.merge_user, avatar: true)} -- cgit v1.2.1 From 356368d959dedce2ff83ae6caff4114444465389 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Sat, 28 Jan 2017 16:30:43 -0600 Subject: fix failing rspec build --- app/assets/javascripts/merge_request.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/merge_request.js b/app/assets/javascripts/merge_request.js index d4e7fe235ad..8762ec35b80 100644 --- a/app/assets/javascripts/merge_request.js +++ b/app/assets/javascripts/merge_request.js @@ -110,9 +110,8 @@ require('./merge_request_tabs'); }; 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 @@ require('./merge_request_tabs'); $('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')); -- cgit v1.2.1 From ecdcd1be87e140c144bb2afc861a1dc56b297cdd Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Sun, 29 Jan 2017 20:05:27 -0600 Subject: add CHAGELOG.md entry for webpack branch --- changelogs/unreleased/go-go-gadget-webpack.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelogs/unreleased/go-go-gadget-webpack.yml diff --git a/changelogs/unreleased/go-go-gadget-webpack.yml b/changelogs/unreleased/go-go-gadget-webpack.yml new file mode 100644 index 00000000000..7f372ccb428 --- /dev/null +++ b/changelogs/unreleased/go-go-gadget-webpack.yml @@ -0,0 +1,4 @@ +--- +title: use webpack to bundle frontend assets and use karma for frontend testing +merge_request: 7288 +author: -- cgit v1.2.1 From cc24682b58a66a217e6ffa1d56f8d45900c10d03 Mon Sep 17 00:00:00 2001 From: Oswaldo Ferreira Date: Fri, 27 Jan 2017 15:56:40 -0200 Subject: Unify projects search by removing /projects/:search endpoint --- .../unreleased/22007-unify-projects-search.yml | 4 ++ lib/api/projects.rb | 16 -------- spec/requests/api/projects_spec.rb | 46 ---------------------- 3 files changed, 4 insertions(+), 62 deletions(-) create mode 100644 changelogs/unreleased/22007-unify-projects-search.yml diff --git a/changelogs/unreleased/22007-unify-projects-search.yml b/changelogs/unreleased/22007-unify-projects-search.yml new file mode 100644 index 00000000000..f43c1925ad0 --- /dev/null +++ b/changelogs/unreleased/22007-unify-projects-search.yml @@ -0,0 +1,4 @@ +--- +title: Unify projects search by removing /projects/:search endpoint +merge_request: 8877 +author: diff --git a/lib/api/projects.rb b/lib/api/projects.rb index 941f47114a4..92a70faf1c2 100644 --- a/lib/api/projects.rb +++ b/lib/api/projects.rb @@ -151,22 +151,6 @@ module API present_projects Project.all, with: Entities::ProjectWithAccess, statistics: params[:statistics] end - desc 'Search for projects the current user has access to' do - success Entities::Project - end - params do - requires :query, type: String, desc: 'The project name to be searched' - use :sort_params - use :pagination - end - get "/search/:query", requirements: { query: /[^\/]+/ } do - search_service = Search::GlobalService.new(current_user, search: params[:query]).execute - projects = search_service.objects('projects', params[:page]) - projects = projects.reorder(params[:order_by] => params[:sort]) - - present paginate(projects), with: Entities::Project - end - desc 'Create new project' do success Entities::Project end diff --git a/spec/requests/api/projects_spec.rb b/spec/requests/api/projects_spec.rb index a1db81ce18c..8b04748b3b0 100644 --- a/spec/requests/api/projects_spec.rb +++ b/spec/requests/api/projects_spec.rb @@ -1085,52 +1085,6 @@ describe API::Projects, api: true do end end - describe 'GET /projects/search/:query' do - let!(:query) { 'query'} - let!(:search) { create(:empty_project, name: query, creator_id: user.id, namespace: user.namespace) } - let!(:pre) { create(:empty_project, name: "pre_#{query}", creator_id: user.id, namespace: user.namespace) } - let!(:post) { create(:empty_project, name: "#{query}_post", creator_id: user.id, namespace: user.namespace) } - let!(:pre_post) { create(:empty_project, name: "pre_#{query}_post", creator_id: user.id, namespace: user.namespace) } - let!(:unfound) { create(:empty_project, name: 'unfound', creator_id: user.id, namespace: user.namespace) } - let!(:internal) { create(:empty_project, :internal, name: "internal #{query}") } - let!(:unfound_internal) { create(:empty_project, :internal, name: 'unfound internal') } - let!(:public) { create(:empty_project, :public, name: "public #{query}") } - let!(:unfound_public) { create(:empty_project, :public, name: 'unfound public') } - let!(:one_dot_two) { create(:empty_project, :public, name: "one.dot.two") } - - shared_examples_for 'project search response' do |args = {}| - it 'returns project search responses' do - get api("/projects/search/#{args[:query]}", current_user) - - expect(response).to have_http_status(200) - expect(json_response).to be_an Array - expect(json_response.size).to eq(args[:results]) - json_response.each { |project| expect(project['name']).to match(args[:match_regex] || /.*#{args[:query]}.*/) } - end - end - - context 'when unauthenticated' do - it_behaves_like 'project search response', query: 'query', results: 1 do - let(:current_user) { nil } - end - end - - context 'when authenticated' do - it_behaves_like 'project search response', query: 'query', results: 6 do - let(:current_user) { user } - end - it_behaves_like 'project search response', query: 'one.dot.two', results: 1 do - let(:current_user) { user } - end - end - - context 'when authenticated as a different user' do - it_behaves_like 'project search response', query: 'query', results: 2, match_regex: /(internal|public) query/ do - let(:current_user) { user2 } - end - end - end - describe 'PUT /projects/:id' do before { project } before { user } -- cgit v1.2.1 From e8f4f30627c07cbca26e7ce292cad7942ca76d0d Mon Sep 17 00:00:00 2001 From: Nur Rony Date: Wed, 25 Jan 2017 16:36:40 +0600 Subject: layout rearranged --- app/views/admin/projects/index.html.haml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index 2e6f03fcde0..5936312801b 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -27,7 +27,7 @@ = icon("search", class: "search-icon") .dropdown - - toggle_text = 'Search for Namespace' + - toggle_text = 'Namespace' - if params[:namespace_id].present? - namespace = Namespace.find(params[:namespace_id]) - toggle_text = "#{namespace.kind}: #{namespace.path}" @@ -37,8 +37,9 @@ = dropdown_filter("Search for Namespace") = dropdown_content = dropdown_loading - - = button_tag "Search", class: "btn btn-primary btn-search" + = render 'shared/projects/dropdown' + = link_to new_project_path, class: 'btn btn-new' do + New Project %ul.nav-links - opts = params[:visibility_level].present? ? {} : { page: admin_projects_path } @@ -56,11 +57,6 @@ = link_to admin_projects_path(visibility_level: Gitlab::VisibilityLevel::PUBLIC) do Public - .nav-controls - = render 'shared/projects/dropdown' - = link_to new_project_path, class: 'btn btn-new' do - New Project - .projects-list-holder - if @projects.any? %ul.projects-list.content-list -- cgit v1.2.1 From cadef802758ce4cf0b59849ca4613545967c2da6 Mon Sep 17 00:00:00 2001 From: Oswaldo Ferreira Date: Mon, 30 Jan 2017 15:41:56 -0200 Subject: Remain V3 endpoint unchanged --- lib/api/api.rb | 7 +- lib/api/v3/projects.rb | 458 +++++++++++ spec/requests/api/v3/projects_spec.rb | 1424 +++++++++++++++++++++++++++++++++ spec/support/api_helpers.rb | 9 +- 4 files changed, 1895 insertions(+), 3 deletions(-) create mode 100644 lib/api/v3/projects.rb create mode 100644 spec/requests/api/v3/projects_spec.rb diff --git a/lib/api/api.rb b/lib/api/api.rb index 6cf6b501021..090109d5e6f 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -1,7 +1,12 @@ module API class API < Grape::API include APIGuard - version 'v3', using: :path + + version %w(v3 v4), using: :path + + version 'v3', using: :path do + mount ::API::V3::Projects + end before { allow_access_with_scope :api } diff --git a/lib/api/v3/projects.rb b/lib/api/v3/projects.rb new file mode 100644 index 00000000000..bac7d485a22 --- /dev/null +++ b/lib/api/v3/projects.rb @@ -0,0 +1,458 @@ +module API + module V3 + class Projects < Grape::API + include PaginationParams + + before { authenticate_non_get! } + + helpers do + params :optional_params do + optional :description, type: String, desc: 'The description of the project' + optional :issues_enabled, type: Boolean, desc: 'Flag indication if the issue tracker is enabled' + optional :merge_requests_enabled, type: Boolean, desc: 'Flag indication if merge requests are enabled' + optional :wiki_enabled, type: Boolean, desc: 'Flag indication if the wiki is enabled' + optional :builds_enabled, type: Boolean, desc: 'Flag indication if builds are enabled' + optional :snippets_enabled, type: Boolean, desc: 'Flag indication if snippets are enabled' + optional :shared_runners_enabled, type: Boolean, desc: 'Flag indication if shared runners are enabled for that project' + optional :container_registry_enabled, type: Boolean, desc: 'Flag indication if the container registry is enabled for that project' + optional :lfs_enabled, type: Boolean, desc: 'Flag indication if Git LFS is enabled for that project' + optional :public, type: Boolean, desc: 'Create a public project. The same as visibility_level = 20.' + optional :visibility_level, type: Integer, values: [ + Gitlab::VisibilityLevel::PRIVATE, + Gitlab::VisibilityLevel::INTERNAL, + Gitlab::VisibilityLevel::PUBLIC ], desc: 'Create a public project. The same as visibility_level = 20.' + optional :public_builds, type: Boolean, desc: 'Perform public builds' + optional :request_access_enabled, type: Boolean, desc: 'Allow users to request member access' + optional :only_allow_merge_if_build_succeeds, type: Boolean, desc: 'Only allow to merge if builds succeed' + optional :only_allow_merge_if_all_discussions_are_resolved, type: Boolean, desc: 'Only allow to merge if all discussions are resolved' + end + + def map_public_to_visibility_level(attrs) + publik = attrs.delete(:public) + if !publik.nil? && !attrs[:visibility_level].present? + # Since setting the public attribute to private could mean either + # private or internal, use the more conservative option, private. + attrs[:visibility_level] = (publik == true) ? Gitlab::VisibilityLevel::PUBLIC : Gitlab::VisibilityLevel::PRIVATE + end + attrs + end + end + + resource :projects do + helpers do + params :collection_params do + use :sort_params + use :filter_params + use :pagination + + optional :simple, type: Boolean, default: false, + desc: 'Return only the ID, URL, name, and path of each project' + end + + params :sort_params do + optional :order_by, type: String, values: %w[id name path created_at updated_at last_activity_at], + default: 'created_at', desc: 'Return projects ordered by field' + optional :sort, type: String, values: %w[asc desc], default: 'desc', + desc: 'Return projects sorted in ascending and descending order' + end + + params :filter_params do + optional :archived, type: Boolean, default: false, desc: 'Limit by archived status' + optional :visibility, type: String, values: %w[public internal private], + desc: 'Limit by visibility' + optional :search, type: String, desc: 'Return list of authorized projects matching the search criteria' + end + + params :statistics_params do + optional :statistics, type: Boolean, default: false, desc: 'Include project statistics' + end + + params :create_params do + optional :namespace_id, type: Integer, desc: 'Namespace ID for the new project. Default to the user namespace.' + optional :import_url, type: String, desc: 'URL from which the project is imported' + end + + def present_projects(projects, options = {}) + options = options.reverse_merge( + with: Entities::Project, + current_user: current_user, + simple: params[:simple], + ) + + projects = filter_projects(projects) + projects = projects.with_statistics if options[:statistics] + options[:with] = Entities::BasicProjectDetails if options[:simple] + + present paginate(projects), options + end + end + + desc 'Get a list of visible projects for authenticated user' do + success Entities::BasicProjectDetails + end + params do + use :collection_params + end + get '/visible' do + entity = current_user ? Entities::ProjectWithAccess : Entities::BasicProjectDetails + present_projects ProjectsFinder.new.execute(current_user), with: entity + end + + desc 'Get a projects list for authenticated user' do + success Entities::BasicProjectDetails + end + params do + use :collection_params + end + get do + authenticate! + + present_projects current_user.authorized_projects, + with: Entities::ProjectWithAccess + end + + desc 'Get an owned projects list for authenticated user' do + success Entities::BasicProjectDetails + end + params do + use :collection_params + use :statistics_params + end + get '/owned' do + authenticate! + + present_projects current_user.owned_projects, + with: Entities::ProjectWithAccess, + statistics: params[:statistics] + end + + desc 'Gets starred project for the authenticated user' do + success Entities::BasicProjectDetails + end + params do + use :collection_params + end + get '/starred' do + authenticate! + + present_projects current_user.viewable_starred_projects + end + + desc 'Get all projects for admin user' do + success Entities::BasicProjectDetails + end + params do + use :collection_params + use :statistics_params + end + get '/all' do + authenticated_as_admin! + + present_projects Project.all, with: Entities::ProjectWithAccess, statistics: params[:statistics] + end + + desc 'Search for projects the current user has access to' do + success Entities::Project + end + params do + requires :query, type: String, desc: 'The project name to be searched' + use :sort_params + use :pagination + end + get "/search/:query", requirements: { query: /[^\/]+/ } do + search_service = Search::GlobalService.new(current_user, search: params[:query]).execute + projects = search_service.objects('projects', params[:page]) + projects = projects.reorder(params[:order_by] => params[:sort]) + + present paginate(projects), with: Entities::Project + end + + desc 'Create new project' do + success Entities::Project + end + params do + requires :name, type: String, desc: 'The name of the project' + optional :path, type: String, desc: 'The path of the repository' + use :optional_params + use :create_params + end + post do + attrs = map_public_to_visibility_level(declared_params(include_missing: false)) + project = ::Projects::CreateService.new(current_user, attrs).execute + + if project.saved? + present project, with: Entities::Project, + user_can_admin_project: can?(current_user, :admin_project, project) + else + if project.errors[:limit_reached].present? + error!(project.errors[:limit_reached], 403) + end + render_validation_error!(project) + end + end + + desc 'Create new project for a specified user. Only available to admin users.' do + success Entities::Project + end + params do + requires :name, type: String, desc: 'The name of the project' + requires :user_id, type: Integer, desc: 'The ID of a user' + optional :default_branch, type: String, desc: 'The default branch of the project' + use :optional_params + use :create_params + end + post "user/:user_id" do + authenticated_as_admin! + user = User.find_by(id: params.delete(:user_id)) + not_found!('User') unless user + + attrs = map_public_to_visibility_level(declared_params(include_missing: false)) + project = ::Projects::CreateService.new(user, attrs).execute + + if project.saved? + present project, with: Entities::Project, + user_can_admin_project: can?(current_user, :admin_project, project) + else + render_validation_error!(project) + end + end + end + + params do + requires :id, type: String, desc: 'The ID of a project' + end + resource :projects, requirements: { id: /[^\/]+/ } do + desc 'Get a single project' do + success Entities::ProjectWithAccess + end + get ":id" do + entity = current_user ? Entities::ProjectWithAccess : Entities::BasicProjectDetails + present user_project, with: entity, current_user: current_user, + user_can_admin_project: can?(current_user, :admin_project, user_project) + end + + desc 'Get events for a single project' do + success Entities::Event + end + params do + use :pagination + end + get ":id/events" do + present paginate(user_project.events.recent), with: Entities::Event + end + + desc 'Fork new project for the current user or provided namespace.' do + success Entities::Project + end + params do + optional :namespace, type: String, desc: 'The ID or name of the namespace that the project will be forked into' + end + post 'fork/:id' do + fork_params = declared_params(include_missing: false) + namespace_id = fork_params[:namespace] + + if namespace_id.present? + fork_params[:namespace] = if namespace_id =~ /^\d+$/ + Namespace.find_by(id: namespace_id) + else + Namespace.find_by_path_or_name(namespace_id) + end + + unless fork_params[:namespace] && can?(current_user, :create_projects, fork_params[:namespace]) + not_found!('Target Namespace') + end + end + + forked_project = ::Projects::ForkService.new(user_project, current_user, fork_params).execute + + if forked_project.errors.any? + conflict!(forked_project.errors.messages) + else + present forked_project, with: Entities::Project, + user_can_admin_project: can?(current_user, :admin_project, forked_project) + end + end + + desc 'Update an existing project' do + success Entities::Project + end + params do + optional :name, type: String, desc: 'The name of the project' + optional :default_branch, type: String, desc: 'The default branch of the project' + optional :path, type: String, desc: 'The path of the repository' + use :optional_params + at_least_one_of :name, :description, :issues_enabled, :merge_requests_enabled, + :wiki_enabled, :builds_enabled, :snippets_enabled, + :shared_runners_enabled, :container_registry_enabled, + :lfs_enabled, :public, :visibility_level, :public_builds, + :request_access_enabled, :only_allow_merge_if_build_succeeds, + :only_allow_merge_if_all_discussions_are_resolved, :path, + :default_branch + end + put ':id' do + authorize_admin_project + attrs = map_public_to_visibility_level(declared_params(include_missing: false)) + authorize! :rename_project, user_project if attrs[:name].present? + authorize! :change_visibility_level, user_project if attrs[:visibility_level].present? + + result = ::Projects::UpdateService.new(user_project, current_user, attrs).execute + + if result[:status] == :success + present user_project, with: Entities::Project, + user_can_admin_project: can?(current_user, :admin_project, user_project) + else + render_validation_error!(user_project) + end + end + + desc 'Archive a project' do + success Entities::Project + end + post ':id/archive' do + authorize!(:archive_project, user_project) + + user_project.archive! + + present user_project, with: Entities::Project + end + + desc 'Unarchive a project' do + success Entities::Project + end + post ':id/unarchive' do + authorize!(:archive_project, user_project) + + user_project.unarchive! + + present user_project, with: Entities::Project + end + + desc 'Star a project' do + success Entities::Project + end + post ':id/star' do + if current_user.starred?(user_project) + not_modified! + else + current_user.toggle_star(user_project) + user_project.reload + + present user_project, with: Entities::Project + end + end + + desc 'Unstar a project' do + success Entities::Project + end + delete ':id/star' do + if current_user.starred?(user_project) + current_user.toggle_star(user_project) + user_project.reload + + present user_project, with: Entities::Project + else + not_modified! + end + end + + desc 'Remove a project' + delete ":id" do + authorize! :remove_project, user_project + ::Projects::DestroyService.new(user_project, current_user, {}).async_execute + end + + desc 'Mark this project as forked from another' + params do + requires :forked_from_id, type: String, desc: 'The ID of the project it was forked from' + end + post ":id/fork/:forked_from_id" do + authenticated_as_admin! + + forked_from_project = find_project!(params[:forked_from_id]) + not_found!("Source Project") unless forked_from_project + + if user_project.forked_from_project.nil? + user_project.create_forked_project_link(forked_to_project_id: user_project.id, forked_from_project_id: forked_from_project.id) + else + render_api_error!("Project already forked", 409) + end + end + + desc 'Remove a forked_from relationship' + delete ":id/fork" do + authorize! :remove_fork_project, user_project + + if user_project.forked? + user_project.forked_project_link.destroy + else + not_modified! + end + end + + desc 'Share the project with a group' do + success Entities::ProjectGroupLink + end + params do + requires :group_id, type: Integer, desc: 'The ID of a group' + requires :group_access, type: Integer, values: Gitlab::Access.values, desc: 'The group access level' + optional :expires_at, type: Date, desc: 'Share expiration date' + end + post ":id/share" do + authorize! :admin_project, user_project + group = Group.find_by_id(params[:group_id]) + + unless group && can?(current_user, :read_group, group) + not_found!('Group') + end + + unless user_project.allowed_to_share_with_group? + return render_api_error!("The project sharing with group is disabled", 400) + end + + link = user_project.project_group_links.new(declared_params(include_missing: false)) + + if link.save + present link, with: Entities::ProjectGroupLink + else + render_api_error!(link.errors.full_messages.first, 409) + end + end + + params do + requires :group_id, type: Integer, desc: 'The ID of the group' + end + delete ":id/share/:group_id" do + authorize! :admin_project, user_project + + link = user_project.project_group_links.find_by(group_id: params[:group_id]) + not_found!('Group Link') unless link + + link.destroy + no_content! + end + + desc 'Upload a file' + params do + requires :file, type: File, desc: 'The file to be uploaded' + end + post ":id/uploads" do + ::Projects::UploadService.new(user_project, params[:file]).execute + end + + desc 'Get the users list of a project' do + success Entities::UserBasic + end + params do + optional :search, type: String, desc: 'Return list of users matching the search criteria' + use :pagination + end + get ':id/users' do + users = user_project.team.users + users = users.search(params[:search]) if params[:search].present? + + present paginate(users), with: Entities::UserBasic + end + end + end + end +end diff --git a/spec/requests/api/v3/projects_spec.rb b/spec/requests/api/v3/projects_spec.rb new file mode 100644 index 00000000000..c3f53d0da37 --- /dev/null +++ b/spec/requests/api/v3/projects_spec.rb @@ -0,0 +1,1424 @@ +require 'spec_helper' + +describe API::V3::Projects, v3_api: true do + include ApiHelpers + include Gitlab::CurrentSettings + + let(:user) { create(:user) } + let(:user2) { create(:user) } + let(:user3) { create(:user) } + let(:admin) { create(:admin) } + let(:project) { create(:empty_project, creator_id: user.id, namespace: user.namespace) } + let(:project2) { create(:empty_project, path: 'project2', creator_id: user.id, namespace: user.namespace) } + let(:snippet) { create(:project_snippet, :public, author: user, project: project, title: 'example') } + let(:project_member) { create(:project_member, :master, user: user, project: project) } + let(:project_member2) { create(:project_member, :developer, user: user3, project: project) } + let(:user4) { create(:user) } + let(:project3) do + create(:project, + :private, + :repository, + name: 'second_project', + path: 'second_project', + creator_id: user.id, + namespace: user.namespace, + merge_requests_enabled: false, + issues_enabled: false, wiki_enabled: false, + snippets_enabled: false) + end + let(:project_member3) do + create(:project_member, + user: user4, + project: project3, + access_level: ProjectMember::MASTER) + end + let(:project4) do + create(:empty_project, + name: 'third_project', + path: 'third_project', + creator_id: user4.id, + namespace: user4.namespace) + end + + describe 'GET /projects' do + before { project } + + context 'when unauthenticated' do + it 'returns authentication error' do + get v3_api('/projects') + expect(response).to have_http_status(401) + end + end + + context 'when authenticated as regular user' do + it 'returns an array of projects' do + get v3_api('/projects', user) + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.first['name']).to eq(project.name) + expect(json_response.first['owner']['username']).to eq(user.username) + end + + it 'includes the project labels as the tag_list' do + get v3_api('/projects', user) + expect(response.status).to eq 200 + expect(json_response).to be_an Array + expect(json_response.first.keys).to include('tag_list') + end + + it 'includes open_issues_count' do + get v3_api('/projects', user) + expect(response.status).to eq 200 + expect(json_response).to be_an Array + expect(json_response.first.keys).to include('open_issues_count') + end + + it 'does not include open_issues_count' do + project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED) + + get v3_api('/projects', user) + expect(response.status).to eq 200 + expect(json_response).to be_an Array + expect(json_response.first.keys).not_to include('open_issues_count') + end + + context 'GET /projects?simple=true' do + it 'returns a simplified version of all the projects' do + expected_keys = ["id", "http_url_to_repo", "web_url", "name", "name_with_namespace", "path", "path_with_namespace"] + + get v3_api('/projects?simple=true', user) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.first.keys).to match_array expected_keys + end + end + + context 'and using search' do + it 'returns searched project' do + get v3_api('/projects', user), { search: project.name } + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(1) + end + end + + context 'and using the visibility filter' do + it 'filters based on private visibility param' do + get v3_api('/projects', user), { visibility: 'private' } + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(user.namespace.projects.where(visibility_level: Gitlab::VisibilityLevel::PRIVATE).count) + end + + it 'filters based on internal visibility param' do + get v3_api('/projects', user), { visibility: 'internal' } + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(user.namespace.projects.where(visibility_level: Gitlab::VisibilityLevel::INTERNAL).count) + end + + it 'filters based on public visibility param' do + get v3_api('/projects', user), { visibility: 'public' } + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.length).to eq(user.namespace.projects.where(visibility_level: Gitlab::VisibilityLevel::PUBLIC).count) + end + end + + context 'and using sorting' do + before do + project2 + project3 + end + + it 'returns the correct order when sorted by id' do + get v3_api('/projects', user), { order_by: 'id', sort: 'desc' } + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.first['id']).to eq(project3.id) + end + end + end + end + + describe 'GET /projects/all' do + before { project } + + context 'when unauthenticated' do + it 'returns authentication error' do + get v3_api('/projects/all') + expect(response).to have_http_status(401) + end + end + + context 'when authenticated as regular user' do + it 'returns authentication error' do + get v3_api('/projects/all', user) + expect(response).to have_http_status(403) + end + end + + context 'when authenticated as admin' do + it 'returns an array of all projects' do + get v3_api('/projects/all', admin) + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + + expect(json_response).to satisfy do |response| + response.one? do |entry| + entry.has_key?('permissions') && + entry['name'] == project.name && + entry['owner']['username'] == user.username + end + end + end + + it "does not include statistics by default" do + get v3_api('/projects/all', admin) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.first).not_to include('statistics') + end + + it "includes statistics if requested" do + get v3_api('/projects/all', admin), statistics: true + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.first).to include 'statistics' + end + end + end + + describe 'GET /projects/owned' do + before do + project3 + project4 + end + + context 'when unauthenticated' do + it 'returns authentication error' do + get v3_api('/projects/owned') + expect(response).to have_http_status(401) + end + end + + context 'when authenticated as project owner' do + it 'returns an array of projects the user owns' do + get v3_api('/projects/owned', user4) + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.first['name']).to eq(project4.name) + expect(json_response.first['owner']['username']).to eq(user4.username) + end + + it "does not include statistics by default" do + get v3_api('/projects/owned', user4) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.first).not_to include('statistics') + end + + it "includes statistics if requested" do + attributes = { + commit_count: 23, + storage_size: 702, + repository_size: 123, + lfs_objects_size: 234, + build_artifacts_size: 345, + } + + project4.statistics.update!(attributes) + + get v3_api('/projects/owned', user4), statistics: true + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.first['statistics']).to eq attributes.stringify_keys + end + end + end + + describe 'GET /projects/visible' do + shared_examples_for 'visible projects response' do + it 'returns the visible projects' do + get v3_api('/projects/visible', current_user) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.map { |p| p['id'] }).to contain_exactly(*projects.map(&:id)) + end + end + + let!(:public_project) { create(:empty_project, :public) } + before do + project + project2 + project3 + project4 + end + + context 'when unauthenticated' do + it_behaves_like 'visible projects response' do + let(:current_user) { nil } + let(:projects) { [public_project] } + end + end + + context 'when authenticated' do + it_behaves_like 'visible projects response' do + let(:current_user) { user } + let(:projects) { [public_project, project, project2, project3] } + end + end + + context 'when authenticated as a different user' do + it_behaves_like 'visible projects response' do + let(:current_user) { user2 } + let(:projects) { [public_project] } + end + end + end + + describe 'GET /projects/starred' do + let(:public_project) { create(:empty_project, :public) } + + before do + project_member2 + user3.update_attributes(starred_projects: [project, project2, project3, public_project]) + end + + it 'returns the starred projects viewable by the user' do + get v3_api('/projects/starred', user3) + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.map { |project| project['id'] }).to contain_exactly(project.id, public_project.id) + end + end + + describe 'POST /projects' do + context 'maximum number of projects reached' do + it 'does not create new project and respond with 403' do + allow_any_instance_of(User).to receive(:projects_limit_left).and_return(0) + expect { post v3_api('/projects', user2), name: 'foo' }. + to change {Project.count}.by(0) + expect(response).to have_http_status(403) + end + end + + it 'creates new project without path and return 201' do + expect { post v3_api('/projects', user), name: 'foo' }. + to change { Project.count }.by(1) + expect(response).to have_http_status(201) + end + + it 'creates last project before reaching project limit' do + allow_any_instance_of(User).to receive(:projects_limit_left).and_return(1) + post v3_api('/projects', user2), name: 'foo' + expect(response).to have_http_status(201) + end + + it 'does not create new project without name and return 400' do + expect { post v3_api('/projects', user) }.not_to change { Project.count } + expect(response).to have_http_status(400) + end + + it "assigns attributes to project" do + project = attributes_for(:project, { + path: 'camelCasePath', + description: FFaker::Lorem.sentence, + issues_enabled: false, + merge_requests_enabled: false, + wiki_enabled: false, + only_allow_merge_if_build_succeeds: false, + request_access_enabled: true, + only_allow_merge_if_all_discussions_are_resolved: false + }) + + post v3_api('/projects', user), project + + project.each_pair do |k, v| + next if %i[has_external_issue_tracker issues_enabled merge_requests_enabled wiki_enabled].include?(k) + expect(json_response[k.to_s]).to eq(v) + end + + # Check feature permissions attributes + project = Project.find_by_path(project[:path]) + expect(project.project_feature.issues_access_level).to eq(ProjectFeature::DISABLED) + expect(project.project_feature.merge_requests_access_level).to eq(ProjectFeature::DISABLED) + expect(project.project_feature.wiki_access_level).to eq(ProjectFeature::DISABLED) + end + + it 'sets a project as public' do + project = attributes_for(:project, :public) + post v3_api('/projects', user), project + expect(json_response['public']).to be_truthy + expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC) + end + + it 'sets a project as public using :public' do + project = attributes_for(:project, { public: true }) + post v3_api('/projects', user), project + expect(json_response['public']).to be_truthy + expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC) + end + + it 'sets a project as internal' do + project = attributes_for(:project, :internal) + post v3_api('/projects', user), project + expect(json_response['public']).to be_falsey + expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL) + end + + it 'sets a project as internal overriding :public' do + project = attributes_for(:project, :internal, { public: true }) + post v3_api('/projects', user), project + expect(json_response['public']).to be_falsey + expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL) + end + + it 'sets a project as private' do + project = attributes_for(:project, :private) + post v3_api('/projects', user), project + expect(json_response['public']).to be_falsey + expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE) + end + + it 'sets a project as private using :public' do + project = attributes_for(:project, { public: false }) + post v3_api('/projects', user), project + expect(json_response['public']).to be_falsey + expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE) + end + + it 'sets a project as allowing merge even if build fails' do + project = attributes_for(:project, { only_allow_merge_if_build_succeeds: false }) + post v3_api('/projects', user), project + expect(json_response['only_allow_merge_if_build_succeeds']).to be_falsey + end + + it 'sets a project as allowing merge only if build succeeds' do + project = attributes_for(:project, { only_allow_merge_if_build_succeeds: true }) + post v3_api('/projects', user), project + expect(json_response['only_allow_merge_if_build_succeeds']).to be_truthy + end + + it 'sets a project as allowing merge even if discussions are unresolved' do + project = attributes_for(:project, { only_allow_merge_if_all_discussions_are_resolved: false }) + + post v3_api('/projects', user), project + + expect(json_response['only_allow_merge_if_all_discussions_are_resolved']).to be_falsey + end + + it 'sets a project as allowing merge if only_allow_merge_if_all_discussions_are_resolved is nil' do + project = attributes_for(:project, only_allow_merge_if_all_discussions_are_resolved: nil) + + post v3_api('/projects', user), project + + expect(json_response['only_allow_merge_if_all_discussions_are_resolved']).to be_falsey + end + + it 'sets a project as allowing merge only if all discussions are resolved' do + project = attributes_for(:project, { only_allow_merge_if_all_discussions_are_resolved: true }) + + post v3_api('/projects', user), project + + expect(json_response['only_allow_merge_if_all_discussions_are_resolved']).to be_truthy + end + + context 'when a visibility level is restricted' do + before do + @project = attributes_for(:project, { public: true }) + stub_application_setting(restricted_visibility_levels: [Gitlab::VisibilityLevel::PUBLIC]) + end + + it 'does not allow a non-admin to use a restricted visibility level' do + post v3_api('/projects', user), @project + + expect(response).to have_http_status(400) + expect(json_response['message']['visibility_level'].first).to( + match('restricted by your GitLab administrator') + ) + end + + it 'allows an admin to override restricted visibility settings' do + post v3_api('/projects', admin), @project + expect(json_response['public']).to be_truthy + expect(json_response['visibility_level']).to( + eq(Gitlab::VisibilityLevel::PUBLIC) + ) + end + end + end + + describe 'POST /projects/user/:id' do + before { project } + before { admin } + + it 'should create new project without path and return 201' do + expect { post v3_api("/projects/user/#{user.id}", admin), name: 'foo' }.to change {Project.count}.by(1) + expect(response).to have_http_status(201) + end + + it 'responds with 400 on failure and not project' do + expect { post v3_api("/projects/user/#{user.id}", admin) }. + not_to change { Project.count } + + expect(response).to have_http_status(400) + expect(json_response['error']).to eq('name is missing') + end + + it 'assigns attributes to project' do + project = attributes_for(:project, { + description: FFaker::Lorem.sentence, + issues_enabled: false, + merge_requests_enabled: false, + wiki_enabled: false, + request_access_enabled: true + }) + + post v3_api("/projects/user/#{user.id}", admin), project + + expect(response).to have_http_status(201) + project.each_pair do |k, v| + next if %i[has_external_issue_tracker path].include?(k) + expect(json_response[k.to_s]).to eq(v) + end + end + + it 'sets a project as public' do + project = attributes_for(:project, :public) + post v3_api("/projects/user/#{user.id}", admin), project + + expect(response).to have_http_status(201) + expect(json_response['public']).to be_truthy + expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC) + end + + it 'sets a project as public using :public' do + project = attributes_for(:project, { public: true }) + post v3_api("/projects/user/#{user.id}", admin), project + + expect(response).to have_http_status(201) + expect(json_response['public']).to be_truthy + expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PUBLIC) + end + + it 'sets a project as internal' do + project = attributes_for(:project, :internal) + post v3_api("/projects/user/#{user.id}", admin), project + + expect(response).to have_http_status(201) + expect(json_response['public']).to be_falsey + expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL) + end + + it 'sets a project as internal overriding :public' do + project = attributes_for(:project, :internal, { public: true }) + post v3_api("/projects/user/#{user.id}", admin), project + expect(response).to have_http_status(201) + expect(json_response['public']).to be_falsey + expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::INTERNAL) + end + + it 'sets a project as private' do + project = attributes_for(:project, :private) + post v3_api("/projects/user/#{user.id}", admin), project + expect(json_response['public']).to be_falsey + expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE) + end + + it 'sets a project as private using :public' do + project = attributes_for(:project, { public: false }) + post v3_api("/projects/user/#{user.id}", admin), project + expect(json_response['public']).to be_falsey + expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE) + end + + it 'sets a project as allowing merge even if build fails' do + project = attributes_for(:project, { only_allow_merge_if_build_succeeds: false }) + post v3_api("/projects/user/#{user.id}", admin), project + expect(json_response['only_allow_merge_if_build_succeeds']).to be_falsey + end + + it 'sets a project as allowing merge only if build succeeds' do + project = attributes_for(:project, { only_allow_merge_if_build_succeeds: true }) + post v3_api("/projects/user/#{user.id}", admin), project + expect(json_response['only_allow_merge_if_build_succeeds']).to be_truthy + end + + it 'sets a project as allowing merge even if discussions are unresolved' do + project = attributes_for(:project, { only_allow_merge_if_all_discussions_are_resolved: false }) + + post v3_api("/projects/user/#{user.id}", admin), project + + expect(json_response['only_allow_merge_if_all_discussions_are_resolved']).to be_falsey + end + + it 'sets a project as allowing merge only if all discussions are resolved' do + project = attributes_for(:project, { only_allow_merge_if_all_discussions_are_resolved: true }) + + post v3_api("/projects/user/#{user.id}", admin), project + + expect(json_response['only_allow_merge_if_all_discussions_are_resolved']).to be_truthy + end + end + + describe "POST /projects/:id/uploads" do + before { project } + + it "uploads the file and returns its info" do + post v3_api("/projects/#{project.id}/uploads", user), file: fixture_file_upload(Rails.root + "spec/fixtures/dk.png", "image/png") + + expect(response).to have_http_status(201) + expect(json_response['alt']).to eq("dk") + expect(json_response['url']).to start_with("/uploads/") + expect(json_response['url']).to end_with("/dk.png") + end + end + + describe 'GET /projects/:id' do + context 'when unauthenticated' do + it 'returns the public projects' do + public_project = create(:empty_project, :public) + + get v3_api("/projects/#{public_project.id}") + + expect(response).to have_http_status(200) + expect(json_response['id']).to eq(public_project.id) + expect(json_response['description']).to eq(public_project.description) + expect(json_response.keys).not_to include('permissions') + end + end + + context 'when authenticated' do + before do + project + project_member + end + + it 'returns a project by id' do + group = create(:group) + link = create(:project_group_link, project: project, group: group) + + get v3_api("/projects/#{project.id}", user) + + expect(response).to have_http_status(200) + expect(json_response['id']).to eq(project.id) + expect(json_response['description']).to eq(project.description) + expect(json_response['default_branch']).to eq(project.default_branch) + expect(json_response['tag_list']).to be_an Array + expect(json_response['public']).to be_falsey + expect(json_response['archived']).to be_falsey + expect(json_response['visibility_level']).to be_present + expect(json_response['ssh_url_to_repo']).to be_present + expect(json_response['http_url_to_repo']).to be_present + expect(json_response['web_url']).to be_present + expect(json_response['owner']).to be_a Hash + expect(json_response['owner']).to be_a Hash + expect(json_response['name']).to eq(project.name) + expect(json_response['path']).to be_present + expect(json_response['issues_enabled']).to be_present + expect(json_response['merge_requests_enabled']).to be_present + expect(json_response['wiki_enabled']).to be_present + expect(json_response['builds_enabled']).to be_present + expect(json_response['snippets_enabled']).to be_present + expect(json_response['container_registry_enabled']).to be_present + expect(json_response['created_at']).to be_present + expect(json_response['last_activity_at']).to be_present + expect(json_response['shared_runners_enabled']).to be_present + expect(json_response['creator_id']).to be_present + expect(json_response['namespace']).to be_present + expect(json_response['avatar_url']).to be_nil + expect(json_response['star_count']).to be_present + expect(json_response['forks_count']).to be_present + expect(json_response['public_builds']).to be_present + expect(json_response['shared_with_groups']).to be_an Array + expect(json_response['shared_with_groups'].length).to eq(1) + expect(json_response['shared_with_groups'][0]['group_id']).to eq(group.id) + expect(json_response['shared_with_groups'][0]['group_name']).to eq(group.name) + expect(json_response['shared_with_groups'][0]['group_access_level']).to eq(link.group_access) + expect(json_response['only_allow_merge_if_build_succeeds']).to eq(project.only_allow_merge_if_build_succeeds) + expect(json_response['only_allow_merge_if_all_discussions_are_resolved']).to eq(project.only_allow_merge_if_all_discussions_are_resolved) + end + + it 'returns a project by path name' do + get v3_api("/projects/#{project.id}", user) + expect(response).to have_http_status(200) + expect(json_response['name']).to eq(project.name) + end + + it 'returns a 404 error if not found' do + get v3_api('/projects/42', user) + expect(response).to have_http_status(404) + expect(json_response['message']).to eq('404 Project Not Found') + end + + it 'returns a 404 error if user is not a member' do + other_user = create(:user) + get v3_api("/projects/#{project.id}", other_user) + expect(response).to have_http_status(404) + end + + it 'handles users with dots' do + dot_user = create(:user, username: 'dot.user') + project = create(:empty_project, creator_id: dot_user.id, namespace: dot_user.namespace) + + get v3_api("/projects/#{dot_user.namespace.name}%2F#{project.path}", dot_user) + expect(response).to have_http_status(200) + expect(json_response['name']).to eq(project.name) + end + + it 'exposes namespace fields' do + get v3_api("/projects/#{project.id}", user) + + expect(response).to have_http_status(200) + expect(json_response['namespace']).to eq({ + 'id' => user.namespace.id, + 'name' => user.namespace.name, + 'path' => user.namespace.path, + 'kind' => user.namespace.kind, + }) + end + + describe 'permissions' do + context 'all projects' do + before { project.team << [user, :master] } + + it 'contains permission information' do + get v3_api("/projects", user) + + expect(response).to have_http_status(200) + expect(json_response.first['permissions']['project_access']['access_level']). + to eq(Gitlab::Access::MASTER) + expect(json_response.first['permissions']['group_access']).to be_nil + end + end + + context 'personal project' do + it 'sets project access and returns 200' do + project.team << [user, :master] + get v3_api("/projects/#{project.id}", user) + + expect(response).to have_http_status(200) + expect(json_response['permissions']['project_access']['access_level']). + to eq(Gitlab::Access::MASTER) + expect(json_response['permissions']['group_access']).to be_nil + end + end + + context 'group project' do + let(:project2) { create(:empty_project, group: create(:group)) } + + before { project2.group.add_owner(user) } + + it 'sets the owner and return 200' do + get v3_api("/projects/#{project2.id}", user) + + expect(response).to have_http_status(200) + expect(json_response['permissions']['project_access']).to be_nil + expect(json_response['permissions']['group_access']['access_level']). + to eq(Gitlab::Access::OWNER) + end + end + end + end + end + + describe 'GET /projects/:id/events' do + shared_examples_for 'project events response' do + it 'returns the project events' do + member = create(:user) + create(:project_member, :developer, user: member, project: project) + note = create(:note_on_issue, note: 'What an awesome day!', project: project) + EventCreateService.new.leave_note(note, note.author) + + get v3_api("/projects/#{project.id}/events", current_user) + + expect(response).to have_http_status(200) + + first_event = json_response.first + + expect(first_event['action_name']).to eq('commented on') + expect(first_event['note']['body']).to eq('What an awesome day!') + + last_event = json_response.last + + expect(last_event['action_name']).to eq('joined') + expect(last_event['project_id'].to_i).to eq(project.id) + expect(last_event['author_username']).to eq(member.username) + expect(last_event['author']['name']).to eq(member.name) + end + end + + context 'when unauthenticated' do + it_behaves_like 'project events response' do + let(:project) { create(:empty_project, :public) } + let(:current_user) { nil } + end + end + + context 'when authenticated' do + context 'valid request' do + it_behaves_like 'project events response' do + let(:current_user) { user } + end + end + + it 'returns a 404 error if not found' do + get v3_api('/projects/42/events', user) + + expect(response).to have_http_status(404) + expect(json_response['message']).to eq('404 Project Not Found') + end + + it 'returns a 404 error if user is not a member' do + other_user = create(:user) + + get v3_api("/projects/#{project.id}/events", other_user) + + expect(response).to have_http_status(404) + end + end + end + + describe 'GET /projects/:id/users' do + shared_examples_for 'project users response' do + it 'returns the project users' do + member = create(:user) + create(:project_member, :developer, user: member, project: project) + + get v3_api("/projects/#{project.id}/users", current_user) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.size).to eq(1) + + first_user = json_response.first + + expect(first_user['username']).to eq(member.username) + expect(first_user['name']).to eq(member.name) + expect(first_user.keys).to contain_exactly(*%w[name username id state avatar_url web_url]) + end + end + + context 'when unauthenticated' do + it_behaves_like 'project users response' do + let(:project) { create(:empty_project, :public) } + let(:current_user) { nil } + end + end + + context 'when authenticated' do + context 'valid request' do + it_behaves_like 'project users response' do + let(:current_user) { user } + end + end + + it 'returns a 404 error if not found' do + get v3_api('/projects/42/users', user) + + expect(response).to have_http_status(404) + expect(json_response['message']).to eq('404 Project Not Found') + end + + it 'returns a 404 error if user is not a member' do + other_user = create(:user) + + get v3_api("/projects/#{project.id}/users", other_user) + + expect(response).to have_http_status(404) + end + end + end + + describe 'GET /projects/:id/snippets' do + before { snippet } + + it 'returns an array of project snippets' do + get v3_api("/projects/#{project.id}/snippets", user) + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.first['title']).to eq(snippet.title) + end + end + + describe 'GET /projects/:id/snippets/:snippet_id' do + it 'returns a project snippet' do + get v3_api("/projects/#{project.id}/snippets/#{snippet.id}", user) + expect(response).to have_http_status(200) + expect(json_response['title']).to eq(snippet.title) + end + + it 'returns a 404 error if snippet id not found' do + get v3_api("/projects/#{project.id}/snippets/1234", user) + expect(response).to have_http_status(404) + end + end + + describe 'POST /projects/:id/snippets' do + it 'creates a new project snippet' do + post v3_api("/projects/#{project.id}/snippets", user), + title: 'v3_api test', file_name: 'sample.rb', code: 'test', + visibility_level: '0' + expect(response).to have_http_status(201) + expect(json_response['title']).to eq('v3_api test') + end + + it 'returns a 400 error if invalid snippet is given' do + post v3_api("/projects/#{project.id}/snippets", user) + expect(status).to eq(400) + end + end + + describe 'PUT /projects/:id/snippets/:snippet_id' do + it 'updates an existing project snippet' do + put v3_api("/projects/#{project.id}/snippets/#{snippet.id}", user), + code: 'updated code' + expect(response).to have_http_status(200) + expect(json_response['title']).to eq('example') + expect(snippet.reload.content).to eq('updated code') + end + + it 'updates an existing project snippet with new title' do + put v3_api("/projects/#{project.id}/snippets/#{snippet.id}", user), + title: 'other v3_api test' + expect(response).to have_http_status(200) + expect(json_response['title']).to eq('other v3_api test') + end + end + + describe 'DELETE /projects/:id/snippets/:snippet_id' do + before { snippet } + + it 'deletes existing project snippet' do + expect do + delete v3_api("/projects/#{project.id}/snippets/#{snippet.id}", user) + end.to change { Snippet.count }.by(-1) + expect(response).to have_http_status(200) + end + + it 'returns 404 when deleting unknown snippet id' do + delete v3_api("/projects/#{project.id}/snippets/1234", user) + expect(response).to have_http_status(404) + end + end + + describe 'GET /projects/:id/snippets/:snippet_id/raw' do + it 'gets a raw project snippet' do + get v3_api("/projects/#{project.id}/snippets/#{snippet.id}/raw", user) + expect(response).to have_http_status(200) + end + + it 'returns a 404 error if raw project snippet not found' do + get v3_api("/projects/#{project.id}/snippets/5555/raw", user) + expect(response).to have_http_status(404) + end + end + + describe :fork_admin do + let(:project_fork_target) { create(:empty_project) } + let(:project_fork_source) { create(:empty_project, :public) } + + describe 'POST /projects/:id/fork/:forked_from_id' do + let(:new_project_fork_source) { create(:empty_project, :public) } + + it "is not available for non admin users" do + post v3_api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", user) + expect(response).to have_http_status(403) + end + + it 'allows project to be forked from an existing project' do + expect(project_fork_target.forked?).not_to be_truthy + post v3_api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) + expect(response).to have_http_status(201) + project_fork_target.reload + expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id) + expect(project_fork_target.forked_project_link).not_to be_nil + expect(project_fork_target.forked?).to be_truthy + end + + it 'fails if forked_from project which does not exist' do + post v3_api("/projects/#{project_fork_target.id}/fork/9999", admin) + expect(response).to have_http_status(404) + end + + it 'fails with 409 if already forked' do + post v3_api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) + project_fork_target.reload + expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id) + post v3_api("/projects/#{project_fork_target.id}/fork/#{new_project_fork_source.id}", admin) + expect(response).to have_http_status(409) + project_fork_target.reload + expect(project_fork_target.forked_from_project.id).to eq(project_fork_source.id) + expect(project_fork_target.forked?).to be_truthy + end + end + + describe 'DELETE /projects/:id/fork' do + it "is not visible to users outside group" do + delete v3_api("/projects/#{project_fork_target.id}/fork", user) + expect(response).to have_http_status(404) + end + + context 'when users belong to project group' do + let(:project_fork_target) { create(:empty_project, group: create(:group)) } + + before do + project_fork_target.group.add_owner user + project_fork_target.group.add_developer user2 + end + + it 'is forbidden to non-owner users' do + delete v3_api("/projects/#{project_fork_target.id}/fork", user2) + expect(response).to have_http_status(403) + end + + it 'makes forked project unforked' do + post v3_api("/projects/#{project_fork_target.id}/fork/#{project_fork_source.id}", admin) + project_fork_target.reload + expect(project_fork_target.forked_from_project).not_to be_nil + expect(project_fork_target.forked?).to be_truthy + delete v3_api("/projects/#{project_fork_target.id}/fork", admin) + expect(response).to have_http_status(200) + project_fork_target.reload + expect(project_fork_target.forked_from_project).to be_nil + expect(project_fork_target.forked?).not_to be_truthy + end + + it 'is idempotent if not forked' do + expect(project_fork_target.forked_from_project).to be_nil + delete v3_api("/projects/#{project_fork_target.id}/fork", admin) + expect(response).to have_http_status(304) + expect(project_fork_target.reload.forked_from_project).to be_nil + end + end + end + end + + describe "POST /projects/:id/share" do + let(:group) { create(:group) } + + it "shares project with group" do + expires_at = 10.days.from_now.to_date + + expect do + post v3_api("/projects/#{project.id}/share", user), group_id: group.id, group_access: Gitlab::Access::DEVELOPER, expires_at: expires_at + end.to change { ProjectGroupLink.count }.by(1) + + expect(response).to have_http_status(201) + expect(json_response['group_id']).to eq(group.id) + expect(json_response['group_access']).to eq(Gitlab::Access::DEVELOPER) + expect(json_response['expires_at']).to eq(expires_at.to_s) + end + + it "returns a 400 error when group id is not given" do + post v3_api("/projects/#{project.id}/share", user), group_access: Gitlab::Access::DEVELOPER + expect(response).to have_http_status(400) + end + + it "returns a 400 error when access level is not given" do + post v3_api("/projects/#{project.id}/share", user), group_id: group.id + expect(response).to have_http_status(400) + end + + it "returns a 400 error when sharing is disabled" do + project.namespace.update(share_with_group_lock: true) + post v3_api("/projects/#{project.id}/share", user), group_id: group.id, group_access: Gitlab::Access::DEVELOPER + expect(response).to have_http_status(400) + end + + it 'returns a 404 error when user cannot read group' do + private_group = create(:group, :private) + + post v3_api("/projects/#{project.id}/share", user), group_id: private_group.id, group_access: Gitlab::Access::DEVELOPER + + expect(response).to have_http_status(404) + end + + it 'returns a 404 error when group does not exist' do + post v3_api("/projects/#{project.id}/share", user), group_id: 1234, group_access: Gitlab::Access::DEVELOPER + + expect(response).to have_http_status(404) + end + + it "returns a 400 error when wrong params passed" do + post v3_api("/projects/#{project.id}/share", user), group_id: group.id, group_access: 1234 + + expect(response).to have_http_status(400) + expect(json_response['error']).to eq 'group_access does not have a valid value' + end + end + + describe 'DELETE /projects/:id/share/:group_id' do + it 'returns 204 when deleting a group share' do + group = create(:group, :public) + create(:project_group_link, group: group, project: project) + + delete v3_api("/projects/#{project.id}/share/#{group.id}", user) + + expect(response).to have_http_status(204) + expect(project.project_group_links).to be_empty + end + + it 'returns a 400 when group id is not an integer' do + delete v3_api("/projects/#{project.id}/share/foo", user) + + expect(response).to have_http_status(400) + end + + it 'returns a 404 error when group link does not exist' do + delete v3_api("/projects/#{project.id}/share/1234", user) + + expect(response).to have_http_status(404) + end + + it 'returns a 404 error when project does not exist' do + delete v3_api("/projects/123/share/1234", user) + + expect(response).to have_http_status(404) + end + end + + describe 'GET /projects/search/:query' do + let!(:query) { 'query'} + let!(:search) { create(:empty_project, name: query, creator_id: user.id, namespace: user.namespace) } + let!(:pre) { create(:empty_project, name: "pre_#{query}", creator_id: user.id, namespace: user.namespace) } + let!(:post) { create(:empty_project, name: "#{query}_post", creator_id: user.id, namespace: user.namespace) } + let!(:pre_post) { create(:empty_project, name: "pre_#{query}_post", creator_id: user.id, namespace: user.namespace) } + let!(:unfound) { create(:empty_project, name: 'unfound', creator_id: user.id, namespace: user.namespace) } + let!(:internal) { create(:empty_project, :internal, name: "internal #{query}") } + let!(:unfound_internal) { create(:empty_project, :internal, name: 'unfound internal') } + let!(:public) { create(:empty_project, :public, name: "public #{query}") } + let!(:unfound_public) { create(:empty_project, :public, name: 'unfound public') } + let!(:one_dot_two) { create(:empty_project, :public, name: "one.dot.two") } + + shared_examples_for 'project search response' do |args = {}| + it 'returns project search responses' do + get v3_api("/projects/search/#{args[:query]}", current_user) + + expect(response).to have_http_status(200) + expect(json_response).to be_an Array + expect(json_response.size).to eq(args[:results]) + json_response.each { |project| expect(project['name']).to match(args[:match_regex] || /.*#{args[:query]}.*/) } + end + end + + context 'when unauthenticated' do + it_behaves_like 'project search response', query: 'query', results: 1 do + let(:current_user) { nil } + end + end + + context 'when authenticated' do + it_behaves_like 'project search response', query: 'query', results: 6 do + let(:current_user) { user } + end + it_behaves_like 'project search response', query: 'one.dot.two', results: 1 do + let(:current_user) { user } + end + end + + context 'when authenticated as a different user' do + it_behaves_like 'project search response', query: 'query', results: 2, match_regex: /(internal|public) query/ do + let(:current_user) { user2 } + end + end + end + + describe 'PUT /projects/:id' do + before { project } + before { user } + before { user3 } + before { user4 } + before { project3 } + before { project4 } + before { project_member3 } + before { project_member2 } + + context 'when unauthenticated' do + it 'returns authentication error' do + project_param = { name: 'bar' } + put v3_api("/projects/#{project.id}"), project_param + expect(response).to have_http_status(401) + end + end + + context 'when authenticated as project owner' do + it 'updates name' do + project_param = { name: 'bar' } + put v3_api("/projects/#{project.id}", user), project_param + expect(response).to have_http_status(200) + project_param.each_pair do |k, v| + expect(json_response[k.to_s]).to eq(v) + end + end + + it 'updates visibility_level' do + project_param = { visibility_level: 20 } + put v3_api("/projects/#{project3.id}", user), project_param + expect(response).to have_http_status(200) + project_param.each_pair do |k, v| + expect(json_response[k.to_s]).to eq(v) + end + end + + it 'updates visibility_level from public to private' do + project3.update_attributes({ visibility_level: Gitlab::VisibilityLevel::PUBLIC }) + project_param = { public: false } + put v3_api("/projects/#{project3.id}", user), project_param + expect(response).to have_http_status(200) + project_param.each_pair do |k, v| + expect(json_response[k.to_s]).to eq(v) + end + expect(json_response['visibility_level']).to eq(Gitlab::VisibilityLevel::PRIVATE) + end + + it 'does not update name to existing name' do + project_param = { name: project3.name } + put v3_api("/projects/#{project.id}", user), project_param + expect(response).to have_http_status(400) + expect(json_response['message']['name']).to eq(['has already been taken']) + end + + it 'updates request_access_enabled' do + project_param = { request_access_enabled: false } + + put v3_api("/projects/#{project.id}", user), project_param + + expect(response).to have_http_status(200) + expect(json_response['request_access_enabled']).to eq(false) + end + + it 'updates path & name to existing path & name in different namespace' do + project_param = { path: project4.path, name: project4.name } + put v3_api("/projects/#{project3.id}", user), project_param + expect(response).to have_http_status(200) + project_param.each_pair do |k, v| + expect(json_response[k.to_s]).to eq(v) + end + end + end + + context 'when authenticated as project master' do + it 'updates path' do + project_param = { path: 'bar' } + put v3_api("/projects/#{project3.id}", user4), project_param + expect(response).to have_http_status(200) + project_param.each_pair do |k, v| + expect(json_response[k.to_s]).to eq(v) + end + end + + it 'updates other attributes' do + project_param = { issues_enabled: true, + wiki_enabled: true, + snippets_enabled: true, + merge_requests_enabled: true, + description: 'new description' } + + put v3_api("/projects/#{project3.id}", user4), project_param + expect(response).to have_http_status(200) + project_param.each_pair do |k, v| + expect(json_response[k.to_s]).to eq(v) + end + end + + it 'does not update path to existing path' do + project_param = { path: project.path } + put v3_api("/projects/#{project3.id}", user4), project_param + expect(response).to have_http_status(400) + expect(json_response['message']['path']).to eq(['has already been taken']) + end + + it 'does not update name' do + project_param = { name: 'bar' } + put v3_api("/projects/#{project3.id}", user4), project_param + expect(response).to have_http_status(403) + end + + it 'does not update visibility_level' do + project_param = { visibility_level: 20 } + put v3_api("/projects/#{project3.id}", user4), project_param + expect(response).to have_http_status(403) + end + end + + context 'when authenticated as project developer' do + it 'does not update other attributes' do + project_param = { path: 'bar', + issues_enabled: true, + wiki_enabled: true, + snippets_enabled: true, + merge_requests_enabled: true, + description: 'new description', + request_access_enabled: true } + put v3_api("/projects/#{project.id}", user3), project_param + expect(response).to have_http_status(403) + end + end + end + + describe 'POST /projects/:id/archive' do + context 'on an unarchived project' do + it 'archives the project' do + post v3_api("/projects/#{project.id}/archive", user) + + expect(response).to have_http_status(201) + expect(json_response['archived']).to be_truthy + end + end + + context 'on an archived project' do + before do + project.archive! + end + + it 'remains archived' do + post v3_api("/projects/#{project.id}/archive", user) + + expect(response).to have_http_status(201) + expect(json_response['archived']).to be_truthy + end + end + + context 'user without archiving rights to the project' do + before do + project.team << [user3, :developer] + end + + it 'rejects the action' do + post v3_api("/projects/#{project.id}/archive", user3) + + expect(response).to have_http_status(403) + end + end + end + + describe 'POST /projects/:id/unarchive' do + context 'on an unarchived project' do + it 'remains unarchived' do + post v3_api("/projects/#{project.id}/unarchive", user) + + expect(response).to have_http_status(201) + expect(json_response['archived']).to be_falsey + end + end + + context 'on an archived project' do + before do + project.archive! + end + + it 'unarchives the project' do + post v3_api("/projects/#{project.id}/unarchive", user) + + expect(response).to have_http_status(201) + expect(json_response['archived']).to be_falsey + end + end + + context 'user without archiving rights to the project' do + before do + project.team << [user3, :developer] + end + + it 'rejects the action' do + post v3_api("/projects/#{project.id}/unarchive", user3) + + expect(response).to have_http_status(403) + end + end + end + + describe 'POST /projects/:id/star' do + context 'on an unstarred project' do + it 'stars the project' do + expect { post v3_api("/projects/#{project.id}/star", user) }.to change { project.reload.star_count }.by(1) + + expect(response).to have_http_status(201) + expect(json_response['star_count']).to eq(1) + end + end + + context 'on a starred project' do + before do + user.toggle_star(project) + project.reload + end + + it 'does not modify the star count' do + expect { post v3_api("/projects/#{project.id}/star", user) }.not_to change { project.reload.star_count } + + expect(response).to have_http_status(304) + end + end + end + + describe 'DELETE /projects/:id/star' do + context 'on a starred project' do + before do + user.toggle_star(project) + project.reload + end + + it 'unstars the project' do + expect { delete v3_api("/projects/#{project.id}/star", user) }.to change { project.reload.star_count }.by(-1) + + expect(response).to have_http_status(200) + expect(json_response['star_count']).to eq(0) + end + end + + context 'on an unstarred project' do + it 'does not modify the star count' do + expect { delete v3_api("/projects/#{project.id}/star", user) }.not_to change { project.reload.star_count } + + expect(response).to have_http_status(304) + end + end + end + + describe 'DELETE /projects/:id' do + context 'when authenticated as user' do + it 'removes project' do + delete v3_api("/projects/#{project.id}", user) + expect(response).to have_http_status(200) + end + + it 'does not remove a project if not an owner' do + user3 = create(:user) + project.team << [user3, :developer] + delete v3_api("/projects/#{project.id}", user3) + expect(response).to have_http_status(403) + end + + it 'does not remove a non existing project' do + delete v3_api('/projects/1328', user) + expect(response).to have_http_status(404) + end + + it 'does not remove a project not attached to user' do + delete v3_api("/projects/#{project.id}", user2) + expect(response).to have_http_status(404) + end + end + + context 'when authenticated as admin' do + it 'removes any existing project' do + delete v3_api("/projects/#{project.id}", admin) + expect(response).to have_http_status(200) + end + + it 'does not remove a non existing project' do + delete v3_api('/projects/1328', admin) + expect(response).to have_http_status(404) + end + end + end +end diff --git a/spec/support/api_helpers.rb b/spec/support/api_helpers.rb index 68b196d9033..ae6e708cf87 100644 --- a/spec/support/api_helpers.rb +++ b/spec/support/api_helpers.rb @@ -17,8 +17,8 @@ module ApiHelpers # => "/api/v2/issues?foo=bar&private_token=..." # # Returns the relative path to the requested API resource - def api(path, user = nil) - "/api/#{API::API.version}#{path}" + + def api(path, user = nil, version: API::API.version) + "/api/#{version}#{path}" + # Normalize query string (path.index('?') ? '' : '?') + @@ -31,6 +31,11 @@ module ApiHelpers end end + # Temporary helper method for simplifying V3 exclusive API specs + def v3_api(path, user = nil) + api(path, user, version: 'v3') + end + def ci_api(path, user = nil) "/ci/api/v1/#{path}" + -- cgit v1.2.1 From 90114fea5f4ec410fd3a01892706ad6a066efa43 Mon Sep 17 00:00:00 2001 From: Nur Rony Date: Tue, 31 Jan 2017 17:00:53 +0600 Subject: hides search button --- app/views/admin/projects/index.html.haml | 1 + 1 file changed, 1 insertion(+) diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml index 5936312801b..cf8d438670b 100644 --- a/app/views/admin/projects/index.html.haml +++ b/app/views/admin/projects/index.html.haml @@ -40,6 +40,7 @@ = render 'shared/projects/dropdown' = link_to new_project_path, class: 'btn btn-new' do New Project + = button_tag "Search", class: "btn btn-primary btn-search hide" %ul.nav-links - opts = params[:visibility_level].present? ? {} : { page: admin_projects_path } -- cgit v1.2.1 From dcac161472d163d1c64555f62c15722c2ee01ec9 Mon Sep 17 00:00:00 2001 From: Nur Rony Date: Tue, 31 Jan 2017 17:04:23 +0600 Subject: adds changelog --- changelogs/unreleased/redesign-searchbar-admin-project-26794.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelogs/unreleased/redesign-searchbar-admin-project-26794.yml diff --git a/changelogs/unreleased/redesign-searchbar-admin-project-26794.yml b/changelogs/unreleased/redesign-searchbar-admin-project-26794.yml new file mode 100644 index 00000000000..547a7c6755c --- /dev/null +++ b/changelogs/unreleased/redesign-searchbar-admin-project-26794.yml @@ -0,0 +1,4 @@ +--- +title: Redesign searchbar in admin project list +merge_request: 8776 +author: -- cgit v1.2.1 From a54a734f70273b99b2f34236ebf4abd83dad43dc Mon Sep 17 00:00:00 2001 From: Nur Rony Date: Tue, 31 Jan 2017 17:40:37 +0600 Subject: fixes mobile view --- app/views/shared/projects/_dropdown.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/shared/projects/_dropdown.html.haml b/app/views/shared/projects/_dropdown.html.haml index b7f8551153b..ac028f18e50 100644 --- a/app/views/shared/projects/_dropdown.html.haml +++ b/app/views/shared/projects/_dropdown.html.haml @@ -2,7 +2,7 @@ - personal = params[:personal] - archived = params[:archived] - namespace_id = params[:namespace_id] -.dropdown.inline +.dropdown - toggle_text = projects_sort_options_hash[@sort] = dropdown_toggle(toggle_text, { toggle: 'dropdown' }, { id: 'sort-projects-dropdown' }) %ul.dropdown-menu.dropdown-menu-align-right.dropdown-menu-selectable -- cgit v1.2.1 From f728589e6714be2367391bbf398d228a73d674d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Coutable?= Date: Wed, 25 Jan 2017 18:21:37 +0100 Subject: Document that the retro and kickoff notes are public MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [ci skip] Signed-off-by: Rémy Coutable --- CONTRIBUTING.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d404f1b91df..8d1f3d3f926 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -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 -- cgit v1.2.1 From 6fffdf7f2e72128eac53adfd734deb4fad8421fa Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Tue, 31 Jan 2017 15:28:14 -0600 Subject: remove dev-server config from development environment --- config/environments/development.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/config/environments/development.rb b/config/environments/development.rb index f8cf196bc7c..45a8c1add3e 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -1,6 +1,4 @@ Rails.application.configure do - WEBPACK_DEV_PORT = `cat ../webpack_port 2>/dev/null || echo '3808'`.to_i - # Settings specified here will take precedence over those in config/application.rb # In the development environment your application's code is reloaded on @@ -24,11 +22,6 @@ Rails.application.configure do # Only use best-standards-support built into browsers config.action_dispatch.best_standards_support = :builtin - # Enable webpack dev server - config.webpack.dev_server.enabled = true - config.webpack.dev_server.port = WEBPACK_DEV_PORT - config.webpack.dev_server.manifest_port = WEBPACK_DEV_PORT - # Do not compress assets config.assets.compress = false -- cgit v1.2.1 From e48a1755f42eabb2f459028d10d2d6c1160af4af Mon Sep 17 00:00:00 2001 From: Robert Speicher Date: Sun, 29 Jan 2017 17:37:24 -0500 Subject: Add traits for the different Event types to the Event factory --- spec/factories/events.rb | 12 +++++++++++ spec/finders/contributed_projects_finder_spec.rb | 13 +++++------- spec/lib/event_filter_spec.rb | 18 ++++++++-------- .../import_export/project_tree_saver_spec.rb | 2 +- spec/models/event_spec.rb | 24 +++++++++++----------- spec/models/user_spec.rb | 8 ++++---- spec/support/import_export/export_file_helper.rb | 2 +- 7 files changed, 44 insertions(+), 35 deletions(-) diff --git a/spec/factories/events.rb b/spec/factories/events.rb index bfe41f71b57..55727d6b62c 100644 --- a/spec/factories/events.rb +++ b/spec/factories/events.rb @@ -3,6 +3,18 @@ FactoryGirl.define do project factory: :empty_project author factory: :user + trait(:created) { action Event::CREATED } + trait(:updated) { action Event::UPDATED } + trait(:closed) { action Event::CLOSED } + trait(:reopened) { action Event::REOPENED } + trait(:pushed) { action Event::PUSHED } + trait(:commented) { action Event::COMMENTED } + trait(:merged) { action Event::MERGED } + trait(:joined) { action Event::JOINED } + trait(:left) { action Event::LEFT } + trait(:destroyed) { action Event::DESTROYED } + trait(:expired) { action Event::EXPIRED } + factory :closed_issue_event do action { Event::CLOSED } target factory: :closed_issue diff --git a/spec/finders/contributed_projects_finder_spec.rb b/spec/finders/contributed_projects_finder_spec.rb index ad2d456529a..34f665826b6 100644 --- a/spec/finders/contributed_projects_finder_spec.rb +++ b/spec/finders/contributed_projects_finder_spec.rb @@ -10,15 +10,12 @@ describe ContributedProjectsFinder do let!(:private_project) { create(:empty_project, :private) } before do - private_project.team << [source_user, Gitlab::Access::MASTER] - private_project.team << [current_user, Gitlab::Access::DEVELOPER] - public_project.team << [source_user, Gitlab::Access::MASTER] + private_project.add_master(source_user) + private_project.add_developer(current_user) + public_project.add_master(source_user) - create(:event, action: Event::PUSHED, project: public_project, - target: public_project, author: source_user) - - create(:event, action: Event::PUSHED, project: private_project, - target: private_project, author: source_user) + create(:event, :pushed, project: public_project, target: public_project, author: source_user) + create(:event, :pushed, project: private_project, target: private_project, author: source_user) end describe 'without a current user' do diff --git a/spec/lib/event_filter_spec.rb b/spec/lib/event_filter_spec.rb index e3066311b7d..d70690f589d 100644 --- a/spec/lib/event_filter_spec.rb +++ b/spec/lib/event_filter_spec.rb @@ -5,15 +5,15 @@ describe EventFilter, lib: true do let(:source_user) { create(:user) } let!(:public_project) { create(:empty_project, :public) } - let!(:push_event) { create(:event, action: Event::PUSHED, project: public_project, target: public_project, author: source_user) } - let!(:merged_event) { create(:event, action: Event::MERGED, project: public_project, target: public_project, author: source_user) } - let!(:created_event) { create(:event, action: Event::CREATED, project: public_project, target: public_project, author: source_user) } - let!(:updated_event) { create(:event, action: Event::UPDATED, project: public_project, target: public_project, author: source_user) } - let!(:closed_event) { create(:event, action: Event::CLOSED, project: public_project, target: public_project, author: source_user) } - let!(:reopened_event) { create(:event, action: Event::REOPENED, project: public_project, target: public_project, author: source_user) } - let!(:comments_event) { create(:event, action: Event::COMMENTED, project: public_project, target: public_project, author: source_user) } - let!(:joined_event) { create(:event, action: Event::JOINED, project: public_project, target: public_project, author: source_user) } - let!(:left_event) { create(:event, action: Event::LEFT, project: public_project, target: public_project, author: source_user) } + let!(:push_event) { create(:event, :pushed, project: public_project, target: public_project, author: source_user) } + let!(:merged_event) { create(:event, :merged, project: public_project, target: public_project, author: source_user) } + let!(:created_event) { create(:event, :created, project: public_project, target: public_project, author: source_user) } + let!(:updated_event) { create(:event, :updated, project: public_project, target: public_project, author: source_user) } + let!(:closed_event) { create(:event, :closed, project: public_project, target: public_project, author: source_user) } + let!(:reopened_event) { create(:event, :reopened, project: public_project, target: public_project, author: source_user) } + let!(:comments_event) { create(:event, :commented, project: public_project, target: public_project, author: source_user) } + let!(:joined_event) { create(:event, :joined, project: public_project, target: public_project, author: source_user) } + let!(:left_event) { create(:event, :left, project: public_project, target: public_project, author: source_user) } it 'applies push filter' do events = EventFilter.new(EventFilter.push).apply_filter(Event.all) diff --git a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb index d480c3821ec..1d65b24c2c9 100644 --- a/spec/lib/gitlab/import_export/project_tree_saver_spec.rb +++ b/spec/lib/gitlab/import_export/project_tree_saver_spec.rb @@ -182,7 +182,7 @@ describe Gitlab::ImportExport::ProjectTreeSaver, services: true do project: project, commit_id: ci_pipeline.sha) - create(:event, target: milestone, project: project, action: Event::CREATED, author: user) + create(:event, :created, target: milestone, project: project, author: user) create(:service, project: project, type: 'CustomIssueTrackerService', category: 'issue_tracker') project.project_feature.update_attribute(:issues_access_level, ProjectFeature::DISABLED) diff --git a/spec/models/event_spec.rb b/spec/models/event_spec.rb index 349474bb656..8c90a538f57 100644 --- a/spec/models/event_spec.rb +++ b/spec/models/event_spec.rb @@ -19,7 +19,7 @@ describe Event, models: true do let(:project) { create(:empty_project) } it 'calls the reset_project_activity method' do - expect_any_instance_of(Event).to receive(:reset_project_activity) + expect_any_instance_of(described_class).to receive(:reset_project_activity) create_event(project, project.owner) end @@ -43,33 +43,33 @@ describe Event, models: true do describe '#membership_changed?' do context "created" do - subject { build(:event, action: Event::CREATED).membership_changed? } + subject { build(:event, :created).membership_changed? } it { is_expected.to be_falsey } end context "updated" do - subject { build(:event, action: Event::UPDATED).membership_changed? } + subject { build(:event, :updated).membership_changed? } it { is_expected.to be_falsey } end context "expired" do - subject { build(:event, action: Event::EXPIRED).membership_changed? } + subject { build(:event, :expired).membership_changed? } it { is_expected.to be_truthy } end context "left" do - subject { build(:event, action: Event::LEFT).membership_changed? } + subject { build(:event, :left).membership_changed? } it { is_expected.to be_truthy } end context "joined" do - subject { build(:event, action: Event::JOINED).membership_changed? } + subject { build(:event, :joined).membership_changed? } it { is_expected.to be_truthy } end end describe '#note?' do - subject { Event.new(project: target.project, target: target) } + subject { described_class.new(project: target.project, target: target) } context 'issue note event' do let(:target) { create(:note_on_issue) } @@ -97,7 +97,7 @@ describe Event, models: true do let(:note_on_commit) { create(:note_on_commit, project: project) } let(:note_on_issue) { create(:note_on_issue, noteable: issue, project: project) } let(:note_on_confidential_issue) { create(:note_on_issue, noteable: confidential_issue, project: project) } - let(:event) { Event.new(project: project, target: target, author_id: author.id) } + let(:event) { described_class.new(project: project, target: target, author_id: author.id) } before do project.team << [member, :developer] @@ -221,13 +221,13 @@ describe Event, models: true do let!(:event2) { create(:closed_issue_event) } describe 'without an explicit limit' do - subject { Event.limit_recent } + subject { described_class.limit_recent } it { is_expected.to eq([event2, event1]) } end describe 'with an explicit limit' do - subject { Event.limit_recent(1) } + subject { described_class.limit_recent(1) } it { is_expected.to eq([event2]) } end @@ -294,9 +294,9 @@ describe Event, models: true do } } - Event.create({ + described_class.create({ project: project, - action: Event::PUSHED, + action: described_class::PUSHED, data: data, author_id: user.id }.merge!(attrs)) diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 6ca5ad747d1..6d58b1455c4 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -1013,8 +1013,8 @@ describe User, models: true do let!(:project2) { create(:empty_project, forked_from_project: project3) } let!(:project3) { create(:empty_project) } let!(:merge_request) { create(:merge_request, source_project: project2, target_project: project3, author: subject) } - let!(:push_event) { create(:event, action: Event::PUSHED, project: project1, target: project1, author: subject) } - let!(:merge_event) { create(:event, action: Event::CREATED, project: project3, target: merge_request, author: subject) } + let!(:push_event) { create(:event, :pushed, project: project1, target: project1, author: subject) } + let!(:merge_event) { create(:event, :created, project: project3, target: merge_request, author: subject) } before do project1.team << [subject, :master] @@ -1058,7 +1058,7 @@ describe User, models: true do let!(:push_data) do Gitlab::DataBuilder::Push.build_sample(project2, subject) end - let!(:push_event) { create(:event, action: Event::PUSHED, project: project2, target: project1, author: subject, data: push_data) } + let!(:push_event) { create(:event, :pushed, project: project2, target: project1, author: subject, data: push_data) } before do project1.team << [subject, :master] @@ -1086,7 +1086,7 @@ describe User, models: true do expect(subject.recent_push(project2)).to eq(push_event) push_data1 = Gitlab::DataBuilder::Push.build_sample(project1, subject) - push_event1 = create(:event, action: Event::PUSHED, project: project1, target: project1, author: subject, data: push_data1) + push_event1 = create(:event, :pushed, project: project1, target: project1, author: subject, data: push_data1) expect(subject.recent_push([project1, project2])).to eq(push_event1) # Newest end diff --git a/spec/support/import_export/export_file_helper.rb b/spec/support/import_export/export_file_helper.rb index 1b0a4583f5c..944ea30656f 100644 --- a/spec/support/import_export/export_file_helper.rb +++ b/spec/support/import_export/export_file_helper.rb @@ -35,7 +35,7 @@ module ExportFileHelper project: project, commit_id: ci_pipeline.sha) - create(:event, target: milestone, project: project, action: Event::CREATED, author: user) + create(:event, :created, target: milestone, project: project, author: user) create(:project_member, :master, user: user, project: project) create(:ci_variable, project: project) create(:ci_trigger, project: project) -- cgit v1.2.1 From a2d837a3719187a906b60b9212b0dbf02396cb59 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Wed, 1 Feb 2017 13:05:33 -0600 Subject: add rack middleware to proxy webpack dev server --- Gemfile | 2 ++ Gemfile.lock | 3 +++ config/application.rb | 2 ++ config/gitlab.yml.example | 10 ++++++++++ config/initializers/1_settings.rb | 9 +++++++++ config/initializers/static_files.rb | 21 +++++++++++++++++++++ lib/gitlab/middleware/webpack_proxy.rb | 24 ++++++++++++++++++++++++ 7 files changed, 71 insertions(+) create mode 100644 lib/gitlab/middleware/webpack_proxy.rb diff --git a/Gemfile b/Gemfile index f9aecca70ff..6af69e8a37a 100644 --- a/Gemfile +++ b/Gemfile @@ -312,6 +312,8 @@ group :development, :test do gem 'activerecord_sane_schema_dumper', '0.2' gem 'stackprof', '~> 0.2.10' + + gem 'rack-proxy', '~> 0.6.0' end group :test do diff --git a/Gemfile.lock b/Gemfile.lock index 0434fdefcd5..bcf500b16f9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -544,6 +544,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) @@ -943,6 +945,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) diff --git a/config/application.rb b/config/application.rb index 4efe73c7798..9088d3c432b 100644 --- a/config/application.rb +++ b/config/application.rb @@ -84,6 +84,8 @@ module Gitlab config.webpack.config_file = "config/webpack.config.js" config.webpack.output_dir = "public/assets/webpack" config.webpack.public_path = "assets/webpack" + + # Webpack dev server configuration is handled in initializers/static_files.rb config.webpack.dev_server.enabled = false # Enable the asset pipeline diff --git a/config/gitlab.yml.example b/config/gitlab.yml.example index 42e5f105d46..2906633fcbc 100644 --- a/config/gitlab.yml.example +++ b/config/gitlab.yml.example @@ -505,6 +505,16 @@ production: &base # Git timeout to read a commit, in seconds timeout: 10 + ## Webpack settings + # If enabled, this will tell rails to serve frontend assets from the webpack-dev-server running + # on a given port instead of serving directly from /assets/webpack. This is only indended for use + # in development. + webpack: + # dev_server: + # enabled: true + # host: localhost + # port: 3808 + # # 5. Extra customization # ========================== diff --git a/config/initializers/1_settings.rb b/config/initializers/1_settings.rb index 4f33aad8693..ea61aa9e047 100644 --- a/config/initializers/1_settings.rb +++ b/config/initializers/1_settings.rb @@ -409,6 +409,15 @@ Settings.rack_attack.git_basic_auth['bantime'] ||= 1.hour Settings['gitaly'] ||= Settingslogic.new({}) Settings.gitaly['socket_path'] ||= ENV['GITALY_SOCKET_PATH'] +# +# Webpack settings +# +Settings['webpack'] ||= Settingslogic.new({}) +Settings.webpack['dev_server'] ||= Settingslogic.new({}) +Settings.webpack.dev_server['enabled'] ||= false +Settings.webpack.dev_server['host'] ||= 'localhost' +Settings.webpack.dev_server['port'] ||= 3808 + # # Testing settings # diff --git a/config/initializers/static_files.rb b/config/initializers/static_files.rb index d6dbf8b9fbf..718cdd51782 100644 --- a/config/initializers/static_files.rb +++ b/config/initializers/static_files.rb @@ -12,4 +12,25 @@ if app.config.serve_static_files app.paths["public"].first, app.config.static_cache_control ) + + # If webpack-dev-server is configured, proxy webpack's public directory + # instead of looking for static assets + if Gitlab.config.webpack.dev_server.enabled + app.config.webpack.dev_server.merge!( + enabled: true, + host: Gitlab.config.gitlab.host, + port: Gitlab.config.gitlab.port, + https: Gitlab.config.gitlab.https, + manifest_host: Gitlab.config.webpack.dev_server.host, + manifest_port: Gitlab.config.webpack.dev_server.port, + ) + + app.config.middleware.insert_before( + Gitlab::Middleware::Static, + Gitlab::Middleware::WebpackProxy, + proxy_path: app.config.webpack.public_path, + proxy_host: Gitlab.config.webpack.dev_server.host, + proxy_port: Gitlab.config.webpack.dev_server.port, + ) + end end diff --git a/lib/gitlab/middleware/webpack_proxy.rb b/lib/gitlab/middleware/webpack_proxy.rb new file mode 100644 index 00000000000..3fe32adeade --- /dev/null +++ b/lib/gitlab/middleware/webpack_proxy.rb @@ -0,0 +1,24 @@ +# This Rack middleware is intended to proxy the webpack assets directory to the +# webpack-dev-server. It is only intended for use in development. + +module Gitlab + module Middleware + class WebpackProxy < Rack::Proxy + def initialize(app = nil, opts = {}) + @proxy_host = opts.fetch(:proxy_host, 'localhost') + @proxy_port = opts.fetch(:proxy_port, 3808) + @proxy_path = opts[:proxy_path] if opts[:proxy_path] + super(app, opts) + end + + def perform_request(env) + unless @proxy_path && env['PATH_INFO'].start_with?("/#{@proxy_path}") + return @app.call(env) + end + + env['HTTP_HOST'] = "#{@proxy_host}:#{@proxy_port}" + super(env) + end + end + end +end -- cgit v1.2.1 From 6b2e5e344cb81070ec69efd0f7029abe1db8163d Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Wed, 1 Feb 2017 13:05:52 -0600 Subject: configure webpack dev server port via environment variable --- config/webpack.config.js | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/config/webpack.config.js b/config/webpack.config.js index bddd181b452..db4ce84f376 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -6,18 +6,10 @@ var webpack = require('webpack'); var StatsPlugin = require('stats-webpack-plugin'); var CompressionPlugin = require("compression-webpack-plugin"); +var ROOT_PATH = path.resolve(__dirname, '..'); var IS_PRODUCTION = process.env.NODE_ENV === 'production'; var IS_DEV_SERVER = process.argv[1].indexOf('webpack-dev-server') !== -1; -var ROOT_PATH = path.resolve(__dirname, '..'); - -// must match config.webpack.dev_server.port -var DEV_SERVER_PORT; - -try { - DEV_SERVER_PORT = parseInt(fs.readFileSync('../webpack_port'), 10); -} catch (e) { - DEV_SERVER_PORT = 3808; -} +var DEV_SERVER_PORT = parseInt(process.env.DEV_SERVER_PORT, 10) || 3808; var config = { context: path.join(ROOT_PATH, 'app/assets/javascripts'), -- cgit v1.2.1 From deb2fa20a9ba97bba9105942c81e7b8ce34d566e Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Wed, 1 Feb 2017 13:51:16 -0600 Subject: remove changes to Procfile --- Procfile | 1 - 1 file changed, 1 deletion(-) diff --git a/Procfile b/Procfile index 5e8f4a962ab..cad738d4292 100644 --- a/Procfile +++ b/Procfile @@ -4,5 +4,4 @@ # web: RAILS_ENV=development bin/web start_foreground worker: RAILS_ENV=development bin/background_jobs start_foreground -webpack: npm run dev-server # mail_room: bundle exec mail_room -q -c config/mail_room.yml -- cgit v1.2.1 From 5a099315eb29c345925141609dc5a3a395312016 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 2 Feb 2017 10:46:47 -0600 Subject: disable webpack proxy in rspec environment due to conflicts with webmock gem --- config/initializers/static_files.rb | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/config/initializers/static_files.rb b/config/initializers/static_files.rb index 718cdd51782..cb332e15c11 100644 --- a/config/initializers/static_files.rb +++ b/config/initializers/static_files.rb @@ -16,21 +16,29 @@ if app.config.serve_static_files # If webpack-dev-server is configured, proxy webpack's public directory # instead of looking for static assets if Gitlab.config.webpack.dev_server.enabled - app.config.webpack.dev_server.merge!( + dev_server = { enabled: true, - host: Gitlab.config.gitlab.host, - port: Gitlab.config.gitlab.port, - https: Gitlab.config.gitlab.https, + host: Gitlab.config.webpack.dev_server.host, + port: Gitlab.config.webpack.dev_server.port, manifest_host: Gitlab.config.webpack.dev_server.host, manifest_port: Gitlab.config.webpack.dev_server.port, - ) + } - app.config.middleware.insert_before( - Gitlab::Middleware::Static, - Gitlab::Middleware::WebpackProxy, - proxy_path: app.config.webpack.public_path, - proxy_host: Gitlab.config.webpack.dev_server.host, - proxy_port: Gitlab.config.webpack.dev_server.port, - ) + if Rails.env.development? + dev_server.merge!( + host: Gitlab.config.gitlab.host, + port: Gitlab.config.gitlab.port, + https: Gitlab.config.gitlab.https, + ) + app.config.middleware.insert_before( + Gitlab::Middleware::Static, + Gitlab::Middleware::WebpackProxy, + proxy_path: app.config.webpack.public_path, + proxy_host: Gitlab.config.webpack.dev_server.host, + proxy_port: Gitlab.config.webpack.dev_server.port, + ) + end + + app.config.webpack.dev_server.merge!(dev_server) end end -- cgit v1.2.1 From fbd09871ca7003242053fbca10d9c0e96e7a799d Mon Sep 17 00:00:00 2001 From: Bryce Johnson Date: Fri, 13 Jan 2017 16:54:16 -0500 Subject: Remove turbolinks. --- Gemfile | 1 - Gemfile.lock | 3 - app/assets/javascripts/admin.js | 5 +- app/assets/javascripts/application.js | 4 +- app/assets/javascripts/breakpoints.js | 1 + app/assets/javascripts/build.js | 3 +- .../filtered_search_dropdown_manager.js.es6 | 4 +- .../filtered_search/filtered_search_manager.js.es6 | 10 +-- app/assets/javascripts/gl_dropdown.js | 3 +- app/assets/javascripts/issuable.js.es6 | 5 +- .../lib/utils/bootstrap_linked_tabs.js.es6 | 1 - app/assets/javascripts/lib/utils/url_utility.js | 80 -------------------- .../javascripts/lib/utils/url_utility.js.es6 | 86 ++++++++++++++++++++++ app/assets/javascripts/line_highlighter.js | 1 - app/assets/javascripts/logo.js | 9 +-- app/assets/javascripts/merge_request_tabs.js.es6 | 3 +- app/assets/javascripts/merge_request_widget.js.es6 | 5 +- app/assets/javascripts/project.js | 3 +- app/assets/javascripts/project_import.js | 3 +- app/assets/javascripts/render_gfm.js | 2 +- app/assets/javascripts/shortcuts.js | 3 +- app/assets/javascripts/shortcuts_issuable.js | 3 +- app/assets/javascripts/sidebar.js.es6 | 2 +- app/assets/javascripts/smart_interval.js.es6 | 5 +- app/assets/javascripts/todos.js.es6 | 7 +- app/assets/javascripts/tree.js | 6 +- app/assets/javascripts/user_tabs.js.es6 | 1 - app/assets/javascripts/vue_pagination/index.js.es6 | 4 +- .../vue_pipelines_index/pipelines.js.es6 | 4 +- .../javascripts/vue_realtime_listener/index.js.es6 | 4 +- app/assets/stylesheets/framework.scss | 1 - app/assets/stylesheets/framework/progress.scss | 5 -- app/helpers/javascript_helper.rb | 2 +- app/views/devise/shared/_omniauth_box.html.haml | 2 +- app/views/import/bitbucket/status.html.haml | 2 +- app/views/layouts/_head.html.haml | 2 + app/views/layouts/application.html.haml | 3 - app/views/profiles/accounts/show.html.haml | 2 +- app/views/projects/merge_requests/_show.html.haml | 8 +- app/views/projects/new.html.haml | 2 +- app/views/shared/issuable/_filter.html.haml | 2 +- ...anticipate-obstacles-to-removing-turbolinks.yml | 4 + features/steps/project/merge_requests.rb | 1 + spec/javascripts/behaviors/autosize_spec.js | 2 +- spec/javascripts/behaviors/requires_input_spec.js | 6 -- spec/javascripts/bootstrap_linked_tabs_spec.js.es6 | 1 - spec/javascripts/build_spec.js.es6 | 7 +- spec/javascripts/gl_dropdown_spec.js.es6 | 7 +- spec/javascripts/issuable_spec.js.es6 | 17 ++--- spec/javascripts/merge_request_tabs_spec.js | 1 - spec/javascripts/search_autocomplete_spec.js | 2 - spec/javascripts/smart_interval_spec.js.es6 | 2 +- spec/javascripts/spec_helper.js | 1 - vendor/assets/javascripts/jquery.turbolinks.js | 49 ------------ 54 files changed, 161 insertions(+), 241 deletions(-) delete mode 100644 app/assets/javascripts/lib/utils/url_utility.js create mode 100644 app/assets/javascripts/lib/utils/url_utility.js.es6 delete mode 100644 app/assets/stylesheets/framework/progress.scss create mode 100644 changelogs/unreleased/25624-anticipate-obstacles-to-removing-turbolinks.yml delete mode 100644 vendor/assets/javascripts/jquery.turbolinks.js diff --git a/Gemfile b/Gemfile index dd7c93c5a75..62064fa82b6 100644 --- a/Gemfile +++ b/Gemfile @@ -222,7 +222,6 @@ gem 'chronic_duration', '~> 0.10.6' 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' diff --git a/Gemfile.lock b/Gemfile.lock index 3b207d19d1f..6db54b77979 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -266,8 +266,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) @@ -891,7 +889,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) diff --git a/app/assets/javascripts/admin.js b/app/assets/javascripts/admin.js index 993f427c9fb..424dc719c78 100644 --- a/app/assets/javascripts/admin.js +++ b/app/assets/javascripts/admin.js @@ -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') { diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 4849aab50f4..ad95c1b9dfb 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -24,9 +24,7 @@ /*= 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 */ @@ -64,7 +62,7 @@ /*= require es6-promise.auto */ (function () { - document.addEventListener('page:fetch', function () { + document.addEventListener('beforeunload', function () { // Unbind scroll events $(document).off('scroll'); // Close any open tooltips diff --git a/app/assets/javascripts/breakpoints.js b/app/assets/javascripts/breakpoints.js index eae062a3aa3..f8dac1ff56e 100644 --- a/app/assets/javascripts/breakpoints.js +++ b/app/assets/javascripts/breakpoints.js @@ -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(); diff --git a/app/assets/javascripts/build.js b/app/assets/javascripts/build.js index 0df84234520..0152be88b48 100644 --- a/app/assets/javascripts/build.js +++ b/app/assets/javascripts/build.js @@ -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) diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6 index 00e1c28692f..547989a6ff5 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.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() { diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 b/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 index 029564ffc61..4e02ab7c8c1 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 +++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js.es6 @@ -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() { diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js index d2f66cf5249..dbc9b2e2a1c 100644 --- a/app/assets/javascripts/gl_dropdown.js +++ b/app/assets/javascripts/gl_dropdown.js @@ -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, @@ -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'); } diff --git a/app/assets/javascripts/issuable.js.es6 b/app/assets/javascripts/issuable.js.es6 index f63d700fd65..8df86f68218 100644 --- a/app/assets/javascripts/issuable.js.es6 +++ b/app/assets/javascripts/issuable.js.es6 @@ -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() { diff --git a/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js.es6 b/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js.es6 index e810ee85bd3..2955bda1a36 100644 --- a/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js.es6 +++ b/app/assets/javascripts/lib/utils/bootstrap_linked_tabs.js.es6 @@ -95,7 +95,6 @@ const newState = `${copySource}${this.currentLocation.search}${this.currentLocation.hash}`; history.replaceState({ - turbolinks: true, url: newState, }, document.title, newState); return newState; diff --git a/app/assets/javascripts/lib/utils/url_utility.js b/app/assets/javascripts/lib/utils/url_utility.js deleted file mode 100644 index 8e15bf0735c..00000000000 --- a/app/assets/javascripts/lib/utils/url_utility.js +++ /dev/null @@ -1,80 +0,0 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-param-reassign, no-cond-assign, one-var, one-var-declaration-per-line, no-void, guard-for-in, no-restricted-syntax, prefer-template, quotes, max-len */ -(function() { - (function(w) { - var base; - if (w.gl == null) { - w.gl = {}; - } - if ((base = w.gl).utils == null) { - base.utils = {}; - } - // Returns an array containing the value(s) of the - // of the key passed as an argument - w.gl.utils.getParameterValues = function(sParam) { - var i, sPageURL, sParameterName, sURLVariables, values; - sPageURL = decodeURIComponent(window.location.search.substring(1)); - sURLVariables = sPageURL.split('&'); - sParameterName = void 0; - values = []; - i = 0; - while (i < sURLVariables.length) { - sParameterName = sURLVariables[i].split('='); - if (sParameterName[0] === sParam) { - values.push(sParameterName[1].replace(/\+/g, ' ')); - } - i += 1; - } - return values; - }; - // @param {Object} params - url keys and value to merge - // @param {String} url - w.gl.utils.mergeUrlParams = function(params, url) { - var lastChar, newUrl, paramName, paramValue, pattern; - newUrl = decodeURIComponent(url); - for (paramName in params) { - paramValue = params[paramName]; - pattern = new RegExp("\\b(" + paramName + "=).*?(&|$)"); - if (paramValue == null) { - newUrl = newUrl.replace(pattern, ''); - } else if (url.search(pattern) !== -1) { - newUrl = newUrl.replace(pattern, "$1" + paramValue + "$2"); - } else { - newUrl = "" + newUrl + (newUrl.indexOf('?') > 0 ? '&' : '?') + paramName + "=" + paramValue; - } - } - // Remove a trailing ampersand - lastChar = newUrl[newUrl.length - 1]; - if (lastChar === '&') { - newUrl = newUrl.slice(0, -1); - } - return newUrl; - }; - // removes parameter query string from url. returns the modified url - w.gl.utils.removeParamQueryString = function(url, param) { - var urlVariables, variables; - url = decodeURIComponent(url); - urlVariables = url.split('&'); - return ((function() { - var j, len, results; - results = []; - for (j = 0, len = urlVariables.length; j < len; j += 1) { - variables = urlVariables[j]; - if (variables.indexOf(param) === -1) { - results.push(variables); - } - } - return results; - })()).join('&'); - }; - w.gl.utils.getLocationHash = function(url) { - var hashIndex; - if (typeof url === 'undefined') { - // Note: We can't use window.location.hash here because it's - // not consistent across browsers - Firefox will pre-decode it - url = window.location.href; - } - hashIndex = url.indexOf('#'); - return hashIndex === -1 ? null : url.substring(hashIndex + 1); - }; - })(window); -}).call(this); diff --git a/app/assets/javascripts/lib/utils/url_utility.js.es6 b/app/assets/javascripts/lib/utils/url_utility.js.es6 new file mode 100644 index 00000000000..a1558b371f0 --- /dev/null +++ b/app/assets/javascripts/lib/utils/url_utility.js.es6 @@ -0,0 +1,86 @@ +/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-var, no-param-reassign, no-cond-assign, one-var, one-var-declaration-per-line, no-void, guard-for-in, no-restricted-syntax, prefer-template, quotes, max-len */ +(function() { + (function(w) { + var base; + if (w.gl == null) { + w.gl = {}; + } + if ((base = w.gl).utils == null) { + base.utils = {}; + } + // Returns an array containing the value(s) of the + // of the key passed as an argument + w.gl.utils.getParameterValues = function(sParam) { + var i, sPageURL, sParameterName, sURLVariables, values; + sPageURL = decodeURIComponent(window.location.search.substring(1)); + sURLVariables = sPageURL.split('&'); + sParameterName = void 0; + values = []; + i = 0; + while (i < sURLVariables.length) { + sParameterName = sURLVariables[i].split('='); + if (sParameterName[0] === sParam) { + values.push(sParameterName[1].replace(/\+/g, ' ')); + } + i += 1; + } + return values; + }; + // @param {Object} params - url keys and value to merge + // @param {String} url + w.gl.utils.mergeUrlParams = function(params, url) { + var lastChar, newUrl, paramName, paramValue, pattern; + newUrl = decodeURIComponent(url); + for (paramName in params) { + paramValue = params[paramName]; + pattern = new RegExp("\\b(" + paramName + "=).*?(&|$)"); + if (paramValue == null) { + newUrl = newUrl.replace(pattern, ''); + } else if (url.search(pattern) !== -1) { + newUrl = newUrl.replace(pattern, "$1" + paramValue + "$2"); + } else { + newUrl = "" + newUrl + (newUrl.indexOf('?') > 0 ? '&' : '?') + paramName + "=" + paramValue; + } + } + // Remove a trailing ampersand + lastChar = newUrl[newUrl.length - 1]; + if (lastChar === '&') { + newUrl = newUrl.slice(0, -1); + } + return newUrl; + }; + // removes parameter query string from url. returns the modified url + w.gl.utils.removeParamQueryString = function(url, param) { + var urlVariables, variables; + url = decodeURIComponent(url); + urlVariables = url.split('&'); + return ((function() { + var j, len, results; + results = []; + for (j = 0, len = urlVariables.length; j < len; j += 1) { + variables = urlVariables[j]; + if (variables.indexOf(param) === -1) { + results.push(variables); + } + } + return results; + })()).join('&'); + }; + w.gl.utils.getLocationHash = function(url) { + var hashIndex; + if (typeof url === 'undefined') { + // Note: We can't use window.location.hash here because it's + // not consistent across browsers - Firefox will pre-decode it + url = window.location.href; + } + 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); diff --git a/app/assets/javascripts/line_highlighter.js b/app/assets/javascripts/line_highlighter.js index 2f147704c22..78e338033e3 100644 --- a/app/assets/javascripts/line_highlighter.js +++ b/app/assets/javascripts/line_highlighter.js @@ -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 diff --git a/app/assets/javascripts/logo.js b/app/assets/javascripts/logo.js index ea9bfb4860a..1b0d0768db8 100644 --- a/app/assets/javascripts/logo.js +++ b/app/assets/javascripts/logo.js @@ -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); diff --git a/app/assets/javascripts/merge_request_tabs.js.es6 b/app/assets/javascripts/merge_request_tabs.js.es6 index 4c8c28af755..33463b46008 100644 --- a/app/assets/javascripts/merge_request_tabs.js.es6 +++ b/app/assets/javascripts/merge_request_tabs.js.es6 @@ -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); diff --git a/app/assets/javascripts/merge_request_widget.js.es6 b/app/assets/javascripts/merge_request_widget.js.es6 index fa782ebbedf..2c19029d175 100644 --- a/app/assets/javascripts/merge_request_widget.js.es6 +++ b/app/assets/javascripts/merge_request_widget.js.es6 @@ -2,7 +2,6 @@ /* global notify */ /* global notifyPermissions */ /* global merge_request_widget */ -/* global Turbolinks */ ((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 +68,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(); diff --git a/app/assets/javascripts/project.js b/app/assets/javascripts/project.js index 7cf630a1d76..399b331c941 100644 --- a/app/assets/javascripts/project.js +++ b/app/assets/javascripts/project.js @@ -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() { @@ -99,7 +98,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()); } } }); diff --git a/app/assets/javascripts/project_import.js b/app/assets/javascripts/project_import.js index 6614d8952cd..d7943959238 100644 --- a/app/assets/javascripts/project_import.js +++ b/app/assets/javascripts/project_import.js @@ -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); } diff --git a/app/assets/javascripts/render_gfm.js b/app/assets/javascripts/render_gfm.js index 0caf8ba4344..bdbad93ad04 100644 --- a/app/assets/javascripts/render_gfm.js +++ b/app/assets/javascripts/render_gfm.js @@ -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); diff --git a/app/assets/javascripts/shortcuts.js b/app/assets/javascripts/shortcuts.js index c56ee429b8e..c6d9b007ad1 100644 --- a/app/assets/javascripts/shortcuts.js +++ b/app/assets/javascripts/shortcuts.js @@ -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); }); } } diff --git a/app/assets/javascripts/shortcuts_issuable.js b/app/assets/javascripts/shortcuts_issuable.js index 4dcc5ebe28f..3501974a8c9 100644 --- a/app/assets/javascripts/shortcuts_issuable.js +++ b/app/assets/javascripts/shortcuts_issuable.js @@ -1,6 +1,5 @@ /* eslint-disable func-names, space-before-function-paren, max-len, no-var, one-var, no-restricted-syntax, vars-on-top, no-use-before-define, no-param-reassign, new-cap, no-underscore-dangle, wrap-iife, one-var-declaration-per-line, quotes, prefer-arrow-callback, consistent-return, prefer-template, no-mixed-operators */ /* global Mousetrap */ -/* global Turbolinks */ /* global ShortcutsNavigation */ /* global sidebar */ @@ -80,7 +79,7 @@ ShortcutsIssuable.prototype.editIssue = function() { var $editBtn; $editBtn = $('.issuable-edit'); - return Turbolinks.visit($editBtn.attr('href')); + return gl.utils.visitUrl($editBtn.attr('href')); }; ShortcutsIssuable.prototype.openSidebarDropdown = function(name) { diff --git a/app/assets/javascripts/sidebar.js.es6 b/app/assets/javascripts/sidebar.js.es6 index 05234643c18..ee172f2fa6f 100644 --- a/app/assets/javascripts/sidebar.js.es6 +++ b/app/assets/javascripts/sidebar.js.es6 @@ -40,7 +40,7 @@ .on('click', sidebarToggleSelector, () => this.toggleSidebar()) .on('click', pinnedToggleSelector, () => this.togglePinnedState()) .on('click', 'html, body', (e) => this.handleClickEvent(e)) - .on('page:change', () => this.renderState()) + .on('DOMContentLoaded', () => this.renderState()) .on('todo:toggle', (e, count) => this.updateTodoCount(count)); this.renderState(); } diff --git a/app/assets/javascripts/smart_interval.js.es6 b/app/assets/javascripts/smart_interval.js.es6 index 40f67637c7c..d1bdc353be2 100644 --- a/app/assets/javascripts/smart_interval.js.es6 +++ b/app/assets/javascripts/smart_interval.js.es6 @@ -89,7 +89,7 @@ destroy() { this.cancel(); document.removeEventListener('visibilitychange', this.handleVisibilityChange); - $(document).off('visibilitychange').off('page:before-unload'); + $(document).off('visibilitychange').off('beforeunload'); } /* private */ @@ -111,8 +111,9 @@ } initPageUnloadHandling() { + // TODO: Consider refactoring in light of turbolinks removal. // prevent interval continuing after page change, when kept in cache by Turbolinks - $(document).on('page:before-unload', () => this.cancel()); + $(document).on('beforeunload', () => this.cancel()); } handleVisibilityChange(e) { diff --git a/app/assets/javascripts/todos.js.es6 b/app/assets/javascripts/todos.js.es6 index 05622916ff8..96c7d927509 100644 --- a/app/assets/javascripts/todos.js.es6 +++ b/app/assets/javascripts/todos.js.es6 @@ -1,6 +1,5 @@ /* eslint-disable class-methods-use-this, no-new, func-names, prefer-template, no-unneeded-ternary, object-shorthand, space-before-function-paren, comma-dangle, quote-props, consistent-return, no-else-return, no-param-reassign, max-len */ /* global UsersSelect */ -/* global Turbolinks */ ((global) => { class Todos { @@ -34,7 +33,7 @@ $('form.filter-form').on('submit', function (event) { event.preventDefault(); - Turbolinks.visit(this.action + '&' + $(this).serialize()); + gl.utils.visitUrl(this.action + '&' + $(this).serialize()); }); } @@ -142,7 +141,7 @@ }; url = gl.utils.mergeUrlParams(pageParams, url); } - return Turbolinks.visit(url); + return gl.utils.visitUrl(url); } } @@ -156,7 +155,7 @@ e.preventDefault(); return window.open(todoLink, '_blank'); } else { - return Turbolinks.visit(todoLink); + return gl.utils.visitUrl(todoLink); } } } diff --git a/app/assets/javascripts/tree.js b/app/assets/javascripts/tree.js index d124ca4f88b..b1b35fdbd6c 100644 --- a/app/assets/javascripts/tree.js +++ b/app/assets/javascripts/tree.js @@ -1,5 +1,5 @@ /* eslint-disable func-names, space-before-function-paren, wrap-iife, max-len, quotes, consistent-return, no-var, one-var, one-var-declaration-per-line, no-else-return, prefer-arrow-callback, max-len */ -/* global Turbolinks */ + (function() { this.TreeView = (function() { function TreeView() { @@ -15,7 +15,7 @@ e.preventDefault(); return window.open(path, '_blank'); } else { - return Turbolinks.visit(path); + return gl.utils.visitUrl(path); } } }); @@ -57,7 +57,7 @@ } else if (e.which === 13) { path = $('.tree-item.selected .tree-item-file-name a').attr('href'); if (path) { - return Turbolinks.visit(path); + return gl.utils.visitUrl(path); } } }); diff --git a/app/assets/javascripts/user_tabs.js.es6 b/app/assets/javascripts/user_tabs.js.es6 index 313fb17aee8..465618e3d53 100644 --- a/app/assets/javascripts/user_tabs.js.es6 +++ b/app/assets/javascripts/user_tabs.js.es6 @@ -149,7 +149,6 @@ content on the Users#show page. new_state = new_state.replace(/\/+$/, ''); new_state += this._location.search + this._location.hash; history.replaceState({ - turbolinks: true, url: new_state }, document.title, new_state); return new_state; diff --git a/app/assets/javascripts/vue_pagination/index.js.es6 b/app/assets/javascripts/vue_pagination/index.js.es6 index 605824fa939..d94caa983cd 100644 --- a/app/assets/javascripts/vue_pagination/index.js.es6 +++ b/app/assets/javascripts/vue_pagination/index.js.es6 @@ -13,6 +13,8 @@ gl.VueGlPagination = Vue.extend({ props: { + // TODO: Consider refactoring in light of turbolinks removal. + /** This function will take the information given by the pagination component And make a new Turbolinks call @@ -20,7 +22,7 @@ Here is an example `change` method: change(pagenum, apiScope) { - Turbolinks.visit(`?scope=${apiScope}&p=${pagenum}`); + gl.utils.visitUrl(`?scope=${apiScope}&p=${pagenum}`); }, */ diff --git a/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6 b/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6 index b2ed05503c9..194bbae07d9 100644 --- a/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6 +++ b/app/assets/javascripts/vue_pipelines_index/pipelines.js.es6 @@ -1,4 +1,4 @@ -/* global Vue, Turbolinks, gl */ +/* global Vue, gl */ /* eslint-disable no-param-reassign */ ((gl) => { @@ -36,7 +36,7 @@ }, methods: { change(pagenum, apiScope) { - Turbolinks.visit(`?scope=${apiScope}&p=${pagenum}`); + gl.utils.visitUrl(`?scope=${apiScope}&p=${pagenum}`); }, author(pipeline) { if (!pipeline.commit) return { avatar_url: '', web_url: '', username: '' }; diff --git a/app/assets/javascripts/vue_realtime_listener/index.js.es6 b/app/assets/javascripts/vue_realtime_listener/index.js.es6 index 23cac1466d2..95564152cce 100644 --- a/app/assets/javascripts/vue_realtime_listener/index.js.es6 +++ b/app/assets/javascripts/vue_realtime_listener/index.js.es6 @@ -7,12 +7,12 @@ window.removeEventListener('beforeunload', removeIntervals); window.removeEventListener('focus', startIntervals); window.removeEventListener('blur', removeIntervals); - document.removeEventListener('page:fetch', removeAll); + document.removeEventListener('beforeunload', removeAll); }; window.addEventListener('beforeunload', removeIntervals); window.addEventListener('focus', startIntervals); window.addEventListener('blur', removeIntervals); - document.addEventListener('page:fetch', removeAll); + document.addEventListener('beforeunload', removeAll); }; })(window.gl || (window.gl = {})); diff --git a/app/assets/stylesheets/framework.scss b/app/assets/stylesheets/framework.scss index 3cf49f4ff1b..08f203a1bf6 100644 --- a/app/assets/stylesheets/framework.scss +++ b/app/assets/stylesheets/framework.scss @@ -31,7 +31,6 @@ @import "framework/modal.scss"; @import "framework/nav.scss"; @import "framework/pagination.scss"; -@import "framework/progress.scss"; @import "framework/panels.scss"; @import "framework/selects.scss"; @import "framework/sidebar.scss"; diff --git a/app/assets/stylesheets/framework/progress.scss b/app/assets/stylesheets/framework/progress.scss deleted file mode 100644 index e9800bd24b5..00000000000 --- a/app/assets/stylesheets/framework/progress.scss +++ /dev/null @@ -1,5 +0,0 @@ -html.turbolinks-progress-bar::before { - background-color: $progress-color!important; - height: 2px!important; - box-shadow: 0 0 10px $progress-color, 0 0 5px $progress-color; -} diff --git a/app/helpers/javascript_helper.rb b/app/helpers/javascript_helper.rb index 0e456214d37..cd4075b340d 100644 --- a/app/helpers/javascript_helper.rb +++ b/app/helpers/javascript_helper.rb @@ -1,5 +1,5 @@ module JavascriptHelper def page_specific_javascript_tag(js) - javascript_include_tag asset_path(js), { "data-turbolinks-track" => true } + javascript_include_tag asset_path(js) end end diff --git a/app/views/devise/shared/_omniauth_box.html.haml b/app/views/devise/shared/_omniauth_box.html.haml index e87a16a5157..f92f89e73ff 100644 --- a/app/views/devise/shared/_omniauth_box.html.haml +++ b/app/views/devise/shared/_omniauth_box.html.haml @@ -6,4 +6,4 @@ - providers.each do |provider| %span.light - has_icon = provider_has_icon?(provider) - = link_to provider_image_tag(provider), omniauth_authorize_path(:user, provider), method: :post, class: (has_icon ? 'oauth-image-link' : 'btn'), "data-no-turbolink" => "true" + = link_to provider_image_tag(provider), omniauth_authorize_path(:user, provider), method: :post, class: (has_icon ? 'oauth-image-link' : 'btn') diff --git a/app/views/import/bitbucket/status.html.haml b/app/views/import/bitbucket/status.html.haml index 7f1b9ee7141..e18bd47798b 100644 --- a/app/views/import/bitbucket/status.html.haml +++ b/app/views/import/bitbucket/status.html.haml @@ -82,7 +82,7 @@ rather than Git. Please convert = link_to 'them to Git,', 'https://www.atlassian.com/git/tutorials/migrating-overview' and go through the - = link_to 'import flow', status_import_bitbucket_path, 'data-no-turbolink' => 'true' + = link_to 'import flow', status_import_bitbucket_path again. .js-importer-status{ data: { jobs_import_path: "#{jobs_import_bitbucket_path}", import_path: "#{import_bitbucket_path}" } } diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index 3096f0ee19e..703c1009d5f 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -33,6 +33,8 @@ - if content_for?(:page_specific_javascripts) = yield :page_specific_javascripts + = yield :scripts_body_top + = csrf_meta_tags - unless browser.safari? diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 935517d4913..248d439cd05 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -4,9 +4,6 @@ %body{ class: "#{user_application_theme}", data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}" } } = Gon::Base.render_data - -# Ideally this would be inside the head, but turbolinks only evaluates page-specific JS in the body. - = yield :scripts_body_top - = render "layouts/header/default", title: header_title = render 'layouts/page', sidebar: sidebar, nav: nav diff --git a/app/views/profiles/accounts/show.html.haml b/app/views/profiles/accounts/show.html.haml index 14b330d16ad..a4f4079d556 100644 --- a/app/views/profiles/accounts/show.html.haml +++ b/app/views/profiles/accounts/show.html.haml @@ -82,7 +82,7 @@ = link_to unlink_profile_account_path(provider: provider), method: :delete, class: 'provider-btn' do Disconnect - else - = link_to omniauth_authorize_path(:user, provider), method: :post, class: 'provider-btn not-active', "data-no-turbolink" => "true" do + = link_to omniauth_authorize_path(:user, provider), method: :post, class: 'provider-btn not-active' do Connect %hr - if current_user.can_change_username? diff --git a/app/views/projects/merge_requests/_show.html.haml b/app/views/projects/merge_requests/_show.html.haml index 9585a9a3ad4..b38bd32745b 100644 --- a/app/views/projects/merge_requests/_show.html.haml +++ b/app/views/projects/merge_requests/_show.html.haml @@ -108,10 +108,10 @@ = render "projects/commit/change", type: 'cherry-pick', commit: @merge_request.merge_commit, title: @merge_request.title :javascript - var merge_request; - - merge_request = new MergeRequest({ - action: "#{controller.action_name}" + $(function () { + new MergeRequest({ + action: "#{controller.action_name}" + }); }); var mrRefreshWidgetUrl = "#{mr_widget_refresh_url(@merge_request)}"; diff --git a/app/views/projects/new.html.haml b/app/views/projects/new.html.haml index 064e92b15eb..cd685f7d0eb 100644 --- a/app/views/projects/new.html.haml +++ b/app/views/projects/new.html.haml @@ -50,7 +50,7 @@ = icon('github', text: 'GitHub') %div - if bitbucket_import_enabled? - = link_to status_import_bitbucket_path, class: "btn import_bitbucket #{'how_to_import_link' unless bitbucket_import_configured?}", "data-no-turbolink" => "true" do + = link_to status_import_bitbucket_path, class: "btn import_bitbucket #{'how_to_import_link' unless bitbucket_import_configured?}" do = icon('bitbucket', text: 'Bitbucket') - unless bitbucket_import_configured? = render 'bitbucket_import_modal' diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml index b42eaabb111..55777f21040 100644 --- a/app/views/shared/issuable/_filter.html.haml +++ b/app/views/shared/issuable/_filter.html.haml @@ -91,5 +91,5 @@ new SubscriptionSelect(); $('form.filter-form').on('submit', function (event) { event.preventDefault(); - Turbolinks.visit(this.action + '&' + $(this).serialize()); + gl.utils.visitUrl(this.action + '&' + $(this).serialize()); }); diff --git a/changelogs/unreleased/25624-anticipate-obstacles-to-removing-turbolinks.yml b/changelogs/unreleased/25624-anticipate-obstacles-to-removing-turbolinks.yml new file mode 100644 index 00000000000..d7f950d7be9 --- /dev/null +++ b/changelogs/unreleased/25624-anticipate-obstacles-to-removing-turbolinks.yml @@ -0,0 +1,4 @@ +--- +title: Remove turbolinks. +merge_request: !8570 +author: diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb index d2fa8cd39af..480906929b2 100644 --- a/features/steps/project/merge_requests.rb +++ b/features/steps/project/merge_requests.rb @@ -501,6 +501,7 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps step 'I fill in merge request search with "Fe"' do fill_in 'issuable_search', with: "Fe" + sleep 3 end step 'I click the "Target branch" dropdown' do diff --git a/spec/javascripts/behaviors/autosize_spec.js b/spec/javascripts/behaviors/autosize_spec.js index 51d911792ba..5f2c73634a8 100644 --- a/spec/javascripts/behaviors/autosize_spec.js +++ b/spec/javascripts/behaviors/autosize_spec.js @@ -15,7 +15,7 @@ }); }); return load = function() { - return $(document).trigger('page:load'); + return $(document).trigger('load'); }; }); }).call(this); diff --git a/spec/javascripts/behaviors/requires_input_spec.js b/spec/javascripts/behaviors/requires_input_spec.js index 9467056f04c..b1b1f1f437b 100644 --- a/spec/javascripts/behaviors/requires_input_spec.js +++ b/spec/javascripts/behaviors/requires_input_spec.js @@ -34,11 +34,5 @@ $('#required5').val('1').change(); return expect($('.submit')).not.toBeDisabled(); }); - return it('is called on page:load event', function() { - var spy; - spy = spyOn($.fn, 'requiresInput'); - $(document).trigger('page:load'); - return expect(spy).toHaveBeenCalled(); - }); }); }).call(this); diff --git a/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 b/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 index ea953d0f5a5..cac77cf67a0 100644 --- a/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 +++ b/spec/javascripts/bootstrap_linked_tabs_spec.js.es6 @@ -50,7 +50,6 @@ secondTab.click(); expect(historySpy).toHaveBeenCalledWith({ - turbolinks: true, url: newState, }, document.title, newState); }); diff --git a/spec/javascripts/build_spec.js.es6 b/spec/javascripts/build_spec.js.es6 index 0c556382980..d813d6b39d0 100644 --- a/spec/javascripts/build_spec.js.es6 +++ b/spec/javascripts/build_spec.js.es6 @@ -1,12 +1,11 @@ /* eslint-disable no-new */ /* global Build */ -/* global Turbolinks */ //= require lib/utils/datetime_utility +//= require lib/utils/url_utility //= require build //= require breakpoints //= require jquery.nicescroll -//= require turbolinks describe('Build', () => { const BUILD_URL = `${gl.TEST_HOST}/frontend-fixtures/builds-project/builds/1`; @@ -167,7 +166,7 @@ describe('Build', () => { }); it('reloads the page when the build is done', () => { - spyOn(Turbolinks, 'visit'); + spyOn(gl.utils, 'visitUrl'); jasmine.clock().tick(4001); const [{ success, context }] = $.ajax.calls.argsFor(1); @@ -177,7 +176,7 @@ describe('Build', () => { append: true, }); - expect(Turbolinks.visit).toHaveBeenCalledWith(BUILD_URL); + expect(gl.utils.visitUrl).toHaveBeenCalledWith(BUILD_URL); }); }); }); diff --git a/spec/javascripts/gl_dropdown_spec.js.es6 b/spec/javascripts/gl_dropdown_spec.js.es6 index 06fa64b1b4e..b8d39019183 100644 --- a/spec/javascripts/gl_dropdown_spec.js.es6 +++ b/spec/javascripts/gl_dropdown_spec.js.es6 @@ -1,11 +1,10 @@ /* eslint-disable comma-dangle, no-param-reassign, no-unused-expressions, max-len */ -/* global Turbolinks */ /*= require jquery */ /*= require gl_dropdown */ -/*= require turbolinks */ /*= require lib/utils/common_utils */ /*= require lib/utils/type_utility */ +//= require lib/utils/url_utility (() => { const NON_SELECTABLE_CLASSES = '.divider, .separator, .dropdown-header, .dropdown-menu-empty-link'; @@ -112,13 +111,13 @@ expect(this.dropdownContainerElement).toHaveClass('open'); const randomIndex = Math.floor(Math.random() * (this.projectsData.length - 1)) + 0; navigateWithKeys('down', randomIndex, () => { - spyOn(Turbolinks, 'visit').and.stub(); + spyOn(gl.utils, 'visitUrl').and.stub(); navigateWithKeys('enter', null, () => { expect(this.dropdownContainerElement).not.toHaveClass('open'); const link = $(`${ITEM_SELECTOR}:eq(${randomIndex}) a`, this.$dropdownMenuElement); expect(link).toHaveClass('is-active'); const linkedLocation = link.attr('href'); - if (linkedLocation && linkedLocation !== '#') expect(Turbolinks.visit).toHaveBeenCalledWith(linkedLocation); + if (linkedLocation && linkedLocation !== '#') expect(gl.utils.visitUrl).toHaveBeenCalledWith(linkedLocation); }); }); }); diff --git a/spec/javascripts/issuable_spec.js.es6 b/spec/javascripts/issuable_spec.js.es6 index 917a6267b92..9bea404379b 100644 --- a/spec/javascripts/issuable_spec.js.es6 +++ b/spec/javascripts/issuable_spec.js.es6 @@ -1,8 +1,7 @@ /* global Issuable */ -/* global Turbolinks */ +//= require lib/utils/url_utility //= require issuable -//= require turbolinks (() => { const BASE_URL = '/user/project/issues?scope=all&state=closed'; @@ -42,39 +41,39 @@ }); it('should contain only the default parameters', () => { - spyOn(Turbolinks, 'visit'); + spyOn(gl.utils, 'visitUrl'); Issuable.filterResults($filtersForm); - expect(Turbolinks.visit).toHaveBeenCalledWith(BASE_URL + DEFAULT_PARAMS); + expect(gl.utils.visitUrl).toHaveBeenCalledWith(BASE_URL + DEFAULT_PARAMS); }); it('should filter for the phrase "broken"', () => { - spyOn(Turbolinks, 'visit'); + spyOn(gl.utils, 'visitUrl'); updateForm({ search: 'broken' }, $filtersForm); Issuable.filterResults($filtersForm); const params = `${DEFAULT_PARAMS}&search=broken`; - expect(Turbolinks.visit).toHaveBeenCalledWith(BASE_URL + params); + expect(gl.utils.visitUrl).toHaveBeenCalledWith(BASE_URL + params); }); it('should keep query parameters after modifying filter', () => { - spyOn(Turbolinks, 'visit'); + spyOn(gl.utils, 'visitUrl'); // initial filter updateForm({ milestone_title: 'v1.0' }, $filtersForm); Issuable.filterResults($filtersForm); let params = `${DEFAULT_PARAMS}&milestone_title=v1.0`; - expect(Turbolinks.visit).toHaveBeenCalledWith(BASE_URL + params); + expect(gl.utils.visitUrl).toHaveBeenCalledWith(BASE_URL + params); // update filter updateForm({ label_name: 'Frontend' }, $filtersForm); Issuable.filterResults($filtersForm); params = `${DEFAULT_PARAMS}&milestone_title=v1.0&label_name=Frontend`; - expect(Turbolinks.visit).toHaveBeenCalledWith(BASE_URL + params); + expect(gl.utils.visitUrl).toHaveBeenCalledWith(BASE_URL + params); }); }); }); diff --git a/spec/javascripts/merge_request_tabs_spec.js b/spec/javascripts/merge_request_tabs_spec.js index 98201fb98ed..6009f0dbfc2 100644 --- a/spec/javascripts/merge_request_tabs_spec.js +++ b/spec/javascripts/merge_request_tabs_spec.js @@ -99,7 +99,6 @@ }); newState = this.subject('commits'); expect(this.spies.history).toHaveBeenCalledWith({ - turbolinks: true, url: newState }, document.title, newState); }); diff --git a/spec/javascripts/search_autocomplete_spec.js b/spec/javascripts/search_autocomplete_spec.js index 7ac9710654f..0b48a53f4bc 100644 --- a/spec/javascripts/search_autocomplete_spec.js +++ b/spec/javascripts/search_autocomplete_spec.js @@ -6,8 +6,6 @@ /*= require lib/utils/common_utils */ /*= require lib/utils/type_utility */ /*= require fuzzaldrin-plus */ -/*= require turbolinks */ -/*= require jquery.turbolinks */ (function() { var addBodyAttributes, assertLinks, dashboardIssuesPath, dashboardMRsPath, groupIssuesPath, groupMRsPath, groupName, mockDashboardOptions, mockGroupOptions, mockProjectOptions, projectIssuesPath, projectMRsPath, projectName, userId, widget; diff --git a/spec/javascripts/smart_interval_spec.js.es6 b/spec/javascripts/smart_interval_spec.js.es6 index 39d236986b9..e695454b8f7 100644 --- a/spec/javascripts/smart_interval_spec.js.es6 +++ b/spec/javascripts/smart_interval_spec.js.es6 @@ -164,7 +164,7 @@ const interval = this.smartInterval; setTimeout(() => { - $(document).trigger('page:before-unload'); + $(document).trigger('beforeunload'); expect(interval.state.intervalId).toBeUndefined(); expect(interval.getCurrentInterval()).toBe(interval.cfg.startingInterval); done(); diff --git a/spec/javascripts/spec_helper.js b/spec/javascripts/spec_helper.js index f8e3aca29fa..a89176e9ef4 100644 --- a/spec/javascripts/spec_helper.js +++ b/spec/javascripts/spec_helper.js @@ -8,7 +8,6 @@ // everything in application, however you may get better load performance if you // require the specific files that are being used in the spec that tests them. /*= require jquery */ -/*= require jquery.turbolinks */ /*= require bootstrap */ /*= require underscore */ diff --git a/vendor/assets/javascripts/jquery.turbolinks.js b/vendor/assets/javascripts/jquery.turbolinks.js deleted file mode 100644 index fd6e95e75d5..00000000000 --- a/vendor/assets/javascripts/jquery.turbolinks.js +++ /dev/null @@ -1,49 +0,0 @@ -// Generated by CoffeeScript 1.7.1 - -/* -jQuery.Turbolinks ~ https://github.com/kossnocorp/jquery.turbolinks -jQuery plugin for drop-in fix binded events problem caused by Turbolinks - -The MIT License -Copyright (c) 2012-2013 Sasha Koss & Rico Sta. Cruz - */ - -(function() { - var $, $document; - - $ = window.jQuery || (typeof require === "function" ? require('jquery') : void 0); - - $document = $(document); - - $.turbo = { - version: '2.1.0', - isReady: false, - use: function(load, fetch) { - return $document.off('.turbo').on("" + load + ".turbo", this.onLoad).on("" + fetch + ".turbo", this.onFetch); - }, - addCallback: function(callback) { - if ($.turbo.isReady) { - callback($); - } - return $document.on('turbo:ready', function() { - return callback($); - }); - }, - onLoad: function() { - $.turbo.isReady = true; - return $document.trigger('turbo:ready'); - }, - onFetch: function() { - return $.turbo.isReady = false; - }, - register: function() { - $(this.onLoad); - return $.fn.ready = this.addCallback; - } - }; - - $.turbo.register(); - - $.turbo.use('page:load', 'page:fetch'); - -}).call(this); -- cgit v1.2.1 From f1bcf1e583274ebf4e7d25e983aa3ba803b55f2c Mon Sep 17 00:00:00 2001 From: Bryce Johnson Date: Wed, 1 Feb 2017 15:13:42 -0500 Subject: Remove turbolinks from filtered search after rebase. --- .../filtered_search/filtered_search_manager_spec.js.es6 | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6 b/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6 index a508dacf7f0..8600c90b926 100644 --- a/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6 +++ b/spec/javascripts/filtered_search/filtered_search_manager_spec.js.es6 @@ -1,6 +1,4 @@ -/* global Turbolinks */ - -//= require turbolinks +//= require lib/utils/url_utility //= require lib/utils/common_utils //= require filtered_search/filtered_search_token_keys //= require filtered_search/filtered_search_tokenizer @@ -38,7 +36,7 @@ it('should search with a single word', () => { getInput().value = 'searchTerm'; - spyOn(Turbolinks, 'visit').and.callFake((url) => { + spyOn(gl.utils, 'visitUrl').and.callFake((url) => { expect(url).toEqual(`${defaultParams}&search=searchTerm`); }); @@ -48,7 +46,7 @@ it('should search with multiple words', () => { getInput().value = 'awesome search terms'; - spyOn(Turbolinks, 'visit').and.callFake((url) => { + spyOn(gl.utils, 'visitUrl').and.callFake((url) => { expect(url).toEqual(`${defaultParams}&search=awesome+search+terms`); }); @@ -58,7 +56,7 @@ it('should search with special characters', () => { getInput().value = '~!@#$%^&*()_+{}:<>,.?/'; - spyOn(Turbolinks, 'visit').and.callFake((url) => { + spyOn(gl.utils, 'visitUrl').and.callFake((url) => { expect(url).toEqual(`${defaultParams}&search=~!%40%23%24%25%5E%26*()_%2B%7B%7D%3A%3C%3E%2C.%3F%2F`); }); -- cgit v1.2.1 From 70c4badf4e1192413fb4d8e95248533ca1e88c9d Mon Sep 17 00:00:00 2001 From: Bryce Johnson Date: Thu, 2 Feb 2017 14:06:43 -0500 Subject: Rename scripts_body_top to project_javascripts. --- app/views/layouts/_head.html.haml | 2 +- app/views/layouts/project.html.haml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index 703c1009d5f..79e96f54936 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -33,7 +33,7 @@ - if content_for?(:page_specific_javascripts) = yield :page_specific_javascripts - = yield :scripts_body_top + = yield :project_javascripts = csrf_meta_tags diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml index 277eb71ea73..f5e7ea7710d 100644 --- a/app/views/layouts/project.html.haml +++ b/app/views/layouts/project.html.haml @@ -3,7 +3,7 @@ - header_title project_title(@project) unless header_title - nav "project" -- content_for :scripts_body_top do +- content_for :project_javascripts do - project = @target_project || @project - if @project_wiki && @page - preview_markdown_path = namespace_project_wiki_preview_markdown_path(project.namespace, project, @page.slug) -- cgit v1.2.1 From e8fd6c7e66f8a37b60d9c8cf17ec601df465dc2a Mon Sep 17 00:00:00 2001 From: Oswaldo Ferreira Date: Thu, 2 Feb 2017 17:41:21 -0200 Subject: Update V3 to V4 docs --- doc/api/README.md | 1 + doc/api/v3_to_v4.md | 10 ++++++++++ 2 files changed, 11 insertions(+) create mode 100644 doc/api/v3_to_v4.md diff --git a/doc/api/README.md b/doc/api/README.md index 20f28e8d30e..b334ca46caf 100644 --- a/doc/api/README.md +++ b/doc/api/README.md @@ -49,6 +49,7 @@ following locations: - [Todos](todos.md) - [Users](users.md) - [Validate CI configuration](ci/lint.md) +- [V3 to V4](v3_to_v4.md) - [Version](version.md) ### Internal CI API diff --git a/doc/api/v3_to_v4.md b/doc/api/v3_to_v4.md new file mode 100644 index 00000000000..01de1e59fcb --- /dev/null +++ b/doc/api/v3_to_v4.md @@ -0,0 +1,10 @@ +# V3 to V4 version + +Our V4 API version is currently available as *Beta*! It means that V3 +will still be supported and remain unchanged for now, but be aware that the following +changes are in V4: + +### Changes + +- Removed `/projects/:search` (use: `/projects?search=x`) + -- cgit v1.2.1 From aa91f508369a795878b3ee95556302cdb55d9f6c Mon Sep 17 00:00:00 2001 From: Bryce Johnson Date: Thu, 2 Feb 2017 14:53:46 -0500 Subject: Find .merge-request instead of sleep in MR search spec. --- features/steps/project/merge_requests.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/features/steps/project/merge_requests.rb b/features/steps/project/merge_requests.rb index 480906929b2..9f0057cace7 100644 --- a/features/steps/project/merge_requests.rb +++ b/features/steps/project/merge_requests.rb @@ -501,7 +501,9 @@ class Spinach::Features::ProjectMergeRequests < Spinach::FeatureSteps step 'I fill in merge request search with "Fe"' do fill_in 'issuable_search', with: "Fe" - sleep 3 + page.within '.merge-requests-holder' do + find('.merge-request') + end end step 'I click the "Target branch" dropdown' do -- cgit v1.2.1 From dbcf24c268a4bb9b949a6c94d40a04fc4c56ff90 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 2 Feb 2017 14:07:33 -0600 Subject: DRY with Gitlab.config.webpack.dev_server references --- config/initializers/static_files.rb | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/config/initializers/static_files.rb b/config/initializers/static_files.rb index cb332e15c11..74aba6c5d06 100644 --- a/config/initializers/static_files.rb +++ b/config/initializers/static_files.rb @@ -15,17 +15,19 @@ if app.config.serve_static_files # If webpack-dev-server is configured, proxy webpack's public directory # instead of looking for static assets - if Gitlab.config.webpack.dev_server.enabled - dev_server = { + dev_server = Gitlab.config.webpack.dev_server + + if dev_server.enabled + settings = { enabled: true, - host: Gitlab.config.webpack.dev_server.host, - port: Gitlab.config.webpack.dev_server.port, - manifest_host: Gitlab.config.webpack.dev_server.host, - manifest_port: Gitlab.config.webpack.dev_server.port, + host: dev_server.host, + port: dev_server.port, + manifest_host: dev_server.host, + manifest_port: dev_server.port, } if Rails.env.development? - dev_server.merge!( + settings.merge!( host: Gitlab.config.gitlab.host, port: Gitlab.config.gitlab.port, https: Gitlab.config.gitlab.https, @@ -34,11 +36,11 @@ if app.config.serve_static_files Gitlab::Middleware::Static, Gitlab::Middleware::WebpackProxy, proxy_path: app.config.webpack.public_path, - proxy_host: Gitlab.config.webpack.dev_server.host, - proxy_port: Gitlab.config.webpack.dev_server.port, + proxy_host: dev_server.host, + proxy_port: dev_server.port, ) end - app.config.webpack.dev_server.merge!(dev_server) + app.config.webpack.dev_server.merge!(settings) end end -- cgit v1.2.1 From ae1d69c29a69412847b6aaa80a04b24932f751d1 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 2 Feb 2017 16:29:40 -0600 Subject: allow application.js to require other scripts which start with application* --- app/assets/javascripts/application.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index ae81eecfe6a..f3896749476 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -55,7 +55,7 @@ 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|es6)$/)); +requireAll(require.context('.', false, /^\.\/(?!application\.js).*\.(js|es6)$/)); require('vendor/fuzzaldrin-plus'); window.ES6Promise = require('vendor/es6-promise.auto'); window.ES6Promise.polyfill(); -- cgit v1.2.1 From 152b292d0b566547875a44470c76e9a43cb28a36 Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 2 Feb 2017 16:30:59 -0600 Subject: consistently use single quotes --- config/webpack.config.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/config/webpack.config.js b/config/webpack.config.js index db4ce84f376..7cd92af7d93 100644 --- a/config/webpack.config.js +++ b/config/webpack.config.js @@ -4,7 +4,7 @@ var fs = require('fs'); var path = require('path'); var webpack = require('webpack'); var StatsPlugin = require('stats-webpack-plugin'); -var CompressionPlugin = require("compression-webpack-plugin"); +var CompressionPlugin = require('compression-webpack-plugin'); var ROOT_PATH = path.resolve(__dirname, '..'); var IS_PRODUCTION = process.env.NODE_ENV === 'production'; @@ -53,10 +53,10 @@ var config = { exclude: /node_modules/, loader: 'babel-loader', query: { - // "use strict" was broken in sprockets-es6 due to sprockets concatination method. + // 'use strict' was broken in sprockets-es6 due to sprockets concatination method. // many es5 strict errors which were never caught ended up in our es6 assets as a result. // this hack is necessary until they can be fixed. - blacklist: ["useStrict"] + blacklist: ['useStrict'] } }, { -- cgit v1.2.1 From 80bd5717367ae4af63ac476244e6adee8ccefad5 Mon Sep 17 00:00:00 2001 From: Nur Rony Date: Fri, 3 Feb 2017 14:44:12 +0600 Subject: fixes flickers in avatar mention dropdown --- app/assets/stylesheets/framework/animations.scss | 21 +++++++++++++++++++++ app/assets/stylesheets/framework/markdown_area.scss | 1 + 2 files changed, 22 insertions(+) diff --git a/app/assets/stylesheets/framework/animations.scss b/app/assets/stylesheets/framework/animations.scss index 8d38fc78a19..f1ff9faef7f 100644 --- a/app/assets/stylesheets/framework/animations.scss +++ b/app/assets/stylesheets/framework/animations.scss @@ -71,6 +71,27 @@ transition: $unfoldedTransitions; } +@mixin disableAllAnimation { + /*CSS transitions*/ + -o-transition-property: none !important; + -moz-transition-property: none !important; + -ms-transition-property: none !important; + -webkit-transition-property: none !important; + transition-property: none !important; + /*CSS transforms*/ + -o-transform: none !important; + -moz-transform: none !important; + -ms-transform: none !important; + -webkit-transform: none !important; + transform: none !important; + /*CSS animations*/ + -webkit-animation: none !important; + -moz-animation: none !important; + -o-animation: none !important; + -ms-animation: none !important; + animation: none !important; +} + @function unfoldTransition ($transition) { // Default values $property: all; diff --git a/app/assets/stylesheets/framework/markdown_area.scss b/app/assets/stylesheets/framework/markdown_area.scss index 5bff694658c..d4758d90352 100644 --- a/app/assets/stylesheets/framework/markdown_area.scss +++ b/app/assets/stylesheets/framework/markdown_area.scss @@ -159,6 +159,7 @@ .cur { .avatar { border: 1px solid $white-light; + @include disableAllAnimation; } } } -- cgit v1.2.1 From 22b77948ec8743574bdd74c98888c5c91eb1bb74 Mon Sep 17 00:00:00 2001 From: Nur Rony Date: Fri, 3 Feb 2017 14:56:49 +0600 Subject: adds changelog --- .../unreleased/27602-fix-avatar-border-flicker-mention-dropdown.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 changelogs/unreleased/27602-fix-avatar-border-flicker-mention-dropdown.yml diff --git a/changelogs/unreleased/27602-fix-avatar-border-flicker-mention-dropdown.yml b/changelogs/unreleased/27602-fix-avatar-border-flicker-mention-dropdown.yml new file mode 100644 index 00000000000..a5bb37ec8a9 --- /dev/null +++ b/changelogs/unreleased/27602-fix-avatar-border-flicker-mention-dropdown.yml @@ -0,0 +1,4 @@ +--- +title: Fixes flickering of avatar border in mention dropdown +merge_request: 8950 +author: -- cgit v1.2.1 From 9bb08a7e53b22d7af8484e3921b6fe51996ca981 Mon Sep 17 00:00:00 2001 From: YarNayar Date: Tue, 31 Jan 2017 16:27:29 +0300 Subject: Adds /target_branch slash command functionality for merge requests Allows to use slash command /target_branch in merge requests notes and description. Command allows to specify target branch for current merge request. Proposed in #23619 --- app/services/slash_commands/interpret_service.rb | 12 ++++ ...ash-command-for-target-merge-request-branch.yml | 4 ++ doc/user/project/slash_commands.md | 1 + .../user_uses_slash_commands_spec.rb | 74 ++++++++++++++++++++++ .../slash_commands/interpret_service_spec.rb | 32 ++++++++++ 5 files changed, 123 insertions(+) create mode 100644 changelogs/unreleased/Add-a-shash-command-for-target-merge-request-branch.yml diff --git a/app/services/slash_commands/interpret_service.rb b/app/services/slash_commands/interpret_service.rb index 3566a8ba92f..3e0a85cf059 100644 --- a/app/services/slash_commands/interpret_service.rb +++ b/app/services/slash_commands/interpret_service.rb @@ -304,6 +304,18 @@ module SlashCommands params '@user' command :cc + desc 'Defines target branch for MR' + params '' + condition do + issuable.respond_to?(:target_branch) && + (current_user.can?(:"update_#{issuable.to_ability_name}", issuable) || + issuable.new_record?) + end + command :target_branch do |target_branch_param| + branch_name = target_branch_param.strip + @updates[:target_branch] = branch_name if project.repository.branch_names.include?(branch_name) + end + def find_label_ids(labels_param) label_ids_by_reference = extract_references(labels_param, :label).map(&:id) labels_ids_by_name = LabelsFinder.new(current_user, project_id: project.id, name: labels_param.split).execute.select(:id) diff --git a/changelogs/unreleased/Add-a-shash-command-for-target-merge-request-branch.yml b/changelogs/unreleased/Add-a-shash-command-for-target-merge-request-branch.yml new file mode 100644 index 00000000000..9fd6ea5bc52 --- /dev/null +++ b/changelogs/unreleased/Add-a-shash-command-for-target-merge-request-branch.yml @@ -0,0 +1,4 @@ +--- +title: Adds /target_branch slash command functionality for merge requests +merge_request: +author: YarNayar diff --git a/doc/user/project/slash_commands.md b/doc/user/project/slash_commands.md index a6546cffce2..a53c547e7d2 100644 --- a/doc/user/project/slash_commands.md +++ b/doc/user/project/slash_commands.md @@ -34,3 +34,4 @@ do. | `/remove_estimate` | Remove estimated time | | /spend <1h 30m | -1h 5m> | Add or substract spent time | | `/remove_time_spent` | Remove time spent | +| `/target_branch ` | Set target branch for current merge request | diff --git a/spec/features/merge_requests/user_uses_slash_commands_spec.rb b/spec/features/merge_requests/user_uses_slash_commands_spec.rb index b13674b4db9..cf56715f508 100644 --- a/spec/features/merge_requests/user_uses_slash_commands_spec.rb +++ b/spec/features/merge_requests/user_uses_slash_commands_spec.rb @@ -120,5 +120,79 @@ feature 'Merge Requests > User uses slash commands', feature: true, js: true do expect(page).not_to have_content '/due 2016-08-28' end end + + describe '/target_branch command in merge request' do + let(:another_project) { create(:project, :public) } + let(:new_url_opts) { { merge_request: { source_branch: 'feature' } } } + + before do + logout + another_project.team << [user, :master] + login_with(user) + end + + it 'changes target_branch in new merge_request' do + visit new_namespace_project_merge_request_path(another_project.namespace, another_project, new_url_opts) + fill_in "merge_request_title", with: 'My brand new feature' + fill_in "merge_request_description", with: "le feature \n/target_branch fix\nFeature description:" + click_button "Submit merge request" + + merge_request = another_project.merge_requests.first + expect(merge_request.description).to eq "le feature \nFeature description:" + expect(merge_request.target_branch).to eq 'fix' + end + + it 'does not change target branch when merge request is edited' do + new_merge_request = create(:merge_request, source_project: another_project) + + visit edit_namespace_project_merge_request_path(another_project.namespace, another_project, new_merge_request) + fill_in "merge_request_description", with: "Want to update target branch\n/target_branch fix\n" + click_button "Save changes" + + new_merge_request = another_project.merge_requests.first + expect(new_merge_request.description).to include('/target_branch') + expect(new_merge_request.target_branch).not_to eq('fix') + end + end + + describe '/target_branch command from note' do + context 'when the current user can change target branch' do + it 'changes target branch from a note' do + write_note("message start \n/target_branch merge-test\n message end.") + + expect(page).not_to have_content('/target_branch') + expect(page).to have_content('message start') + expect(page).to have_content('message end.') + + expect(merge_request.reload.target_branch).to eq 'merge-test' + end + + it 'does not fail when target branch does not exists' do + write_note('/target_branch totally_not_existing_branch') + + expect(page).not_to have_content('/target_branch') + + expect(merge_request.target_branch).to eq 'feature' + end + end + + context 'when current user can not change target branch' do + let(:guest) { create(:user) } + before do + project.team << [guest, :guest] + logout + login_with(guest) + visit namespace_project_merge_request_path(project.namespace, project, merge_request) + end + + it 'does not change target branch' do + write_note('/target_branch merge-test') + + expect(page).not_to have_content '/target_branch merge-test' + + expect(merge_request.target_branch).to eq 'feature' + end + end + end end end diff --git a/spec/services/slash_commands/interpret_service_spec.rb b/spec/services/slash_commands/interpret_service_spec.rb index 66fc8fc360b..0b0925983eb 100644 --- a/spec/services/slash_commands/interpret_service_spec.rb +++ b/spec/services/slash_commands/interpret_service_spec.rb @@ -653,5 +653,37 @@ describe SlashCommands::InterpretService, services: true do let(:issuable) { issue } end end + + context '/target_branch command' do + let(:non_empty_project) { create(:project) } + let(:another_merge_request) { create(:merge_request, author: developer, source_project: non_empty_project) } + let(:service) { described_class.new(non_empty_project, developer)} + + it 'updates target_branch if /target_branch command is executed' do + _, updates = service.execute('/target_branch merge-test', merge_request) + + expect(updates).to eq(target_branch: 'merge-test') + end + + it 'handles blanks around param' do + _, updates = service.execute('/target_branch merge-test ', merge_request) + + expect(updates).to eq(target_branch: 'merge-test') + end + + context 'ignores command with no argument' do + it_behaves_like 'empty command' do + let(:content) { '/target_branch' } + let(:issuable) { another_merge_request } + end + end + + context 'ignores non-existing target branch' do + it_behaves_like 'empty command' do + let(:content) { '/target_branch totally_non_existing_branch' } + let(:issuable) { another_merge_request } + end + end + end end end -- cgit v1.2.1 From 6e1d675de97122a966b16b7b732b2b145bbfc201 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Fri, 3 Feb 2017 12:42:11 +0100 Subject: API: Fix file downloading --- changelogs/unreleased/api-fix-files.yml | 4 ++++ lib/api/helpers.rb | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/api-fix-files.yml diff --git a/changelogs/unreleased/api-fix-files.yml b/changelogs/unreleased/api-fix-files.yml new file mode 100644 index 00000000000..8a9e29109a8 --- /dev/null +++ b/changelogs/unreleased/api-fix-files.yml @@ -0,0 +1,4 @@ +--- +title: 'API: Fix file downloading' +merge_request: Robert Schilling +author: 8267 diff --git a/lib/api/helpers.rb b/lib/api/helpers.rb index eb5b947172a..dfab60f7fa5 100644 --- a/lib/api/helpers.rb +++ b/lib/api/helpers.rb @@ -304,7 +304,7 @@ module API header['X-Sendfile'] = path body else - path + file path end end -- cgit v1.2.1 From 63dac85385c6f82db6c6465876d76f67173ebc3b Mon Sep 17 00:00:00 2001 From: blackst0ne Date: Sat, 4 Feb 2017 00:00:26 +1100 Subject: Fixed redirection from http://someproject.git to http://someproject --- app/controllers/projects/application_controller.rb | 2 +- changelogs/unreleased/git_to_html_redirection.yml | 4 ++++ spec/controllers/projects_controller_spec.rb | 11 +++++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 changelogs/unreleased/git_to_html_redirection.yml diff --git a/app/controllers/projects/application_controller.rb b/app/controllers/projects/application_controller.rb index b2ff36f6538..f9d550ffb85 100644 --- a/app/controllers/projects/application_controller.rb +++ b/app/controllers/projects/application_controller.rb @@ -18,7 +18,7 @@ class Projects::ApplicationController < ApplicationController # to # localhost/group/project # - if id =~ /\.git\Z/ + if params[:format] == 'git' redirect_to request.original_url.gsub(/\.git\/?\Z/, '') return end diff --git a/changelogs/unreleased/git_to_html_redirection.yml b/changelogs/unreleased/git_to_html_redirection.yml new file mode 100644 index 00000000000..b2959c02c07 --- /dev/null +++ b/changelogs/unreleased/git_to_html_redirection.yml @@ -0,0 +1,4 @@ +--- +title: Redirect http://someproject.git to http://someproject +merge_request: +author: blackst0ne diff --git a/spec/controllers/projects_controller_spec.rb b/spec/controllers/projects_controller_spec.rb index 9323f723bdb..e7aa8745b99 100644 --- a/spec/controllers/projects_controller_spec.rb +++ b/spec/controllers/projects_controller_spec.rb @@ -213,6 +213,17 @@ describe ProjectsController do expect(response.status).to eq 404 end end + + context "redirection from http://someproject.git" do + it 'redirects to project page (format.html)' do + project = create(:project, :public) + + get :show, namespace_id: project.namespace.path, id: project.path, format: :git + + expect(response).to have_http_status(302) + expect(response).to redirect_to(namespace_project_path) + end + end end describe "#update" do -- cgit v1.2.1 From a132b7d8ce0d962272de5932568a46b64b6dfc5e Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 24 Jan 2017 10:27:41 +0000 Subject: Add issues to boards list This removes the backlog list & instead creates a modal window that will list all issues that are not part of a list for easy adding onto the board Closes #26205 --- app/assets/javascripts/boards/boards_bundle.js.es6 | 17 ++++- .../boards/components/board_card.js.es6 | 29 +------ .../boards/components/issue_card_inner.js.es6 | 89 ++++++++++++++++++++++ .../boards/components/modal/dismiss.js.es6 | 28 +++++++ .../boards/components/modal/footer.js.es6 | 33 ++++++++ .../boards/components/modal/header.js.es6 | 31 ++++++++ .../javascripts/boards/components/modal/index.es6 | 32 ++++++++ .../boards/components/modal/list.js.es6 | 51 +++++++++++++ .../boards/components/modal/search.js.es6 | 14 ++++ .../boards/components/modal/tabs.js.es6 | 46 +++++++++++ .../boards/services/board_service.js.es6 | 10 +++ .../javascripts/boards/stores/boards_store.js.es6 | 5 ++ app/assets/stylesheets/pages/boards.scss | 52 ++++++++++++- app/controllers/projects/boards_controller.rb | 23 +++++- app/views/projects/boards/_show.html.haml | 1 + .../projects/boards/components/_card.html.haml | 25 +----- app/views/shared/issuable/_filter.html.haml | 2 + config/routes/project.rb | 2 + 18 files changed, 438 insertions(+), 52 deletions(-) create mode 100644 app/assets/javascripts/boards/components/issue_card_inner.js.es6 create mode 100644 app/assets/javascripts/boards/components/modal/dismiss.js.es6 create mode 100644 app/assets/javascripts/boards/components/modal/footer.js.es6 create mode 100644 app/assets/javascripts/boards/components/modal/header.js.es6 create mode 100644 app/assets/javascripts/boards/components/modal/index.es6 create mode 100644 app/assets/javascripts/boards/components/modal/list.js.es6 create mode 100644 app/assets/javascripts/boards/components/modal/search.js.es6 create mode 100644 app/assets/javascripts/boards/components/modal/tabs.js.es6 diff --git a/app/assets/javascripts/boards/boards_bundle.js.es6 b/app/assets/javascripts/boards/boards_bundle.js.es6 index f9766471780..d87a1de7eee 100644 --- a/app/assets/javascripts/boards/boards_bundle.js.es6 +++ b/app/assets/javascripts/boards/boards_bundle.js.es6 @@ -13,6 +13,7 @@ //= require ./components/board //= require ./components/board_sidebar //= require ./components/new_list_dropdown +//= require ./components/modal //= require ./vue_resource_interceptor $(() => { @@ -31,7 +32,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, @@ -55,12 +57,12 @@ $(() => { gl.boardService.all() .then((resp) => { resp.json().forEach((board) => { + if (board.list_type === 'backlog') return; + const list = Store.addList(board); if (list.type === 'done') { list.position = Infinity; - } else if (list.type === 'backlog') { - list.position = -1; } }); @@ -81,4 +83,13 @@ $(() => { gl.issueBoards.newListDropdownInit(); } }); + + // This element is outside the Vue app + $(document) + .off('click', '.js-show-add-issues') + .on('click', '.js-show-add-issues', (e) => { + e.preventDefault(); + + Store.modal.showAddIssuesModal = true; + }); }); diff --git a/app/assets/javascripts/boards/components/board_card.js.es6 b/app/assets/javascripts/boards/components/board_card.js.es6 index 5fc50280811..ab4226ded1d 100644 --- a/app/assets/javascripts/boards/components/board_card.js.es6 +++ b/app/assets/javascripts/boards/components/board_card.js.es6 @@ -1,4 +1,5 @@ /* eslint-disable comma-dangle, space-before-function-paren, dot-notation */ +//= require ./issue_card_inner /* global Vue */ (() => { @@ -9,6 +10,9 @@ gl.issueBoards.BoardCard = Vue.extend({ template: '#js-board-list-card', + components: { + 'issue-card-inner': gl.issueBoards.IssueCardInner, + }, props: { list: Object, issue: Object, @@ -28,31 +32,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(``); - } 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; }, diff --git a/app/assets/javascripts/boards/components/issue_card_inner.js.es6 b/app/assets/javascripts/boards/components/issue_card_inner.js.es6 new file mode 100644 index 00000000000..6a7e9419503 --- /dev/null +++ b/app/assets/javascripts/boards/components/issue_card_inner.js.es6 @@ -0,0 +1,89 @@ +/* global Vue */ +(() => { + const Store = gl.issueBoards.BoardsStore; + + window.gl = window.gl || {}; + window.gl.issueBoards = window.gl.issueBoards || {}; + + gl.issueBoards.IssueCardInner = Vue.extend({ + props: [ + 'issue', 'issueLinkBase', 'list', + ], + 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.target).tooltip('hide'); + + if (labelIndex === -1) { + Store.state.filters.label_name.push(label.title); + $('.labels-filter').prepend(``); + } 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(); + }, + }, + template: ` +
    +

    + + + {{ issue.title }} + +

    + +
    + `, + }); +})(); diff --git a/app/assets/javascripts/boards/components/modal/dismiss.js.es6 b/app/assets/javascripts/boards/components/modal/dismiss.js.es6 new file mode 100644 index 00000000000..b5027f004c6 --- /dev/null +++ b/app/assets/javascripts/boards/components/modal/dismiss.js.es6 @@ -0,0 +1,28 @@ +/* global Vue */ +(() => { + const Store = gl.issueBoards.BoardsStore; + + window.gl = window.gl || {}; + window.gl.issueBoards = window.gl.issueBoards || {}; + + gl.issueBoards.DismissModal = Vue.extend({ + data() { + return Store.modal; + }, + methods: { + toggleModal(toggle) { + this.showAddIssuesModal = toggle; + }, + }, + template: ` + + `, + }); +})(); diff --git a/app/assets/javascripts/boards/components/modal/footer.js.es6 b/app/assets/javascripts/boards/components/modal/footer.js.es6 new file mode 100644 index 00000000000..9cb48448a87 --- /dev/null +++ b/app/assets/javascripts/boards/components/modal/footer.js.es6 @@ -0,0 +1,33 @@ +/* global Vue */ +(() => { + const Store = gl.issueBoards.BoardsStore; + + window.gl = window.gl || {}; + window.gl.issueBoards = window.gl.issueBoards || {}; + + gl.issueBoards.ModalFooter = Vue.extend({ + data() { + return Store.modal; + }, + methods: { + hideModal() { + this.showAddIssuesModal = false; + }, + }, + template: ` +
    + + +
    + `, + }); +})(); diff --git a/app/assets/javascripts/boards/components/modal/header.js.es6 b/app/assets/javascripts/boards/components/modal/header.js.es6 new file mode 100644 index 00000000000..74681fa4bcf --- /dev/null +++ b/app/assets/javascripts/boards/components/modal/header.js.es6 @@ -0,0 +1,31 @@ +//= require ./dismiss +//= require ./tabs +//= require ./search +/* global Vue */ +(() => { + const Store = gl.issueBoards.BoardsStore; + + window.gl = window.gl || {}; + window.gl.issueBoards = window.gl.issueBoards || {}; + + gl.issueBoards.IssuesModalHeader = Vue.extend({ + data() { + return Store.modal; + }, + components: { + 'modal-dismiss': gl.issueBoards.DismissModal, + 'modal-tabs': gl.issueBoards.ModalTabs, + 'modal-search': gl.issueBoards.ModalSearch, + }, + template: ` +
    +

    + Add issues to board + +

    + + +
    + `, + }); +})(); diff --git a/app/assets/javascripts/boards/components/modal/index.es6 b/app/assets/javascripts/boards/components/modal/index.es6 new file mode 100644 index 00000000000..bedd7c9735a --- /dev/null +++ b/app/assets/javascripts/boards/components/modal/index.es6 @@ -0,0 +1,32 @@ +//= require ./header +//= require ./list +//= require ./footer +/* global Vue */ +(() => { + const Store = gl.issueBoards.BoardsStore; + + window.gl = window.gl || {}; + window.gl.issueBoards = window.gl.issueBoards || {}; + + gl.issueBoards.IssuesModal = Vue.extend({ + data() { + return Store.modal; + }, + components: { + 'modal-header': gl.issueBoards.IssuesModalHeader, + 'modal-list': gl.issueBoards.ModalList, + 'modal-footer': gl.issueBoards.ModalFooter, + }, + template: ` +
    +
    + + + +
    +
    + `, + }); +})(); diff --git a/app/assets/javascripts/boards/components/modal/list.js.es6 b/app/assets/javascripts/boards/components/modal/list.js.es6 new file mode 100644 index 00000000000..4e060895c5d --- /dev/null +++ b/app/assets/javascripts/boards/components/modal/list.js.es6 @@ -0,0 +1,51 @@ +/* global Vue */ +/* global ListIssue */ +(() => { + const Store = gl.issueBoards.BoardsStore; + + window.gl = window.gl || {}; + window.gl.issueBoards = window.gl.issueBoards || {}; + + gl.issueBoards.ModalList = Vue.extend({ + data() { + return Store.modal; + }, + computed: { + loading() { + return this.issues.length === 0; + }, + }, + mounted() { + gl.boardService.getBacklog() + .then((res) => { + const data = res.json(); + + data.forEach((issueObj) => { + this.issues.push(new ListIssue(issueObj)); + }); + }); + }, + components: { + 'issue-card-inner': gl.issueBoards.IssueCardInner, + }, + template: ` +
    + +
      +
    • + + +
    • +
    +
    + `, + }); +})(); diff --git a/app/assets/javascripts/boards/components/modal/search.js.es6 b/app/assets/javascripts/boards/components/modal/search.js.es6 new file mode 100644 index 00000000000..714c9240d4d --- /dev/null +++ b/app/assets/javascripts/boards/components/modal/search.js.es6 @@ -0,0 +1,14 @@ +/* global Vue */ +(() => { + window.gl = window.gl || {}; + window.gl.issueBoards = window.gl.issueBoards || {}; + + gl.issueBoards.ModalSearch = Vue.extend({ + template: ` + + `, + }); +})(); diff --git a/app/assets/javascripts/boards/components/modal/tabs.js.es6 b/app/assets/javascripts/boards/components/modal/tabs.js.es6 new file mode 100644 index 00000000000..bfdfd7e2bf5 --- /dev/null +++ b/app/assets/javascripts/boards/components/modal/tabs.js.es6 @@ -0,0 +1,46 @@ +/* global Vue */ +(() => { + const Store = gl.issueBoards.BoardsStore; + + window.gl = window.gl || {}; + window.gl.issueBoards = window.gl.issueBoards || {}; + + gl.issueBoards.ModalTabs = Vue.extend({ + data() { + return Store.modal; + }, + methods: { + changeTab(tab) { + this.activeTab = tab; + }, + }, + template: ` + + `, + }); +})(); diff --git a/app/assets/javascripts/boards/services/board_service.js.es6 b/app/assets/javascripts/boards/services/board_service.js.es6 index ea55158306b..4625b13d5f3 100644 --- a/app/assets/javascripts/boards/services/board_service.js.es6 +++ b/app/assets/javascripts/boards/services/board_service.js.es6 @@ -3,6 +3,12 @@ class BoardService { constructor (root, boardId) { + this.boards = Vue.resource(`${root}{/id}.json`, {}, { + backlog: { + method: 'GET', + url: `${root}/${boardId}/backlog.json` + } + }); this.lists = Vue.resource(`${root}/${boardId}/lists{/id}`, {}, { generate: { method: 'POST', @@ -65,6 +71,10 @@ class BoardService { issue }); } + + getBacklog() { + return this.boards.backlog(); + } } window.BoardService = BoardService; diff --git a/app/assets/javascripts/boards/stores/boards_store.js.es6 b/app/assets/javascripts/boards/stores/boards_store.js.es6 index cdf1b09c0a4..57de80e448c 100644 --- a/app/assets/javascripts/boards/stores/boards_store.js.es6 +++ b/app/assets/javascripts/boards/stores/boards_store.js.es6 @@ -12,6 +12,11 @@ detail: { issue: {} }, + modal: { + issues: [], + showAddIssuesModal: false, + activeTab: 'all', + }, moving: { issue: {}, list: {} diff --git a/app/assets/stylesheets/pages/boards.scss b/app/assets/stylesheets/pages/boards.scss index f2d60bff2b5..5390bad1b33 100644 --- a/app/assets/stylesheets/pages/boards.scss +++ b/app/assets/stylesheets/pages/boards.scss @@ -250,11 +250,12 @@ } .issue-boards-search { - width: 290px; + width: 395px; .form-control { display: inline-block; width: 210px; + margin-right: 10px } } @@ -354,3 +355,52 @@ padding-right: 0; } } + +.add-issues-modal { + display: flex; + align-items: center; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + background-color: rgba($black, .3); + z-index: 9999; +} + +.add-issues-container { + display: flex; + flex-direction: column; + width: 90vw; + height: 85vh; + margin-left: auto; + margin-right: auto; + padding: 25px 15px 0; + background-color: $white-light; + border-radius: $border-radius-default; + box-shadow: 0 2px 12px rgba($black, .5); +} + +.add-issues-header { + > h2 { + margin: 0; + font-size: 18px; + } + + .top-area { + margin-bottom: 10px; + } +} + +.add-issues-list { + flex: 1; + overflow-y: scroll; +} + +.add-issues-footer { + margin-top: auto; + margin-left: -15px; + margin-right: -15px; + padding-left: 15px; + padding-right: 15px; +} diff --git a/app/controllers/projects/boards_controller.rb b/app/controllers/projects/boards_controller.rb index 808affa4f98..7a2e2324323 100644 --- a/app/controllers/projects/boards_controller.rb +++ b/app/controllers/projects/boards_controller.rb @@ -1,7 +1,7 @@ class Projects::BoardsController < Projects::ApplicationController include IssuableCollections - before_action :authorize_read_board!, only: [:index, :show] + # before_action :authorize_read_board!, only: [:index, :show, :backlog] def index @boards = ::Boards::ListService.new(project, current_user).execute @@ -25,6 +25,27 @@ class Projects::BoardsController < Projects::ApplicationController end end + def backlog + board = project.boards.find(params[:id]) + + @issues = issues_collection + @issues = @issues.where.not( + LabelLink.where("label_links.target_type = 'Issue' AND label_links.target_id = issues.id") + .where(label_id: board.lists.movable.pluck(:label_id)).limit(1).arel.exists + ) + @issues = @issues.page(params[:page]) + + render json: @issues.as_json( + labels: true, + only: [:iid, :title, :confidential, :due_date], + include: { + assignee: { only: [:id, :name, :username], methods: [:avatar_url] }, + milestone: { only: [:id, :title] } + }, + user: current_user + ) + end + private def authorize_read_board! diff --git a/app/views/projects/boards/_show.html.haml b/app/views/projects/boards/_show.html.haml index 356bd50f7f3..798eace7a82 100644 --- a/app/views/projects/boards/_show.html.haml +++ b/app/views/projects/boards/_show.html.haml @@ -26,3 +26,4 @@ ":issue-link-base" => "issueLinkBase", ":key" => "_uid" } = render "projects/boards/components/sidebar" + %board-add-issues-modal diff --git a/app/views/projects/boards/components/_card.html.haml b/app/views/projects/boards/components/_card.html.haml index e4c2aff46ec..51e5d739537 100644 --- a/app/views/projects/boards/components/_card.html.haml +++ b/app/views/projects/boards/components/_card.html.haml @@ -4,25 +4,6 @@ "@mousedown" => "mouseDown", "@mousemove" => "mouseMove", "@mouseup" => "showIssue($event)" } - %h4.card-title - = icon("eye-slash", class: "confidential-icon", "v-if" => "issue.confidential") - %a{ ":href" => 'issueLinkBase + "/" + issue.id', - ":title" => "issue.title" } - {{ issue.title }} - .card-footer - %span.card-number{ "v-if" => "issue.id" } - = precede '#' do - {{ issue.id }} - %a.has-tooltip{ ":href" => "\"#{root_path}\" + issue.assignee.username", - ":title" => '"Assigned to " + issue.assignee.name', - "v-if" => "issue.assignee", - data: { container: 'body' } } - %img.avatar.avatar-inline.s20{ ":src" => "issue.assignee.avatar", width: 20, height: 20, alt: "Avatar" } - %button.label.color-label.has-tooltip{ "v-for" => "label in issue.labels", - type: "button", - "v-if" => "(!list.label || label.id !== list.label.id)", - "@click" => "filterByLabel(label, $event)", - ":style" => "{ backgroundColor: label.color, color: label.textColor }", - ":title" => "label.description", - data: { container: 'body' } } - {{ label.title }} + %issue-card-inner{ ":list" => "list", + ":issue" => "issue", + ":issue-link-base" => "issueLinkBase" } diff --git a/app/views/shared/issuable/_filter.html.haml b/app/views/shared/issuable/_filter.html.haml index b42eaabb111..b94bdf14d5e 100644 --- a/app/views/shared/issuable/_filter.html.haml +++ b/app/views/shared/issuable/_filter.html.haml @@ -38,6 +38,8 @@ #js-boards-search.issue-boards-search %input.pull-left.form-control{ type: "search", placeholder: "Filter by name...", "v-model" => "filters.search", "debounce" => "250" } - if can?(current_user, :admin_list, @project) + %button.btn.btn-create.btn-inverted.js-show-add-issues{ type: "button" } + Add issues .dropdown.pull-right %button.btn.btn-create.js-new-board-list{ type: "button", data: { toggle: "dropdown", labels: labels_filter_path, namespace_path: @project.try(:namespace).try(:path), project_path: @project.try(:path) } } Add list diff --git a/config/routes/project.rb b/config/routes/project.rb index efe2fbc521d..5c33bb4a6ca 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -266,6 +266,8 @@ constraints(ProjectUrlConstrainer.new) do end resources :boards, only: [:index, :show] do + get :backlog, on: :member + scope module: :boards do resources :issues, only: [:update] -- cgit v1.2.1 From 94c07c21ae5cc505a5b34a71975198efe400f5a7 Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 24 Jan 2017 10:49:39 +0000 Subject: Styling fix for list --- app/assets/javascripts/boards/boards_bundle.js.es6 | 2 +- .../javascripts/boards/components/modal/index.es6 | 32 ---------------------- .../boards/components/modal/list.js.es6 | 2 +- .../javascripts/boards/components/modal/modal.es6 | 32 ++++++++++++++++++++++ app/assets/stylesheets/pages/boards.scss | 7 +++++ 5 files changed, 41 insertions(+), 34 deletions(-) delete mode 100644 app/assets/javascripts/boards/components/modal/index.es6 create mode 100644 app/assets/javascripts/boards/components/modal/modal.es6 diff --git a/app/assets/javascripts/boards/boards_bundle.js.es6 b/app/assets/javascripts/boards/boards_bundle.js.es6 index d87a1de7eee..09f5caee921 100644 --- a/app/assets/javascripts/boards/boards_bundle.js.es6 +++ b/app/assets/javascripts/boards/boards_bundle.js.es6 @@ -13,7 +13,7 @@ //= require ./components/board //= require ./components/board_sidebar //= require ./components/new_list_dropdown -//= require ./components/modal +//= require ./components/modal/modal //= require ./vue_resource_interceptor $(() => { diff --git a/app/assets/javascripts/boards/components/modal/index.es6 b/app/assets/javascripts/boards/components/modal/index.es6 deleted file mode 100644 index bedd7c9735a..00000000000 --- a/app/assets/javascripts/boards/components/modal/index.es6 +++ /dev/null @@ -1,32 +0,0 @@ -//= require ./header -//= require ./list -//= require ./footer -/* global Vue */ -(() => { - const Store = gl.issueBoards.BoardsStore; - - window.gl = window.gl || {}; - window.gl.issueBoards = window.gl.issueBoards || {}; - - gl.issueBoards.IssuesModal = Vue.extend({ - data() { - return Store.modal; - }, - components: { - 'modal-header': gl.issueBoards.IssuesModalHeader, - 'modal-list': gl.issueBoards.ModalList, - 'modal-footer': gl.issueBoards.ModalFooter, - }, - template: ` -
    -
    - - - -
    -
    - `, - }); -})(); diff --git a/app/assets/javascripts/boards/components/modal/list.js.es6 b/app/assets/javascripts/boards/components/modal/list.js.es6 index 4e060895c5d..d4b3bcc71d7 100644 --- a/app/assets/javascripts/boards/components/modal/list.js.es6 +++ b/app/assets/javascripts/boards/components/modal/list.js.es6 @@ -34,7 +34,7 @@ class="fa fa-spinner fa-spin" v-if="loading">