From c252c03401881fd7dbf7fab984285c402eb31d5f Mon Sep 17 00:00:00 2001 From: Luke Bennett Date: Sun, 9 Oct 2016 23:40:58 +0100 Subject: Added raven and raven-vue plugin, updated gon_helper with data needed for raven and created raven_config, required by application.js Added is_production to define sentry environment Removed as much jQuery as possible Added public_sentry_dsn application_settings helper method Use URI module instead of regex for public dsn Removed raven-vue and load raven on if sentry is enabled Add load_script spec added raven_config spec added class_spec_helper and tests added sentry_helper spec added feature spec --- app/assets/javascripts/application.js | 1 + .../javascripts/lib/utils/load_script.js.es6 | 26 +++++++++ app/assets/javascripts/raven_config.js.es6 | 66 ++++++++++++++++++++++ app/helpers/sentry_helper.rb | 8 +++ 4 files changed, 101 insertions(+) create mode 100644 app/assets/javascripts/lib/utils/load_script.js.es6 create mode 100644 app/assets/javascripts/raven_config.js.es6 (limited to 'app') diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index f0615481ed2..94902e560a8 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -62,6 +62,7 @@ /*= require_directory . */ /*= require fuzzaldrin-plus */ /*= require es6-promise.auto */ +/*= require raven_config */ (function () { document.addEventListener('page:fetch', function () { diff --git a/app/assets/javascripts/lib/utils/load_script.js.es6 b/app/assets/javascripts/lib/utils/load_script.js.es6 new file mode 100644 index 00000000000..351d96530ed --- /dev/null +++ b/app/assets/javascripts/lib/utils/load_script.js.es6 @@ -0,0 +1,26 @@ +(() => { + const global = window.gl || (window.gl = {}); + + class LoadScript { + static load(source, id = '') { + if (!source) return Promise.reject('source url must be defined'); + if (id && document.querySelector(`#${id}`)) return Promise.reject('script id already exists'); + return new Promise((resolve, reject) => this.appendScript(source, id, resolve, reject)); + } + + static appendScript(source, id, resolve, reject) { + const scriptElement = document.createElement('script'); + scriptElement.type = 'text/javascript'; + if (id) scriptElement.id = id; + scriptElement.onload = resolve; + scriptElement.onerror = reject; + scriptElement.src = source; + + document.body.appendChild(scriptElement); + } + } + + global.LoadScript = LoadScript; + + return global.LoadScript; +})(); diff --git a/app/assets/javascripts/raven_config.js.es6 b/app/assets/javascripts/raven_config.js.es6 new file mode 100644 index 00000000000..e15eeb9f9cd --- /dev/null +++ b/app/assets/javascripts/raven_config.js.es6 @@ -0,0 +1,66 @@ +/* global Raven */ + +/*= require lib/utils/load_script */ + +(() => { + const global = window.gl || (window.gl = {}); + + class RavenConfig { + static init(options = {}) { + this.options = options; + if (!this.options.sentryDsn || !this.options.ravenAssetUrl) return Promise.reject('sentry dsn and raven asset url is required'); + return global.LoadScript.load(this.options.ravenAssetUrl, 'raven-js') + .then(() => { + this.configure(); + this.bindRavenErrors(); + if (this.options.currentUserId) this.setUser(); + }); + } + + static configure() { + Raven.config(this.options.sentryDsn, { + whitelistUrls: this.options.whitelistUrls, + environment: this.options.isProduction ? 'production' : 'development', + }).install(); + } + + static setUser() { + Raven.setUserContext({ + id: this.options.currentUserId, + }); + } + + static bindRavenErrors() { + $(document).on('ajaxError.raven', this.handleRavenErrors); + } + + static handleRavenErrors(event, req, config, err) { + const error = err || req.statusText; + Raven.captureMessage(error, { + extra: { + type: config.type, + url: config.url, + data: config.data, + status: req.status, + response: req.responseText.substring(0, 100), + error, + event, + }, + }); + } + } + + global.RavenConfig = RavenConfig; + + document.addEventListener('DOMContentLoaded', () => { + if (!window.gon) return; + + global.RavenConfig.init({ + sentryDsn: gon.sentry_dsn, + ravenAssetUrl: gon.raven_asset_url, + currentUserId: gon.current_user_id, + whitelistUrls: [gon.gitlab_url], + isProduction: gon.is_production, + }).catch($.noop); + }); +})(); diff --git a/app/helpers/sentry_helper.rb b/app/helpers/sentry_helper.rb index 3d255df66a0..19de38ac52d 100644 --- a/app/helpers/sentry_helper.rb +++ b/app/helpers/sentry_helper.rb @@ -6,4 +6,12 @@ module SentryHelper def sentry_context Gitlab::Sentry.context(current_user) end + + def sentry_dsn_public + sentry_dsn = ApplicationSetting.current.sentry_dsn + return unless sentry_dsn + uri = URI.parse(sentry_dsn) + uri.password = nil + uri.to_s + end end -- cgit v1.2.1 From e0dc73527a478188cfa28b456b64798639aa73c9 Mon Sep 17 00:00:00 2001 From: Jarka Kadlecova Date: Fri, 24 Mar 2017 11:11:36 +0100 Subject: Project deploy keys json end point --- app/controllers/projects/deploy_keys_controller.rb | 9 +++++++-- app/presenters/projects/settings/deploy_keys_presenter.rb | 11 +++++++++++ app/serializers/deploy_key_entity.rb | 12 ++++++++++++ app/serializers/deploy_key_serializer.rb | 3 +++ app/serializers/project_entity.rb | 12 ++++++++++++ 5 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 app/serializers/deploy_key_entity.rb create mode 100644 app/serializers/deploy_key_serializer.rb create mode 100644 app/serializers/project_entity.rb (limited to 'app') diff --git a/app/controllers/projects/deploy_keys_controller.rb b/app/controllers/projects/deploy_keys_controller.rb index d0c44e297e3..a47e15a192b 100644 --- a/app/controllers/projects/deploy_keys_controller.rb +++ b/app/controllers/projects/deploy_keys_controller.rb @@ -8,7 +8,12 @@ class Projects::DeployKeysController < Projects::ApplicationController layout "project_settings" def index - redirect_to_repository_settings(@project) + respond_to do |format| + format.html { redirect_to_repository_settings(@project) } + format.json do + render json: Projects::Settings::DeployKeysPresenter.new(@project, current_user: current_user).as_json + end + end end def new @@ -19,7 +24,7 @@ class Projects::DeployKeysController < Projects::ApplicationController @key = DeployKey.new(deploy_key_params.merge(user: current_user)) unless @key.valid? && @project.deploy_keys << @key - flash[:alert] = @key.errors.full_messages.join(', ').html_safe + flash[:alert] = @key.errors.full_messages.join(', ').html_safe end redirect_to_repository_settings(@project) end diff --git a/app/presenters/projects/settings/deploy_keys_presenter.rb b/app/presenters/projects/settings/deploy_keys_presenter.rb index 86ac513b3c0..070b0c35e36 100644 --- a/app/presenters/projects/settings/deploy_keys_presenter.rb +++ b/app/presenters/projects/settings/deploy_keys_presenter.rb @@ -48,6 +48,17 @@ module Projects available_public_keys.any? end + def as_json + serializer = DeployKeySerializer.new + opts = { user: current_user } + + { + enabled_keys: serializer.represent(enabled_keys, opts), + available_project_keys: serializer.represent(available_project_keys, opts), + public_keys: serializer.represent(available_public_keys, opts) + } + end + def to_partial_path 'projects/deploy_keys/index' end diff --git a/app/serializers/deploy_key_entity.rb b/app/serializers/deploy_key_entity.rb new file mode 100644 index 00000000000..cdedc2c7bd0 --- /dev/null +++ b/app/serializers/deploy_key_entity.rb @@ -0,0 +1,12 @@ +class DeployKeyEntity < Grape::Entity + expose :id + expose :user_id + expose :title + expose :fingerprint + expose :can_push + expose :created_at + expose :updated_at + expose :projects, using: ProjectEntity do |deploy_key| + deploy_key.projects.select { |project| options[:user].can?(:read_project, project) } + end +end diff --git a/app/serializers/deploy_key_serializer.rb b/app/serializers/deploy_key_serializer.rb new file mode 100644 index 00000000000..8f849eb88b7 --- /dev/null +++ b/app/serializers/deploy_key_serializer.rb @@ -0,0 +1,3 @@ +class DeployKeySerializer < BaseSerializer + entity DeployKeyEntity +end diff --git a/app/serializers/project_entity.rb b/app/serializers/project_entity.rb new file mode 100644 index 00000000000..6f8061f7530 --- /dev/null +++ b/app/serializers/project_entity.rb @@ -0,0 +1,12 @@ +class ProjectEntity < Grape::Entity + expose :id + expose :name + + expose :full_path do |project| + project.full_path + end + + expose :full_name do |project| + project.full_name + end +end -- cgit v1.2.1 From 5525db8b33bf1f76c4a8023ea4fb571d73e41b0f Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 6 Apr 2017 11:52:37 +0200 Subject: Check branch access when user triggers manual action --- app/models/ci/build.rb | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'app') diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 8431c5f228c..159b3b2e101 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -115,7 +115,17 @@ module Ci commands.present? end + def can_play?(current_user) + ::Gitlab::UserAccess + .new(current_user, project: project) + .can_push_to_branch?(ref) + end + def play(current_user) + unless can_play?(current_user) + raise Gitlab::Access::AccessDeniedError + end + # Try to queue a current build if self.enqueue self.update(user: current_user) -- cgit v1.2.1 From 3dbef510c187606ef12eb9f2aaf51f30ddc3e30d Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 6 Apr 2017 12:58:13 +0200 Subject: Expose manual action abilities from a build entity --- app/serializers/build_entity.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/serializers/build_entity.rb b/app/serializers/build_entity.rb index b804d6d0e8a..401a277dadc 100644 --- a/app/serializers/build_entity.rb +++ b/app/serializers/build_entity.rb @@ -12,7 +12,7 @@ class BuildEntity < Grape::Entity path_to(:retry_namespace_project_build, build) end - expose :play_path, if: ->(build, _) { build.playable? } do |build| + expose :play_path, if: proc { playable? } do |build| path_to(:play_namespace_project_build, build) end @@ -25,11 +25,15 @@ class BuildEntity < Grape::Entity alias_method :build, :object - def path_to(route, build) - send("#{route}_path", build.project.namespace, build.project, build) + def playable? + build.playable? && build.can_play?(request.user) end def detailed_status build.detailed_status(request.user) end + + def path_to(route, build) + send("#{route}_path", build.project.namespace, build.project, build) + end end -- cgit v1.2.1 From 6c0fc62ef5c4fa4535174a9f187b9853f0fb90ac Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 6 Apr 2017 15:19:52 +0200 Subject: Take branch access into account when stopping environment --- app/models/deployment.rb | 4 ++-- app/models/environment.rb | 6 ++++++ app/services/ci/stop_environments_service.rb | 8 +++++--- 3 files changed, 13 insertions(+), 5 deletions(-) (limited to 'app') diff --git a/app/models/deployment.rb b/app/models/deployment.rb index afad001d50f..37adfb4de73 100644 --- a/app/models/deployment.rb +++ b/app/models/deployment.rb @@ -85,8 +85,8 @@ class Deployment < ActiveRecord::Base end def stop_action - return nil unless on_stop.present? - return nil unless manual_actions + return unless on_stop.present? + return unless manual_actions @stop_action ||= manual_actions.find_by(name: on_stop) end diff --git a/app/models/environment.rb b/app/models/environment.rb index bf33010fd21..f8b9a21c08e 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -122,6 +122,12 @@ class Environment < ActiveRecord::Base available? && stop_action.present? end + def can_trigger_stop_action?(current_user) + return false unless stop_action? + + stop_action.can_play?(current_user) + end + def stop_with_action!(current_user) return unless available? diff --git a/app/services/ci/stop_environments_service.rb b/app/services/ci/stop_environments_service.rb index 42c72aba7dd..d1e341bc9b5 100644 --- a/app/services/ci/stop_environments_service.rb +++ b/app/services/ci/stop_environments_service.rb @@ -6,9 +6,10 @@ module Ci @ref = branch_name return unless has_ref? + return unless can?(current_user, :create_deployment, project) environments.each do |environment| - next unless can?(current_user, :create_deployment, project) + next unless environment.can_trigger_stop_action?(current_user) environment.stop_with_action!(current_user) end @@ -21,8 +22,9 @@ module Ci end def environments - @environments ||= - EnvironmentsFinder.new(project, current_user, ref: @ref, recently_updated: true).execute + @environments ||= EnvironmentsFinder + .new(project, current_user, ref: @ref, recently_updated: true) + .execute end end end -- cgit v1.2.1 From 3e55e0742218fe20b269dfbc4f44d3798e4b0eb6 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 6 Apr 2017 15:32:23 +0200 Subject: Check if user can trigger manual action in the UI --- app/views/projects/ci/builds/_build.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml index aeed293a724..ceec36e2440 100644 --- a/app/views/projects/ci/builds/_build.html.haml +++ b/app/views/projects/ci/builds/_build.html.haml @@ -101,7 +101,7 @@ = link_to cancel_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Cancel', class: 'btn btn-build' do = icon('remove', class: 'cred') - elsif allow_retry - - if build.playable? && !admin + - if build.playable? && !admin && build.can_play?(current_user) = link_to play_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Play', class: 'btn btn-build' do = custom_icon('icon_play') - elsif build.retryable? -- cgit v1.2.1 From 7bcca2284b09e18438e6163c6ead72e10fdd2f57 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Thu, 6 Apr 2017 17:16:19 +0200 Subject: Check branch permission in manual action entity --- app/serializers/build_action_entity.rb | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'app') diff --git a/app/serializers/build_action_entity.rb b/app/serializers/build_action_entity.rb index 184b4b7a681..3d12c64b88a 100644 --- a/app/serializers/build_action_entity.rb +++ b/app/serializers/build_action_entity.rb @@ -13,4 +13,12 @@ class BuildActionEntity < Grape::Entity end expose :playable?, as: :playable + + private + + alias_method :build, :object + + def playable? + build.playable? && build.can_play?(request.user) + end end -- cgit v1.2.1 From 703df2881bb137a79284baafe2cc12ff32ab9ff5 Mon Sep 17 00:00:00 2001 From: Jarka Kadlecova Date: Fri, 7 Apr 2017 13:34:39 +0200 Subject: expose additional values in deploy key entity --- app/serializers/deploy_key_entity.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'app') diff --git a/app/serializers/deploy_key_entity.rb b/app/serializers/deploy_key_entity.rb index cdedc2c7bd0..d75a83d0fa5 100644 --- a/app/serializers/deploy_key_entity.rb +++ b/app/serializers/deploy_key_entity.rb @@ -4,6 +4,8 @@ class DeployKeyEntity < Grape::Entity expose :title expose :fingerprint expose :can_push + expose :destroyed_when_orphaned?, as: :destroyed_when_orphaned + expose :almost_orphaned?, as: :almost_orphaned expose :created_at expose :updated_at expose :projects, using: ProjectEntity do |deploy_key| -- cgit v1.2.1 From acea881bb012cce0b59f3d5874a630b16d0caaef Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Fri, 7 Apr 2017 23:38:43 -0400 Subject: Initial balsamiq support --- app/models/blob.rb | 6 ++++++ app/views/projects/blob/_bmpr.html.haml | 5 +++++ app/views/projects/blob/balsamiq_viewer.js | 3 +++ 3 files changed, 14 insertions(+) create mode 100644 app/views/projects/blob/_bmpr.html.haml create mode 100644 app/views/projects/blob/balsamiq_viewer.js (limited to 'app') diff --git a/app/models/blob.rb b/app/models/blob.rb index 801d3442803..0c1730f6801 100644 --- a/app/models/blob.rb +++ b/app/models/blob.rb @@ -58,6 +58,10 @@ class Blob < SimpleDelegator binary? && extname.downcase.delete('.') == 'sketch' end + def balsamiq? + binary? && extname.downcase.delete('.') == 'bmpr' + end + def stl? extname.downcase.delete('.') == 'stl' end @@ -87,6 +91,8 @@ class Blob < SimpleDelegator 'sketch' elsif stl? 'stl' + elsif balsamiq? + 'bmpr' elsif text? 'text' else diff --git a/app/views/projects/blob/_bmpr.html.haml b/app/views/projects/blob/_bmpr.html.haml new file mode 100644 index 00000000000..048bdf9dcb5 --- /dev/null +++ b/app/views/projects/blob/_bmpr.html.haml @@ -0,0 +1,5 @@ +- content_for :page_specific_javascripts do + = page_specific_javascript_bundle_tag('common_vue') + = page_specific_javascript_bundle_tag('balsamiq_viewer') + +.file-content#js-balsamiq-viewer{ data: { endpoint: namespace_project_raw_path(@project.namespace, @project, @id) } } \ No newline at end of file diff --git a/app/views/projects/blob/balsamiq_viewer.js b/app/views/projects/blob/balsamiq_viewer.js new file mode 100644 index 00000000000..b60cfe165a4 --- /dev/null +++ b/app/views/projects/blob/balsamiq_viewer.js @@ -0,0 +1,3 @@ +import renderBalsamiq from './balsamiq'; + +document.addEventListener('DOMContentLoaded', renderBalsamiq); \ No newline at end of file -- cgit v1.2.1 From ef07200cd0f059a2e0493779263aa526a2ade2e3 Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Sat, 8 Apr 2017 00:18:37 -0400 Subject: Get initial sql values back from file which is database --- app/assets/javascripts/blob/balsamiq/index.js | 27 ++++++++++++++++++++++++++ app/assets/javascripts/blob/balsamiq_viewer.js | 5 +++++ app/views/projects/blob/balsamiq_viewer.js | 3 --- 3 files changed, 32 insertions(+), 3 deletions(-) create mode 100644 app/assets/javascripts/blob/balsamiq/index.js create mode 100644 app/assets/javascripts/blob/balsamiq_viewer.js delete mode 100644 app/views/projects/blob/balsamiq_viewer.js (limited to 'app') diff --git a/app/assets/javascripts/blob/balsamiq/index.js b/app/assets/javascripts/blob/balsamiq/index.js new file mode 100644 index 00000000000..04201366897 --- /dev/null +++ b/app/assets/javascripts/blob/balsamiq/index.js @@ -0,0 +1,27 @@ +import Vue from 'vue'; +import sqljs from 'sql.js'; + +export default class BalsamiqViewer { + constructor(el) { + this.el = el; + this.loadSqlFile(); + } + + + + loadSqlFile() { + var xhr = new XMLHttpRequest(); + console.log(this.el) + xhr.open('GET', this.el.dataset.endpoint, true); + xhr.responseType = 'arraybuffer'; + + xhr.onload = function(e) { + var uInt8Array = new Uint8Array(this.response); + var db = new SQL.Database(uInt8Array); + var contents = db.exec("SELECT * FROM thumbnails"); + console.log(contents) + // contents is now [{columns:['col1','col2',...], values:[[first row], [second row], ...]}] + }; + xhr.send(); + } +} \ No newline at end of file diff --git a/app/assets/javascripts/blob/balsamiq_viewer.js b/app/assets/javascripts/blob/balsamiq_viewer.js new file mode 100644 index 00000000000..b1493398099 --- /dev/null +++ b/app/assets/javascripts/blob/balsamiq_viewer.js @@ -0,0 +1,5 @@ +import BalsamiqViewer from './balsamiq'; + +document.addEventListener('DOMContentLoaded', () => { + new BalsamiqViewer(document.getElementById('js-balsamiq-viewer')); +}); \ No newline at end of file diff --git a/app/views/projects/blob/balsamiq_viewer.js b/app/views/projects/blob/balsamiq_viewer.js deleted file mode 100644 index b60cfe165a4..00000000000 --- a/app/views/projects/blob/balsamiq_viewer.js +++ /dev/null @@ -1,3 +0,0 @@ -import renderBalsamiq from './balsamiq'; - -document.addEventListener('DOMContentLoaded', renderBalsamiq); \ No newline at end of file -- cgit v1.2.1 From e1b0ed391fcbd1c622b6e3c866674b85ccd0edea Mon Sep 17 00:00:00 2001 From: Jacob Schatz Date: Sat, 8 Apr 2017 10:36:42 -0400 Subject: Show thumbnails and their titles. --- app/assets/javascripts/blob/balsamiq/index.js | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'app') diff --git a/app/assets/javascripts/blob/balsamiq/index.js b/app/assets/javascripts/blob/balsamiq/index.js index 04201366897..61f4631b423 100644 --- a/app/assets/javascripts/blob/balsamiq/index.js +++ b/app/assets/javascripts/blob/balsamiq/index.js @@ -8,19 +8,33 @@ export default class BalsamiqViewer { } - loadSqlFile() { var xhr = new XMLHttpRequest(); - console.log(this.el) + var self = this; xhr.open('GET', this.el.dataset.endpoint, true); xhr.responseType = 'arraybuffer'; xhr.onload = function(e) { + var list = document.createElement('ul'); var uInt8Array = new Uint8Array(this.response); var db = new SQL.Database(uInt8Array); var contents = db.exec("SELECT * FROM thumbnails"); - console.log(contents) - // contents is now [{columns:['col1','col2',...], values:[[first row], [second row], ...]}] + var previews = contents[0].values.map((i)=>{return JSON.parse(i[1])}); + previews.forEach((prev) => { + var li = document.createElement('li'); + var title = db.exec(`select * from resources where id = '${prev.resourceID}'`) + var template = + `
+
${JSON.parse(title[0].values[0][2]).name}
+
+ +
+
`; + li.innerHTML = template; + list.appendChild(li); + }); + list.classList += 'list-inline'; + self.el.appendChild(list); }; xhr.send(); } -- cgit v1.2.1 From 440ff838f7646ac7ea7a660280b51740ebeed70f Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Mon, 10 Apr 2017 15:48:23 +0100 Subject: Tidy balsamiq viewer and remove unused Vue --- .../javascripts/blob/balsamiq/balsamiq_viewer.js | 89 ++++++++++++++++++++++ app/assets/javascripts/blob/balsamiq/index.js | 41 ---------- app/assets/javascripts/blob/balsamiq_viewer.js | 7 +- app/views/projects/blob/_bmpr.html.haml | 3 +- 4 files changed, 94 insertions(+), 46 deletions(-) create mode 100644 app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js delete mode 100644 app/assets/javascripts/blob/balsamiq/index.js (limited to 'app') diff --git a/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js b/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js new file mode 100644 index 00000000000..e1c837cb09e --- /dev/null +++ b/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js @@ -0,0 +1,89 @@ +/* global Flash */ + +import sqljs from 'sql.js'; + +class BalsamiqViewer { + constructor(viewer) { + this.viewer = viewer; + this.endpoint = this.viewer.dataset.endpoint; + } + + loadFile() { + const xhr = new XMLHttpRequest(); + + xhr.open('GET', this.endpoint, true); + xhr.responseType = 'arraybuffer'; + + xhr.onload = this.renderFile.bind(this); + xhr.onerror = BalsamiqViewer.onError; + + xhr.send(); + } + + renderFile(loadEvent) { + const container = document.createElement('ul'); + + this.initDatabase(loadEvent.target.response); + + const previews = this.getPreviews(); + const renderedPreviews = previews.map(preview => this.renderPreview(preview, container)); + + container.innerHTML = renderedPreviews.join(''); + container.classList.add('list-inline'); + + this.viewer.appendChild(container); + } + + initDatabase(data) { + const previewBinary = new Uint8Array(data); + + this.database = new sqljs.Database(previewBinary); + } + + getPreviews() { + const thumnails = this.database.exec('SELECT * FROM thumbnails'); + + return thumnails[0].values.map(BalsamiqViewer.parsePreview); + } + + renderPreview(preview) { + const previewElement = document.createElement('li'); + + previewElement.innerHTML = this.renderTemplate(preview); + + return previewElement.outerHTML; + } + + renderTemplate(preview) { + let template = BalsamiqViewer.PREVIEW_TEMPLATE; + + const title = this.database.exec(`SELECT * FROM resources WHERE id = '${preview.resourceID}'`); + const name = JSON.parse(title[0].values[0][2]).name; + const image = preview.image; + + template = template.replace(/{{name}}/, name).replace(/{{image}}/, image); + + return template; + } + + static parsePreview(preview) { + return JSON.parse(preview[1]); + } + + static onError() { + const flash = new Flash('Balsamiq file could not be loaded.'); + + return flash; + } +} + +BalsamiqViewer.PREVIEW_TEMPLATE = ` +
+
{{name}}
+
+ +
+
+`; + +export default BalsamiqViewer; diff --git a/app/assets/javascripts/blob/balsamiq/index.js b/app/assets/javascripts/blob/balsamiq/index.js deleted file mode 100644 index 61f4631b423..00000000000 --- a/app/assets/javascripts/blob/balsamiq/index.js +++ /dev/null @@ -1,41 +0,0 @@ -import Vue from 'vue'; -import sqljs from 'sql.js'; - -export default class BalsamiqViewer { - constructor(el) { - this.el = el; - this.loadSqlFile(); - } - - - loadSqlFile() { - var xhr = new XMLHttpRequest(); - var self = this; - xhr.open('GET', this.el.dataset.endpoint, true); - xhr.responseType = 'arraybuffer'; - - xhr.onload = function(e) { - var list = document.createElement('ul'); - var uInt8Array = new Uint8Array(this.response); - var db = new SQL.Database(uInt8Array); - var contents = db.exec("SELECT * FROM thumbnails"); - var previews = contents[0].values.map((i)=>{return JSON.parse(i[1])}); - previews.forEach((prev) => { - var li = document.createElement('li'); - var title = db.exec(`select * from resources where id = '${prev.resourceID}'`) - var template = - `
-
${JSON.parse(title[0].values[0][2]).name}
-
- -
-
`; - li.innerHTML = template; - list.appendChild(li); - }); - list.classList += 'list-inline'; - self.el.appendChild(list); - }; - xhr.send(); - } -} \ No newline at end of file diff --git a/app/assets/javascripts/blob/balsamiq_viewer.js b/app/assets/javascripts/blob/balsamiq_viewer.js index b1493398099..1dacf84470f 100644 --- a/app/assets/javascripts/blob/balsamiq_viewer.js +++ b/app/assets/javascripts/blob/balsamiq_viewer.js @@ -1,5 +1,6 @@ -import BalsamiqViewer from './balsamiq'; +import BalsamiqViewer from './balsamiq/balsamiq_viewer'; document.addEventListener('DOMContentLoaded', () => { - new BalsamiqViewer(document.getElementById('js-balsamiq-viewer')); -}); \ No newline at end of file + const balsamiqViewer = new BalsamiqViewer(document.getElementById('js-balsamiq-viewer')); + balsamiqViewer.loadFile(); +}); diff --git a/app/views/projects/blob/_bmpr.html.haml b/app/views/projects/blob/_bmpr.html.haml index 048bdf9dcb5..36ec0cbcce8 100644 --- a/app/views/projects/blob/_bmpr.html.haml +++ b/app/views/projects/blob/_bmpr.html.haml @@ -1,5 +1,4 @@ - content_for :page_specific_javascripts do - = page_specific_javascript_bundle_tag('common_vue') = page_specific_javascript_bundle_tag('balsamiq_viewer') -.file-content#js-balsamiq-viewer{ data: { endpoint: namespace_project_raw_path(@project.namespace, @project, @id) } } \ No newline at end of file +.file-content#js-balsamiq-viewer{ data: { endpoint: namespace_project_raw_path(@project.namespace, @project, @id) } } -- cgit v1.2.1 From 75d3ed9a43eceda6a375e1538945a20c97925841 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Mon, 10 Apr 2017 16:44:49 +0100 Subject: Added Spinner class --- .../javascripts/blob/balsamiq/balsamiq_viewer.js | 13 +++++++--- app/assets/javascripts/spinner.js | 28 ++++++++++++++++++++++ app/assets/stylesheets/framework/files.scss | 11 +++++++++ 3 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 app/assets/javascripts/spinner.js (limited to 'app') diff --git a/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js b/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js index e1c837cb09e..0065584cec5 100644 --- a/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js +++ b/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js @@ -1,11 +1,13 @@ /* global Flash */ +import Spinner from '../../spinner'; import sqljs from 'sql.js'; class BalsamiqViewer { constructor(viewer) { this.viewer = viewer; this.endpoint = this.viewer.dataset.endpoint; + this.spinner = new Spinner(this.viewer); } loadFile() { @@ -17,10 +19,14 @@ class BalsamiqViewer { xhr.onload = this.renderFile.bind(this); xhr.onerror = BalsamiqViewer.onError; + this.spinner.start(); + xhr.send(); } renderFile(loadEvent) { + this.spinner.stop(); + const container = document.createElement('ul'); this.initDatabase(loadEvent.target.response); @@ -29,7 +35,7 @@ class BalsamiqViewer { const renderedPreviews = previews.map(preview => this.renderPreview(preview, container)); container.innerHTML = renderedPreviews.join(''); - container.classList.add('list-inline'); + container.classList.add('list-inline', 'previews'); this.viewer.appendChild(container); } @@ -41,14 +47,15 @@ class BalsamiqViewer { } getPreviews() { - const thumnails = this.database.exec('SELECT * FROM thumbnails'); + const thumbnails = this.database.exec('SELECT * FROM thumbnails'); - return thumnails[0].values.map(BalsamiqViewer.parsePreview); + return thumbnails[0].values.map(BalsamiqViewer.parsePreview); } renderPreview(preview) { const previewElement = document.createElement('li'); + previewElement.classList.add('preview'); previewElement.innerHTML = this.renderTemplate(preview); return previewElement.outerHTML; diff --git a/app/assets/javascripts/spinner.js b/app/assets/javascripts/spinner.js new file mode 100644 index 00000000000..b7bfe1a2572 --- /dev/null +++ b/app/assets/javascripts/spinner.js @@ -0,0 +1,28 @@ +class Spinner { + constructor(renderable) { + this.renderable = renderable; + + this.container = Spinner.createContainer(); + } + + start() { + this.renderable.prepend(this.container); + } + + stop() { + this.container.remove(); + } + + static createContainer() { + const container = document.createElement('div'); + container.classList.add('loading'); + + container.innerHTML = Spinner.TEMPLATE; + + return container; + } +} + +Spinner.TEMPLATE = ''; + +export default Spinner; diff --git a/app/assets/stylesheets/framework/files.scss b/app/assets/stylesheets/framework/files.scss index a5a8522739e..b8dab538fee 100644 --- a/app/assets/stylesheets/framework/files.scss +++ b/app/assets/stylesheets/framework/files.scss @@ -168,6 +168,17 @@ &.code { padding: 0; } + + .list-inline.previews { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + padding: $gl-padding; + + .preview { + flex-shrink: 0; + } + } } } -- cgit v1.2.1 From 40e2be25c74aef14a94cf9dff4e80554958fd347 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Mon, 10 Apr 2017 18:20:54 +0100 Subject: Added unit tests --- app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js b/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js index 0065584cec5..d0c161f2aad 100644 --- a/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js +++ b/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js @@ -1,7 +1,7 @@ /* global Flash */ -import Spinner from '../../spinner'; import sqljs from 'sql.js'; +import Spinner from '../../spinner'; class BalsamiqViewer { constructor(viewer) { @@ -32,7 +32,7 @@ class BalsamiqViewer { this.initDatabase(loadEvent.target.response); const previews = this.getPreviews(); - const renderedPreviews = previews.map(preview => this.renderPreview(preview, container)); + const renderedPreviews = previews.map(preview => this.renderPreview(preview)); container.innerHTML = renderedPreviews.join(''); container.classList.add('list-inline', 'previews'); @@ -68,7 +68,7 @@ class BalsamiqViewer { const name = JSON.parse(title[0].values[0][2]).name; const image = preview.image; - template = template.replace(/{{name}}/, name).replace(/{{image}}/, image); + template = template.replace(/{{name}}/g, name).replace(/{{image}}/g, image); return template; } -- cgit v1.2.1 From 897d8d547c5888bc63d3c3ecc0d0dd971d70e6c0 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Tue, 11 Apr 2017 11:28:17 +0100 Subject: Further review changes --- .../javascripts/blob/balsamiq/balsamiq_viewer.js | 28 +++++++++++++++------- 1 file changed, 19 insertions(+), 9 deletions(-) (limited to 'app') diff --git a/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js b/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js index d0c161f2aad..3885b0f43b2 100644 --- a/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js +++ b/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js @@ -1,6 +1,7 @@ /* global Flash */ import sqljs from 'sql.js'; +import _ from 'underscore'; import Spinner from '../../spinner'; class BalsamiqViewer { @@ -52,6 +53,10 @@ class BalsamiqViewer { return thumbnails[0].values.map(BalsamiqViewer.parsePreview); } + getTitle(resourceID) { + return this.database.exec(`SELECT * FROM resources WHERE id = '${resourceID}'`); + } + renderPreview(preview) { const previewElement = document.createElement('li'); @@ -62,13 +67,14 @@ class BalsamiqViewer { } renderTemplate(preview) { - let template = BalsamiqViewer.PREVIEW_TEMPLATE; - - const title = this.database.exec(`SELECT * FROM resources WHERE id = '${preview.resourceID}'`); - const name = JSON.parse(title[0].values[0][2]).name; + const title = this.getTitle(preview.resourceID); + const name = BalsamiqViewer.parseTitle(title); const image = preview.image; - template = template.replace(/{{name}}/g, name).replace(/{{image}}/g, image); + const template = BalsamiqViewer.PREVIEW_TEMPLATE({ + name, + image, + }); return template; } @@ -77,6 +83,10 @@ class BalsamiqViewer { return JSON.parse(preview[1]); } + static parseTitle(title) { + return JSON.parse(title[0].values[0][2]).name; + } + static onError() { const flash = new Flash('Balsamiq file could not be loaded.'); @@ -84,13 +94,13 @@ class BalsamiqViewer { } } -BalsamiqViewer.PREVIEW_TEMPLATE = ` +BalsamiqViewer.PREVIEW_TEMPLATE = _.template(`
-
{{name}}
+
<%- name %>
- +
-`; +`); export default BalsamiqViewer; -- cgit v1.2.1 From fbed2909091b98f614ae51c5d6503cdd40a74eb5 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Tue, 11 Apr 2017 11:42:47 +0100 Subject: Removed prepend in favour of clean and appendChild --- app/assets/javascripts/spinner.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/assets/javascripts/spinner.js b/app/assets/javascripts/spinner.js index b7bfe1a2572..6b5ac89a576 100644 --- a/app/assets/javascripts/spinner.js +++ b/app/assets/javascripts/spinner.js @@ -6,7 +6,8 @@ class Spinner { } start() { - this.renderable.prepend(this.container); + this.renderable.innerHTML = ''; + this.renderable.appendChild(this.container); } stop() { -- cgit v1.2.1 From 18751fb1356935f38bf1ff0f00350b276d77169d Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Tue, 11 Apr 2017 13:06:32 +0100 Subject: Only import template function from underscore --- app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js b/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js index 3885b0f43b2..5bcd7d5eccc 100644 --- a/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js +++ b/app/assets/javascripts/blob/balsamiq/balsamiq_viewer.js @@ -1,7 +1,7 @@ /* global Flash */ import sqljs from 'sql.js'; -import _ from 'underscore'; +import { template as _template } from 'underscore'; import Spinner from '../../spinner'; class BalsamiqViewer { @@ -94,7 +94,7 @@ class BalsamiqViewer { } } -BalsamiqViewer.PREVIEW_TEMPLATE = _.template(` +BalsamiqViewer.PREVIEW_TEMPLATE = _template(`
<%- name %>
-- cgit v1.2.1 From cf678945044f657111997a92330420a0110d03fc Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Tue, 11 Apr 2017 13:06:45 +0100 Subject: Finished feature specs --- app/views/projects/blob/_bmpr.html.haml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/views/projects/blob/_bmpr.html.haml b/app/views/projects/blob/_bmpr.html.haml index 36ec0cbcce8..573b24ae44f 100644 --- a/app/views/projects/blob/_bmpr.html.haml +++ b/app/views/projects/blob/_bmpr.html.haml @@ -1,4 +1,4 @@ - content_for :page_specific_javascripts do = page_specific_javascript_bundle_tag('balsamiq_viewer') -.file-content#js-balsamiq-viewer{ data: { endpoint: namespace_project_raw_path(@project.namespace, @project, @id) } } +.file-content.balsamiq-viewer#js-balsamiq-viewer{ data: { endpoint: namespace_project_raw_path(@project.namespace, @project, @id) } } -- cgit v1.2.1 From 04eaed8088a398aee0954935752a99ac7721bb4f Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Wed, 12 Apr 2017 08:11:12 +0100 Subject: Used underscore to template list children to utilize their simple escaped interpolation --- app/assets/javascripts/droplab/constants.js | 2 ++ app/assets/javascripts/droplab/drop_down.js | 2 +- app/assets/javascripts/droplab/utils.js | 16 ++++++++-------- app/assets/javascripts/filtered_search/dropdown_hint.js | 2 +- 4 files changed, 12 insertions(+), 10 deletions(-) (limited to 'app') diff --git a/app/assets/javascripts/droplab/constants.js b/app/assets/javascripts/droplab/constants.js index a23d914772a..34b1aee73c7 100644 --- a/app/assets/javascripts/droplab/constants.js +++ b/app/assets/javascripts/droplab/constants.js @@ -2,10 +2,12 @@ const DATA_TRIGGER = 'data-dropdown-trigger'; const DATA_DROPDOWN = 'data-dropdown'; const SELECTED_CLASS = 'droplab-item-selected'; const ACTIVE_CLASS = 'droplab-item-active'; +const TEMPLATE_REGEX = /\{\{(.+?)\}\}/g; export { DATA_TRIGGER, DATA_DROPDOWN, SELECTED_CLASS, ACTIVE_CLASS, + TEMPLATE_REGEX, }; diff --git a/app/assets/javascripts/droplab/drop_down.js b/app/assets/javascripts/droplab/drop_down.js index 9588921ebcd..084d57e2e1f 100644 --- a/app/assets/javascripts/droplab/drop_down.js +++ b/app/assets/javascripts/droplab/drop_down.js @@ -93,7 +93,7 @@ Object.assign(DropDown.prototype, { }, renderChildren: function(data) { - var html = utils.t(this.templateString, data); + var html = utils.template(this.templateString, data); var template = document.createElement('div'); template.innerHTML = html; diff --git a/app/assets/javascripts/droplab/utils.js b/app/assets/javascripts/droplab/utils.js index c149a33a1e9..4da7344604e 100644 --- a/app/assets/javascripts/droplab/utils.js +++ b/app/assets/javascripts/droplab/utils.js @@ -1,19 +1,19 @@ /* eslint-disable */ -import { DATA_TRIGGER, DATA_DROPDOWN } from './constants'; +import { template as _template } from 'underscore'; +import { DATA_TRIGGER, DATA_DROPDOWN, TEMPLATE_REGEX } from './constants'; const utils = { toCamelCase(attr) { return this.camelize(attr.split('-').slice(1).join(' ')); }, - t(s, d) { - for (const p in d) { - if (Object.prototype.hasOwnProperty.call(d, p)) { - s = s.replace(new RegExp(`{{${p}}}`, 'g'), d[p]); - } - } - return s; + template(templateString, data) { + const template = _template(templateString, { + escape: TEMPLATE_REGEX, + }); + + return template(data); }, camelize(str) { diff --git a/app/assets/javascripts/filtered_search/dropdown_hint.js b/app/assets/javascripts/filtered_search/dropdown_hint.js index 381c40c03d8..5b7b059666a 100644 --- a/app/assets/javascripts/filtered_search/dropdown_hint.js +++ b/app/assets/javascripts/filtered_search/dropdown_hint.js @@ -63,7 +63,7 @@ require('./filtered_search_dropdown'); Object.assign({ icon: `fa-${icon}`, hint, - tag: `<${tag}>`, + tag: `<${tag}>`, }, type && { type }), ); } -- cgit v1.2.1 From 0453d6d7ae72f0179d02ff5190122a86e304e1bb Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Wed, 12 Apr 2017 09:50:54 +0100 Subject: BE review changes --- app/models/blob.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/models/blob.rb b/app/models/blob.rb index 91cf171a688..82333b6f369 100644 --- a/app/models/blob.rb +++ b/app/models/blob.rb @@ -63,7 +63,7 @@ class Blob < SimpleDelegator end def balsamiq? - binary? && extname.downcase.delete('.') == 'bmpr' + binary? && extension == 'bmpr' end def stl? -- cgit v1.2.1 From b09465f38d66d7ff6074843177bcdb7d72caf07f Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 12 Apr 2017 11:26:18 +0200 Subject: Implement new rule for manual actions in policies --- app/policies/ci/build_policy.rb | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'app') diff --git a/app/policies/ci/build_policy.rb b/app/policies/ci/build_policy.rb index 8b25332b73c..0522cbdb331 100644 --- a/app/policies/ci/build_policy.rb +++ b/app/policies/ci/build_policy.rb @@ -8,6 +8,20 @@ module Ci %w[read create update admin].each do |rule| cannot! :"#{rule}_commit_status" unless can? :"#{rule}_build" end + + can! :play_build if can_play_action? + end + + private + + alias_method :build, :subject + + def can_play_action? + return false unless build.playable? + + ::Gitlab::UserAccess + .new(user, project: build.project) + .can_push_to_branch?(build.ref) end end end -- cgit v1.2.1 From 6c6bc400d1d8a96f6e443788cd0b2c14addd88e3 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 12 Apr 2017 11:46:24 +0200 Subject: Move code for playing an action to separate service --- app/models/ci/build.rb | 15 +++------------ app/policies/ci/build_policy.rb | 2 +- app/services/ci/play_build_service.rb | 17 +++++++++++++++++ 3 files changed, 21 insertions(+), 13 deletions(-) create mode 100644 app/services/ci/play_build_service.rb (limited to 'app') diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 159b3b2e101..9edc4cd96b9 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -122,18 +122,9 @@ module Ci end def play(current_user) - unless can_play?(current_user) - raise Gitlab::Access::AccessDeniedError - end - - # Try to queue a current build - if self.enqueue - self.update(user: current_user) - self - else - # Otherwise we need to create a duplicate - Ci::Build.retry(self, current_user) - end + Ci::PlayBuildService + .new(project, current_user) + .execute(self) end def cancelable? diff --git a/app/policies/ci/build_policy.rb b/app/policies/ci/build_policy.rb index 0522cbdb331..2c39d31488f 100644 --- a/app/policies/ci/build_policy.rb +++ b/app/policies/ci/build_policy.rb @@ -17,7 +17,7 @@ module Ci alias_method :build, :subject def can_play_action? - return false unless build.playable? + return false unless build.action? ::Gitlab::UserAccess .new(user, project: build.project) diff --git a/app/services/ci/play_build_service.rb b/app/services/ci/play_build_service.rb new file mode 100644 index 00000000000..c9ed45408f2 --- /dev/null +++ b/app/services/ci/play_build_service.rb @@ -0,0 +1,17 @@ +module Ci + class PlayBuildService < ::BaseService + def execute(build) + unless can?(current_user, :play_build, build) + raise Gitlab::Access::AccessDeniedError + end + + # Try to enqueue thebuild, otherwise create a duplicate. + # + if build.enqueue + build.tap { |action| action.update(user: current_user) } + else + Ci::Build.retry(build, current_user) + end + end + end +end -- cgit v1.2.1 From 7fc6b5b6ff23e2faba7f06a1362ada31f6f3436a Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 12 Apr 2017 12:19:39 +0200 Subject: Do not inherit build policy in pipeline policy --- app/policies/base_policy.rb | 4 ++++ app/policies/ci/pipeline_policy.rb | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/policies/base_policy.rb b/app/policies/base_policy.rb index 8890409d056..623424c63e0 100644 --- a/app/policies/base_policy.rb +++ b/app/policies/base_policy.rb @@ -97,6 +97,10 @@ class BasePolicy rules end + def rules + raise NotImplementedError + end + def delegate!(new_subject) @rule_set.merge(Ability.allowed(@user, new_subject)) end diff --git a/app/policies/ci/pipeline_policy.rb b/app/policies/ci/pipeline_policy.rb index 3d2eef1c50c..10aa2d3e72a 100644 --- a/app/policies/ci/pipeline_policy.rb +++ b/app/policies/ci/pipeline_policy.rb @@ -1,4 +1,7 @@ module Ci - class PipelinePolicy < BuildPolicy + class PipelinePolicy < BasePolicy + def rules + delegate! @subject.project + end end end -- cgit v1.2.1 From 2aa211fa69ffd02ba11757e06e19d34f6ca51865 Mon Sep 17 00:00:00 2001 From: Grzegorz Bizon Date: Wed, 12 Apr 2017 13:48:43 +0200 Subject: Use build policy to determine if user can play build --- app/models/ci/build.rb | 6 ------ app/models/environment.rb | 6 ------ app/serializers/build_action_entity.rb | 2 +- app/serializers/build_entity.rb | 2 +- app/services/ci/stop_environments_service.rb | 3 ++- app/views/projects/ci/builds/_build.html.haml | 2 +- 6 files changed, 5 insertions(+), 16 deletions(-) (limited to 'app') diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 9edc4cd96b9..b3acb25b9ce 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -115,12 +115,6 @@ module Ci commands.present? end - def can_play?(current_user) - ::Gitlab::UserAccess - .new(current_user, project: project) - .can_push_to_branch?(ref) - end - def play(current_user) Ci::PlayBuildService .new(project, current_user) diff --git a/app/models/environment.rb b/app/models/environment.rb index f8b9a21c08e..bf33010fd21 100644 --- a/app/models/environment.rb +++ b/app/models/environment.rb @@ -122,12 +122,6 @@ class Environment < ActiveRecord::Base available? && stop_action.present? end - def can_trigger_stop_action?(current_user) - return false unless stop_action? - - stop_action.can_play?(current_user) - end - def stop_with_action!(current_user) return unless available? diff --git a/app/serializers/build_action_entity.rb b/app/serializers/build_action_entity.rb index 3d12c64b88a..0bb7e561073 100644 --- a/app/serializers/build_action_entity.rb +++ b/app/serializers/build_action_entity.rb @@ -19,6 +19,6 @@ class BuildActionEntity < Grape::Entity alias_method :build, :object def playable? - build.playable? && build.can_play?(request.user) + can?(request.user, :play_build, build) && build.playable? end end diff --git a/app/serializers/build_entity.rb b/app/serializers/build_entity.rb index 401a277dadc..f301900c43c 100644 --- a/app/serializers/build_entity.rb +++ b/app/serializers/build_entity.rb @@ -26,7 +26,7 @@ class BuildEntity < Grape::Entity alias_method :build, :object def playable? - build.playable? && build.can_play?(request.user) + can?(request.user, :play_build, build) && build.playable? end def detailed_status diff --git a/app/services/ci/stop_environments_service.rb b/app/services/ci/stop_environments_service.rb index d1e341bc9b5..bd9735fc0ac 100644 --- a/app/services/ci/stop_environments_service.rb +++ b/app/services/ci/stop_environments_service.rb @@ -9,7 +9,8 @@ module Ci return unless can?(current_user, :create_deployment, project) environments.each do |environment| - next unless environment.can_trigger_stop_action?(current_user) + next unless environment.stop_action? + next unless can?(current_user, :play_build, environment.stop_action) environment.stop_with_action!(current_user) end diff --git a/app/views/projects/ci/builds/_build.html.haml b/app/views/projects/ci/builds/_build.html.haml index ceec36e2440..769640c4842 100644 --- a/app/views/projects/ci/builds/_build.html.haml +++ b/app/views/projects/ci/builds/_build.html.haml @@ -101,7 +101,7 @@ = link_to cancel_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Cancel', class: 'btn btn-build' do = icon('remove', class: 'cred') - elsif allow_retry - - if build.playable? && !admin && build.can_play?(current_user) + - if build.playable? && !admin && can?(current_user, :play_build, build) = link_to play_namespace_project_build_path(build.project.namespace, build.project, build, return_to: request.original_url), method: :post, title: 'Play', class: 'btn btn-build' do = custom_icon('icon_play') - elsif build.retryable? -- cgit v1.2.1 From bd86796dd0edae7e5db2bfbb887d3196498ebd49 Mon Sep 17 00:00:00 2001 From: Ruben Davila Date: Wed, 12 Apr 2017 23:23:02 -0500 Subject: Add support to change language in profile form --- app/controllers/profiles_controller.rb | 3 ++- app/views/profiles/show.html.haml | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index 987b95e89b9..57e23cea00e 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -85,7 +85,8 @@ class ProfilesController < Profiles::ApplicationController :twitter, :username, :website_url, - :organization + :organization, + :preferred_language ) end end diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index c74b3249a13..dc71a04cbf0 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -72,6 +72,9 @@ = f.label :public_email, class: "label-light" = f.select :public_email, options_for_select(@user.all_emails, selected: @user.public_email), { include_blank: 'Do not show on profile' }, class: "select2" %span.help-block This email will be displayed on your public profile. + .form-group + = f.label :preferred_language, class: "label-light" + = f.select :preferred_language, Gitlab::I18n::AVAILABLE_LANGUAGES, {}, class: "select2" .form-group = f.label :skype, class: "label-light" = f.text_field :skype, class: "form-control" -- cgit v1.2.1 From 73d0730d09b5f9a9b68f158cc72ad30c7a2b35d0 Mon Sep 17 00:00:00 2001 From: Ruben Davila Date: Thu, 13 Apr 2017 01:03:47 -0500 Subject: Set locale through controller filter --- app/controllers/application_controller.rb | 6 ++++++ app/controllers/profiles_controller.rb | 1 + app/views/profiles/show.html.haml | 3 ++- 3 files changed, 9 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index e77094fe2a8..5a3bd4040cc 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -265,4 +265,10 @@ class ApplicationController < ActionController::Base def u2f_app_id request.base_url end + + def set_locale + requested_locale = current_user&.preferred_language || request.env['HTTP_ACCEPT_LANGUAGE'] || I18n.default_locale + locale = FastGettext.set_locale(requested_locale) + I18n.locale = locale + end end diff --git a/app/controllers/profiles_controller.rb b/app/controllers/profiles_controller.rb index 57e23cea00e..0f01bf7e706 100644 --- a/app/controllers/profiles_controller.rb +++ b/app/controllers/profiles_controller.rb @@ -3,6 +3,7 @@ class ProfilesController < Profiles::ApplicationController before_action :user before_action :authorize_change_username!, only: :update_username + before_action :set_locale, only: :show skip_before_action :require_email, only: [:show, :update] def show diff --git a/app/views/profiles/show.html.haml b/app/views/profiles/show.html.haml index dc71a04cbf0..d8ef64ceb72 100644 --- a/app/views/profiles/show.html.haml +++ b/app/views/profiles/show.html.haml @@ -74,7 +74,8 @@ %span.help-block This email will be displayed on your public profile. .form-group = f.label :preferred_language, class: "label-light" - = f.select :preferred_language, Gitlab::I18n::AVAILABLE_LANGUAGES, {}, class: "select2" + = f.select :preferred_language, Gitlab::I18n::AVAILABLE_LANGUAGES.map { |lang| [_(lang[0]), lang[1]] }, + {}, class: "select2" .form-group = f.label :skype, class: "label-light" = f.text_field :skype, class: "form-control" -- cgit v1.2.1 From cfd3d0fd377c3438c6ce8bc2f20b11f86b43a785 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Tue, 4 Apr 2017 14:58:45 +0100 Subject: [ci skip] Remove loadscript class in favour of backend conditional --- app/assets/javascripts/application.js | 266 --------------------- .../javascripts/lib/utils/load_script.js.es6 | 26 -- app/assets/javascripts/raven/index.js | 10 + app/assets/javascripts/raven/raven_config.js | 46 ++++ app/assets/javascripts/raven_config.js.es6 | 66 ----- app/helpers/sentry_helper.rb | 2 + app/views/layouts/application.html.haml | 2 + app/views/layouts/devise.html.haml | 2 + app/views/layouts/devise_empty.html.haml | 2 + 9 files changed, 64 insertions(+), 358 deletions(-) delete mode 100644 app/assets/javascripts/application.js delete mode 100644 app/assets/javascripts/lib/utils/load_script.js.es6 create mode 100644 app/assets/javascripts/raven/index.js create mode 100644 app/assets/javascripts/raven/raven_config.js delete mode 100644 app/assets/javascripts/raven_config.js.es6 (limited to 'app') diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js deleted file mode 100644 index 94902e560a8..00000000000 --- a/app/assets/javascripts/application.js +++ /dev/null @@ -1,266 +0,0 @@ -/* eslint-disable func-names, space-before-function-paren, no-var, quotes, consistent-return, prefer-arrow-callback, comma-dangle, object-shorthand, no-new, max-len */ -/* global bp */ -/* global Cookies */ -/* global Flash */ -/* global ConfirmDangerModal */ -/* global AwardsHandler */ -/* global Aside */ - -// This is a manifest file that'll be compiled into including all the files listed below. -// Add new JavaScript code in separate files in this directory and they'll automatically -// be included in the compiled file accessible from http://example.com/assets/application.js -// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the -// the compiled file. -// -/*= require jquery2 */ -/*= require jquery-ui/autocomplete */ -/*= require jquery-ui/datepicker */ -/*= require jquery-ui/draggable */ -/*= require jquery-ui/effect-highlight */ -/*= require jquery-ui/sortable */ -/*= require jquery_ujs */ -/*= require jquery.endless-scroll */ -/*= require jquery.highlight */ -/*= require jquery.waitforimages */ -/*= require jquery.atwho */ -/*= require jquery.scrollTo */ -/*= require jquery.turbolinks */ -/*= require js.cookie */ -/*= require turbolinks */ -/*= require autosave */ -/*= require bootstrap/affix */ -/*= require bootstrap/alert */ -/*= require bootstrap/button */ -/*= require bootstrap/collapse */ -/*= require bootstrap/dropdown */ -/*= require bootstrap/modal */ -/*= require bootstrap/scrollspy */ -/*= require bootstrap/tab */ -/*= require bootstrap/transition */ -/*= require bootstrap/tooltip */ -/*= require bootstrap/popover */ -/*= require select2 */ -/*= require underscore */ -/*= require dropzone */ -/*= require mousetrap */ -/*= require mousetrap/pause */ -/*= require shortcuts */ -/*= require shortcuts_navigation */ -/*= require shortcuts_dashboard_navigation */ -/*= require shortcuts_issuable */ -/*= require shortcuts_network */ -/*= require jquery.nicescroll */ -/*= require date.format */ -/*= require_directory ./behaviors */ -/*= require_directory ./blob */ -/*= require_directory ./templates */ -/*= require_directory ./commit */ -/*= require_directory ./extensions */ -/*= require_directory ./lib/utils */ -/*= require_directory ./u2f */ -/*= require_directory ./droplab */ -/*= require_directory . */ -/*= require fuzzaldrin-plus */ -/*= require es6-promise.auto */ -/*= require raven_config */ - -(function () { - document.addEventListener('page:fetch', function () { - // Unbind scroll events - $(document).off('scroll'); - // Close any open tooltips - $('.has-tooltip, [data-toggle="tooltip"]').tooltip('destroy'); - }); - - window.addEventListener('hashchange', gl.utils.handleLocationHash); - window.addEventListener('load', function onLoad() { - window.removeEventListener('load', onLoad, false); - gl.utils.handleLocationHash(); - }, false); - - $(function () { - var $body = $('body'); - var $document = $(document); - var $window = $(window); - var $sidebarGutterToggle = $('.js-sidebar-toggle'); - var $flash = $('.flash-container'); - var bootstrapBreakpoint = bp.getBreakpointSize(); - var checkInitialSidebarSize; - var fitSidebarForSize; - - // Set the default path for all cookies to GitLab's root directory - Cookies.defaults.path = gon.relative_url_root || '/'; - - // `hashchange` is not triggered when link target is already in window.location - $body.on('click', 'a[href^="#"]', function() { - var href = this.getAttribute('href'); - if (href.substr(1) === gl.utils.getLocationHash()) { - setTimeout(gl.utils.handleLocationHash, 1); - } - }); - - // prevent default action for disabled buttons - $('.btn').click(function(e) { - if ($(this).hasClass('disabled')) { - e.preventDefault(); - e.stopImmediatePropagation(); - return false; - } - }); - - $('.nav-sidebar').niceScroll({ - cursoropacitymax: '0.4', - cursorcolor: '#FFF', - cursorborder: '1px solid #FFF' - }); - $('.js-select-on-focus').on('focusin', function () { - return $(this).select().one('mouseup', function (e) { - return e.preventDefault(); - }); - // Click a .js-select-on-focus field, select the contents - // Prevent a mouseup event from deselecting the input - }); - $('.remove-row').bind('ajax:success', function () { - $(this).tooltip('destroy') - .closest('li') - .fadeOut(); - }); - $('.js-remove-tr').bind('ajax:before', function () { - return $(this).hide(); - }); - $('.js-remove-tr').bind('ajax:success', function () { - return $(this).closest('tr').fadeOut(); - }); - $('select.select2').select2({ - width: 'resolve', - // Initialize select2 selects - dropdownAutoWidth: true - }); - $('.js-select2').bind('select2-close', function () { - return setTimeout((function () { - $('.select2-container-active').removeClass('select2-container-active'); - return $(':focus').blur(); - }), 1); - // Close select2 on escape - }); - // Initialize tooltips - $.fn.tooltip.Constructor.DEFAULTS.trigger = 'hover'; - $body.tooltip({ - selector: '.has-tooltip, [data-toggle="tooltip"]', - placement: function (_, el) { - return $(el).data('placement') || 'bottom'; - } - }); - $('.trigger-submit').on('change', function () { - return $(this).parents('form').submit(); - // Form submitter - }); - gl.utils.localTimeAgo($('abbr.timeago, .js-timeago'), true); - // Flash - if ($flash.length > 0) { - $flash.click(function () { - return $(this).fadeOut(); - }); - $flash.show(); - } - // Disable form buttons while a form is submitting - $body.on('ajax:complete, ajax:beforeSend, submit', 'form', function (e) { - var buttons; - buttons = $('[type="submit"]', this); - switch (e.type) { - case 'ajax:beforeSend': - case 'submit': - return buttons.disable(); - default: - return buttons.enable(); - } - }); - $(document).ajaxError(function (e, xhrObj) { - var ref = xhrObj.status; - if (xhrObj.status === 401) { - return new Flash('You need to be logged in.', 'alert'); - } else if (ref === 404 || ref === 500) { - return new Flash('Something went wrong on our end.', 'alert'); - } - }); - $('.account-box').hover(function () { - // Show/Hide the profile menu when hovering the account box - return $(this).toggleClass('hover'); - }); - $document.on('click', '.diff-content .js-show-suppressed-diff', function () { - var $container; - $container = $(this).parent(); - $container.next('table').show(); - return $container.remove(); - // Commit show suppressed diff - }); - $('.navbar-toggle').on('click', function () { - $('.header-content .title').toggle(); - $('.header-content .header-logo').toggle(); - $('.header-content .navbar-collapse').toggle(); - return $('.navbar-toggle').toggleClass('active'); - }); - // Show/hide comments on diff - $body.on('click', '.js-toggle-diff-comments', function (e) { - var $this = $(this); - var notesHolders = $this.closest('.diff-file').find('.notes_holder'); - $this.toggleClass('active'); - if ($this.hasClass('active')) { - notesHolders.show().find('.hide').show(); - } else { - notesHolders.hide(); - } - $this.trigger('blur'); - return e.preventDefault(); - }); - $document.off('click', '.js-confirm-danger'); - $document.on('click', '.js-confirm-danger', function (e) { - var btn = $(e.target); - var form = btn.closest('form'); - var text = btn.data('confirm-danger-message'); - e.preventDefault(); - return new ConfirmDangerModal(form, text); - }); - $('input[type="search"]').each(function () { - var $this = $(this); - $this.attr('value', $this.val()); - }); - $document.off('keyup', 'input[type="search"]').on('keyup', 'input[type="search"]', function () { - var $this; - $this = $(this); - return $this.attr('value', $this.val()); - }); - $document.off('breakpoint:change').on('breakpoint:change', function (e, breakpoint) { - var $gutterIcon; - if (breakpoint === 'sm' || breakpoint === 'xs') { - $gutterIcon = $sidebarGutterToggle.find('i'); - if ($gutterIcon.hasClass('fa-angle-double-right')) { - return $sidebarGutterToggle.trigger('click'); - } - } - }); - fitSidebarForSize = function () { - var oldBootstrapBreakpoint; - oldBootstrapBreakpoint = bootstrapBreakpoint; - bootstrapBreakpoint = bp.getBreakpointSize(); - if (bootstrapBreakpoint !== oldBootstrapBreakpoint) { - return $document.trigger('breakpoint:change', [bootstrapBreakpoint]); - } - }; - checkInitialSidebarSize = function () { - bootstrapBreakpoint = bp.getBreakpointSize(); - if (bootstrapBreakpoint === 'xs' || 'sm') { - return $document.trigger('breakpoint:change', [bootstrapBreakpoint]); - } - }; - $window.off('resize.app').on('resize.app', function () { - return fitSidebarForSize(); - }); - gl.awardsHandler = new AwardsHandler(); - checkInitialSidebarSize(); - new Aside(); - - // bind sidebar events - new gl.Sidebar(); - }); -}).call(this); diff --git a/app/assets/javascripts/lib/utils/load_script.js.es6 b/app/assets/javascripts/lib/utils/load_script.js.es6 deleted file mode 100644 index 351d96530ed..00000000000 --- a/app/assets/javascripts/lib/utils/load_script.js.es6 +++ /dev/null @@ -1,26 +0,0 @@ -(() => { - const global = window.gl || (window.gl = {}); - - class LoadScript { - static load(source, id = '') { - if (!source) return Promise.reject('source url must be defined'); - if (id && document.querySelector(`#${id}`)) return Promise.reject('script id already exists'); - return new Promise((resolve, reject) => this.appendScript(source, id, resolve, reject)); - } - - static appendScript(source, id, resolve, reject) { - const scriptElement = document.createElement('script'); - scriptElement.type = 'text/javascript'; - if (id) scriptElement.id = id; - scriptElement.onload = resolve; - scriptElement.onerror = reject; - scriptElement.src = source; - - document.body.appendChild(scriptElement); - } - } - - global.LoadScript = LoadScript; - - return global.LoadScript; -})(); diff --git a/app/assets/javascripts/raven/index.js b/app/assets/javascripts/raven/index.js new file mode 100644 index 00000000000..6cc81248e6b --- /dev/null +++ b/app/assets/javascripts/raven/index.js @@ -0,0 +1,10 @@ +import RavenConfig from './raven_config'; + +RavenConfig.init({ + sentryDsn: gon.sentry_dsn, + currentUserId: gon.current_user_id, + whitelistUrls: [gon.gitlab_url], + isProduction: gon.is_production, +}); + +export default RavenConfig; diff --git a/app/assets/javascripts/raven/raven_config.js b/app/assets/javascripts/raven/raven_config.js new file mode 100644 index 00000000000..5510dd2752d --- /dev/null +++ b/app/assets/javascripts/raven/raven_config.js @@ -0,0 +1,46 @@ +import Raven from 'raven-js'; + +class RavenConfig { + static init(options = {}) { + this.options = options; + + this.configure(); + this.bindRavenErrors(); + if (this.options.currentUserId) this.setUser(); + } + + static configure() { + Raven.config(this.options.sentryDsn, { + whitelistUrls: this.options.whitelistUrls, + environment: this.options.isProduction ? 'production' : 'development', + }).install(); + } + + static setUser() { + Raven.setUserContext({ + id: this.options.currentUserId, + }); + } + + static bindRavenErrors() { + $(document).on('ajaxError.raven', this.handleRavenErrors); + } + + static handleRavenErrors(event, req, config, err) { + const error = err || req.statusText; + + Raven.captureMessage(error, { + extra: { + type: config.type, + url: config.url, + data: config.data, + status: req.status, + response: req.responseText.substring(0, 100), + error, + event, + }, + }); + } +} + +export default RavenConfig; diff --git a/app/assets/javascripts/raven_config.js.es6 b/app/assets/javascripts/raven_config.js.es6 deleted file mode 100644 index e15eeb9f9cd..00000000000 --- a/app/assets/javascripts/raven_config.js.es6 +++ /dev/null @@ -1,66 +0,0 @@ -/* global Raven */ - -/*= require lib/utils/load_script */ - -(() => { - const global = window.gl || (window.gl = {}); - - class RavenConfig { - static init(options = {}) { - this.options = options; - if (!this.options.sentryDsn || !this.options.ravenAssetUrl) return Promise.reject('sentry dsn and raven asset url is required'); - return global.LoadScript.load(this.options.ravenAssetUrl, 'raven-js') - .then(() => { - this.configure(); - this.bindRavenErrors(); - if (this.options.currentUserId) this.setUser(); - }); - } - - static configure() { - Raven.config(this.options.sentryDsn, { - whitelistUrls: this.options.whitelistUrls, - environment: this.options.isProduction ? 'production' : 'development', - }).install(); - } - - static setUser() { - Raven.setUserContext({ - id: this.options.currentUserId, - }); - } - - static bindRavenErrors() { - $(document).on('ajaxError.raven', this.handleRavenErrors); - } - - static handleRavenErrors(event, req, config, err) { - const error = err || req.statusText; - Raven.captureMessage(error, { - extra: { - type: config.type, - url: config.url, - data: config.data, - status: req.status, - response: req.responseText.substring(0, 100), - error, - event, - }, - }); - } - } - - global.RavenConfig = RavenConfig; - - document.addEventListener('DOMContentLoaded', () => { - if (!window.gon) return; - - global.RavenConfig.init({ - sentryDsn: gon.sentry_dsn, - ravenAssetUrl: gon.raven_asset_url, - currentUserId: gon.current_user_id, - whitelistUrls: [gon.gitlab_url], - isProduction: gon.is_production, - }).catch($.noop); - }); -})(); diff --git a/app/helpers/sentry_helper.rb b/app/helpers/sentry_helper.rb index 19de38ac52d..4b07f71bcea 100644 --- a/app/helpers/sentry_helper.rb +++ b/app/helpers/sentry_helper.rb @@ -9,7 +9,9 @@ module SentryHelper def sentry_dsn_public sentry_dsn = ApplicationSetting.current.sentry_dsn + return unless sentry_dsn + uri = URI.parse(sentry_dsn) uri.password = nil uri.to_s diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 36543edc040..cfd9481e4b2 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -9,3 +9,5 @@ = yield :scripts_body = render "layouts/init_auto_complete" if @gfm_form + + = javascript_include_tag(*webpack_asset_paths("raven")) if sentry_enabled? diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml index 3368a9beb29..6274f6340ab 100644 --- a/app/views/layouts/devise.html.haml +++ b/app/views/layouts/devise.html.haml @@ -35,3 +35,5 @@ = link_to "Explore", explore_root_path = link_to "Help", help_path = link_to "About GitLab", "https://about.gitlab.com/" + + = javascript_include_tag(*webpack_asset_paths("raven")) if sentry_enabled? diff --git a/app/views/layouts/devise_empty.html.haml b/app/views/layouts/devise_empty.html.haml index 7466423a934..120f7299fc9 100644 --- a/app/views/layouts/devise_empty.html.haml +++ b/app/views/layouts/devise_empty.html.haml @@ -16,3 +16,5 @@ = link_to "Explore", explore_root_path = link_to "Help", help_path = link_to "About GitLab", "https://about.gitlab.com/" + + = javascript_include_tag(*webpack_asset_paths("raven")) if sentry_enabled? -- cgit v1.2.1 From 13b60eb75b99abb23f41c0d899d6e40eefa641cc Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Thu, 13 Apr 2017 17:17:41 +0100 Subject: [ci skip] Index and singleton improvements with some more unit, more to come --- app/assets/javascripts/raven/index.js | 6 ++++-- app/assets/javascripts/raven/raven_config.js | 25 ++++++++++++++----------- 2 files changed, 18 insertions(+), 13 deletions(-) (limited to 'app') diff --git a/app/assets/javascripts/raven/index.js b/app/assets/javascripts/raven/index.js index 6cc81248e6b..373f9f29c79 100644 --- a/app/assets/javascripts/raven/index.js +++ b/app/assets/javascripts/raven/index.js @@ -1,10 +1,12 @@ import RavenConfig from './raven_config'; -RavenConfig.init({ +const index = RavenConfig.init.bind(RavenConfig, { sentryDsn: gon.sentry_dsn, currentUserId: gon.current_user_id, whitelistUrls: [gon.gitlab_url], isProduction: gon.is_production, }); -export default RavenConfig; +index(); + +export default index; diff --git a/app/assets/javascripts/raven/raven_config.js b/app/assets/javascripts/raven/raven_config.js index 5510dd2752d..1157a10d96f 100644 --- a/app/assets/javascripts/raven/raven_config.js +++ b/app/assets/javascripts/raven/raven_config.js @@ -1,32 +1,35 @@ import Raven from 'raven-js'; +import $ from 'jquery'; -class RavenConfig { - static init(options = {}) { +const RavenConfig = { + init(options = {}) { this.options = options; this.configure(); this.bindRavenErrors(); if (this.options.currentUserId) this.setUser(); - } - static configure() { + return this; + }, + + configure() { Raven.config(this.options.sentryDsn, { whitelistUrls: this.options.whitelistUrls, environment: this.options.isProduction ? 'production' : 'development', }).install(); - } + }, - static setUser() { + setUser() { Raven.setUserContext({ id: this.options.currentUserId, }); - } + }, - static bindRavenErrors() { + bindRavenErrors() { $(document).on('ajaxError.raven', this.handleRavenErrors); - } + }, - static handleRavenErrors(event, req, config, err) { + handleRavenErrors(event, req, config, err) { const error = err || req.statusText; Raven.captureMessage(error, { @@ -40,7 +43,7 @@ class RavenConfig { event, }, }); - } + }, } export default RavenConfig; -- cgit v1.2.1 From 067361327bba0cb7a8b28190485699da7deb22bb Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Fri, 14 Apr 2017 21:09:16 +0100 Subject: Updated units --- app/assets/javascripts/raven/index.js | 16 ++++++++++------ app/assets/javascripts/raven/raven_config.js | 4 +--- 2 files changed, 11 insertions(+), 9 deletions(-) (limited to 'app') diff --git a/app/assets/javascripts/raven/index.js b/app/assets/javascripts/raven/index.js index 373f9f29c79..3c5656040b9 100644 --- a/app/assets/javascripts/raven/index.js +++ b/app/assets/javascripts/raven/index.js @@ -1,11 +1,15 @@ import RavenConfig from './raven_config'; -const index = RavenConfig.init.bind(RavenConfig, { - sentryDsn: gon.sentry_dsn, - currentUserId: gon.current_user_id, - whitelistUrls: [gon.gitlab_url], - isProduction: gon.is_production, -}); +const index = function index() { + RavenConfig.init({ + sentryDsn: gon.sentry_dsn, + currentUserId: gon.current_user_id, + whitelistUrls: [gon.gitlab_url], + isProduction: gon.is_production, + }); + + return RavenConfig; +}; index(); diff --git a/app/assets/javascripts/raven/raven_config.js b/app/assets/javascripts/raven/raven_config.js index 1157a10d96f..bb9be7cb196 100644 --- a/app/assets/javascripts/raven/raven_config.js +++ b/app/assets/javascripts/raven/raven_config.js @@ -8,8 +8,6 @@ const RavenConfig = { this.configure(); this.bindRavenErrors(); if (this.options.currentUserId) this.setUser(); - - return this; }, configure() { @@ -44,6 +42,6 @@ const RavenConfig = { }, }); }, -} +}; export default RavenConfig; -- cgit v1.2.1 From e22bd9650d7bebfea0909fdaf5be7dcf746b53f7 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Sat, 15 Apr 2017 03:38:59 +0100 Subject: Updated specs, added rewire, updated layouts to move conditional raven and gon to head --- app/views/layouts/_head.html.haml | 3 +++ app/views/layouts/application.html.haml | 4 ---- app/views/layouts/devise.html.haml | 3 --- app/views/layouts/devise_empty.html.haml | 3 --- 4 files changed, 3 insertions(+), 10 deletions(-) (limited to 'app') diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index f6d8bb08a64..00de3b506b4 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -28,9 +28,12 @@ = stylesheet_link_tag "application", media: "all" = stylesheet_link_tag "print", media: "print" + = Gon::Base.render_data + = javascript_include_tag(*webpack_asset_paths("runtime")) = javascript_include_tag(*webpack_asset_paths("common")) = javascript_include_tag(*webpack_asset_paths("main")) + = javascript_include_tag(*webpack_asset_paths("raven")) if sentry_enabled? - if content_for?(:page_specific_javascripts) = yield :page_specific_javascripts diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index cfd9481e4b2..4c7f0b57d16 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -2,12 +2,8 @@ %html{ lang: "en", class: "#{page_class}" } = render "layouts/head" %body{ class: @body_class, data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}" } } - = Gon::Base.render_data - = render "layouts/header/default", title: header_title = render 'layouts/page', sidebar: sidebar, nav: nav = yield :scripts_body = render "layouts/init_auto_complete" if @gfm_form - - = javascript_include_tag(*webpack_asset_paths("raven")) if sentry_enabled? diff --git a/app/views/layouts/devise.html.haml b/app/views/layouts/devise.html.haml index 6274f6340ab..52fb46eb8c9 100644 --- a/app/views/layouts/devise.html.haml +++ b/app/views/layouts/devise.html.haml @@ -3,7 +3,6 @@ = render "layouts/head" %body.ui_charcoal.login-page.application.navless{ data: { page: body_data_page } } .page-wrap - = Gon::Base.render_data = render "layouts/header/empty" = render "layouts/broadcast" .container.navless-container @@ -35,5 +34,3 @@ = link_to "Explore", explore_root_path = link_to "Help", help_path = link_to "About GitLab", "https://about.gitlab.com/" - - = javascript_include_tag(*webpack_asset_paths("raven")) if sentry_enabled? diff --git a/app/views/layouts/devise_empty.html.haml b/app/views/layouts/devise_empty.html.haml index 120f7299fc9..ed6731bde95 100644 --- a/app/views/layouts/devise_empty.html.haml +++ b/app/views/layouts/devise_empty.html.haml @@ -2,7 +2,6 @@ %html{ lang: "en" } = render "layouts/head" %body.ui_charcoal.login-page.application.navless - = Gon::Base.render_data = render "layouts/header/empty" = render "layouts/broadcast" .container.navless-container @@ -16,5 +15,3 @@ = link_to "Explore", explore_root_path = link_to "Help", help_path = link_to "About GitLab", "https://about.gitlab.com/" - - = javascript_include_tag(*webpack_asset_paths("raven")) if sentry_enabled? -- cgit v1.2.1 From 86b4f49c8c76a322d2f12f61e5a2d27d3c5c4671 Mon Sep 17 00:00:00 2001 From: "Luke \"Jared\" Bennett" Date: Sat, 15 Apr 2017 12:29:46 +0100 Subject: Removed rewire and fixed tests --- app/assets/javascripts/raven/raven_config.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/assets/javascripts/raven/raven_config.js b/app/assets/javascripts/raven/raven_config.js index bb9be7cb196..9c756a4130b 100644 --- a/app/assets/javascripts/raven/raven_config.js +++ b/app/assets/javascripts/raven/raven_config.js @@ -1,5 +1,4 @@ import Raven from 'raven-js'; -import $ from 'jquery'; const RavenConfig = { init(options = {}) { @@ -24,11 +23,12 @@ const RavenConfig = { }, bindRavenErrors() { - $(document).on('ajaxError.raven', this.handleRavenErrors); + window.$(document).on('ajaxError.raven', this.handleRavenErrors); }, handleRavenErrors(event, req, config, err) { const error = err || req.statusText; + const responseText = req.responseText || 'Unknown response text'; Raven.captureMessage(error, { extra: { @@ -36,7 +36,7 @@ const RavenConfig = { url: config.url, data: config.data, status: req.status, - response: req.responseText.substring(0, 100), + response: responseText.substring(0, 100), error, event, }, -- cgit v1.2.1 From 90ba69d224eb7ef3d91332f1b7944c68ad16affd Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Sat, 15 Apr 2017 16:07:31 +0100 Subject: Started internationalising cycyle analytics --- app/assets/javascripts/locale/de/app.js | 1 + app/assets/javascripts/locale/en/app.js | 1 + app/assets/javascripts/locale/es/app.js | 1 + app/assets/javascripts/locale/index.js | 15 +++++++++++++++ app/views/layouts/_head.html.haml | 1 + app/views/layouts/application.html.haml | 2 +- 6 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/locale/de/app.js create mode 100644 app/assets/javascripts/locale/en/app.js create mode 100644 app/assets/javascripts/locale/es/app.js create mode 100644 app/assets/javascripts/locale/index.js (limited to 'app') diff --git a/app/assets/javascripts/locale/de/app.js b/app/assets/javascripts/locale/de/app.js new file mode 100644 index 00000000000..643e82a90a0 --- /dev/null +++ b/app/assets/javascripts/locale/de/app.js @@ -0,0 +1 @@ +var locales = locales || {}; locales['de'] = {"domain":"app","locale_data":{"app":{"":{"Project-Id-Version":"gitlab 1.0.0","Report-Msgid-Bugs-To":"","PO-Revision-Date":"2017-04-12 22:37-0500","Last-Translator":"FULL NAME ","Language-Team":"German","Language":"de","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"8bit","Plural-Forms":"nplurals=2; plural=n != 1;","lang":"de","domain":"app","plural_forms":"nplurals=2; plural=n != 1;"},"Deutsch":[""],"English":[""],"Spanish":[""]}}}; \ No newline at end of file diff --git a/app/assets/javascripts/locale/en/app.js b/app/assets/javascripts/locale/en/app.js new file mode 100644 index 00000000000..9070b519ff3 --- /dev/null +++ b/app/assets/javascripts/locale/en/app.js @@ -0,0 +1 @@ +var locales = locales || {}; locales['en'] = {"domain":"app","locale_data":{"app":{"":{"Project-Id-Version":"gitlab 1.0.0","Report-Msgid-Bugs-To":"","PO-Revision-Date":"2017-04-12 22:36-0500","Last-Translator":"FULL NAME ","Language-Team":"English","Language":"en","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"8bit","Plural-Forms":"nplurals=2; plural=n != 1;","lang":"en","domain":"app","plural_forms":"nplurals=2; plural=n != 1;"},"Deutsch":[""],"English":[""],"Spanish":[""]}}}; diff --git a/app/assets/javascripts/locale/es/app.js b/app/assets/javascripts/locale/es/app.js new file mode 100644 index 00000000000..41f6ddef5b8 --- /dev/null +++ b/app/assets/javascripts/locale/es/app.js @@ -0,0 +1 @@ +var locales = locales || {}; locales['es'] = {"domain":"app","locale_data":{"app":{"":{"Project-Id-Version":"gitlab 1.0.0","Report-Msgid-Bugs-To":"","PO-Revision-Date":"2017-04-13 00:07-0500","Language-Team":"Spanish","Language":"es","MIME-Version":"1.0","Content-Type":"text/plain; charset=UTF-8","Content-Transfer-Encoding":"8bit","Plural-Forms":"nplurals=2; plural=n != 1;","Last-Translator":"","X-Generator":"Poedit 2.0.1","lang":"es","domain":"app","plural_forms":"nplurals=2; plural=n != 1;"},"Deutsch":["Alemán"],"English":["Inglés"],"Spanish":["Español"]}}}; diff --git a/app/assets/javascripts/locale/index.js b/app/assets/javascripts/locale/index.js new file mode 100644 index 00000000000..0feb9eb5d43 --- /dev/null +++ b/app/assets/javascripts/locale/index.js @@ -0,0 +1,15 @@ +import Jed from 'jed'; +import de from './de/app'; +import es from './es/app'; +import en from './en/app'; + +const locales = { + de, + es, + en, +}; + +const lang = document.querySelector('html').getAttribute('lang'); + +export { lang }; +export default new Jed(locales[lang]); diff --git a/app/views/layouts/_head.html.haml b/app/views/layouts/_head.html.haml index 19473b6ab27..7e198679489 100644 --- a/app/views/layouts/_head.html.haml +++ b/app/views/layouts/_head.html.haml @@ -31,6 +31,7 @@ = webpack_bundle_tag "runtime" = webpack_bundle_tag "common" = webpack_bundle_tag "main" + = webpack_bundle_tag "locale" - if content_for?(:page_specific_javascripts) = yield :page_specific_javascripts diff --git a/app/views/layouts/application.html.haml b/app/views/layouts/application.html.haml index 36543edc040..dc926a615c7 100644 --- a/app/views/layouts/application.html.haml +++ b/app/views/layouts/application.html.haml @@ -1,5 +1,5 @@ !!! 5 -%html{ lang: "en", class: "#{page_class}" } +%html{ lang: I18n.locale, class: "#{page_class}" } = render "layouts/head" %body{ class: @body_class, data: { page: body_data_page, project: "#{@project.path if @project}", group: "#{@group.path if @group}" } } = Gon::Base.render_data -- cgit v1.2.1 From 7963c2c25114e871eb42c0859b6d24fc37437a8a Mon Sep 17 00:00:00 2001 From: Phil Hughes Date: Tue, 18 Apr 2017 14:55:09 +0100 Subject: Added Vue filters & directives for translating --- .../components/limit_warning_component.js | 2 +- .../components/stage_code_component.js | 4 ++-- .../components/stage_issue_component.js | 4 ++-- .../components/stage_plan_component.js | 4 ++-- .../components/stage_production_component.js | 4 ++-- .../components/stage_review_component.js | 4 ++-- .../components/stage_staging_component.js | 2 +- .../components/total_time_component.js | 6 +++--- .../cycle_analytics/cycle_analytics_bundle.js | 3 +++ .../cycle_analytics/cycle_analytics_store.js | 16 +++++++++------- app/assets/javascripts/vue_shared/translate.js | 14 ++++++++++++++ .../cycle_analytics/_empty_stage.html.haml | 2 +- .../projects/cycle_analytics/_no_access.html.haml | 4 ++-- app/views/projects/cycle_analytics/show.html.haml | 22 +++++++++++----------- 14 files changed, 55 insertions(+), 36 deletions(-) create mode 100644 app/assets/javascripts/vue_shared/translate.js (limited to 'app') diff --git a/app/assets/javascripts/cycle_analytics/components/limit_warning_component.js b/app/assets/javascripts/cycle_analytics/components/limit_warning_component.js index abe48572347..a7b187a0a36 100644 --- a/app/assets/javascripts/cycle_analytics/components/limit_warning_component.js +++ b/app/assets/javascripts/cycle_analytics/components/limit_warning_component.js @@ -11,7 +11,7 @@ export default { aria-hidden="true" title="Limited to showing 50 events at most" data-placement="top"> - Showing 50 events + {{ 'Showing 50 events' | translate }} `, }; diff --git a/app/assets/javascripts/cycle_analytics/components/stage_code_component.js b/app/assets/javascripts/cycle_analytics/components/stage_code_component.js index 80bd2df6f42..f72882872cd 100644 --- a/app/assets/javascripts/cycle_analytics/components/stage_code_component.js +++ b/app/assets/javascripts/cycle_analytics/components/stage_code_component.js @@ -28,11 +28,11 @@ global.cycleAnalytics.StageCodeComponent = Vue.extend({ !{{ mergeRequest.iid }} · - Opened + {{ 'Opened' | translate }} {{ mergeRequest.createdAt }} - by + {{ 'by' | translate }} {{ mergeRequest.author.name }}
diff --git a/app/assets/javascripts/cycle_analytics/components/stage_issue_component.js b/app/assets/javascripts/cycle_analytics/components/stage_issue_component.js index 20a43798fbe..bb265c8316f 100644 --- a/app/assets/javascripts/cycle_analytics/components/stage_issue_component.js +++ b/app/assets/javascripts/cycle_analytics/components/stage_issue_component.js @@ -28,11 +28,11 @@ global.cycleAnalytics.StageIssueComponent = Vue.extend({ #{{ issue.iid }} · - Opened + {{ 'Opened' | translate }} {{ issue.createdAt }} - by + {{ 'by' | translate }} {{ issue.author.name }} diff --git a/app/assets/javascripts/cycle_analytics/components/stage_plan_component.js b/app/assets/javascripts/cycle_analytics/components/stage_plan_component.js index f33cac3da82..32b685faece 100644 --- a/app/assets/javascripts/cycle_analytics/components/stage_plan_component.js +++ b/app/assets/javascripts/cycle_analytics/components/stage_plan_component.js @@ -31,10 +31,10 @@ global.cycleAnalytics.StagePlanComponent = Vue.extend({ - First + {{ 'First' | translate }} ${iconCommit} {{ commit.shortSha }} - pushed by + {{ 'pushed by' | translate }} {{ commit.author.name }} diff --git a/app/assets/javascripts/cycle_analytics/components/stage_production_component.js b/app/assets/javascripts/cycle_analytics/components/stage_production_component.js index 657f5385374..5c9186a2e49 100644 --- a/app/assets/javascripts/cycle_analytics/components/stage_production_component.js +++ b/app/assets/javascripts/cycle_analytics/components/stage_production_component.js @@ -28,11 +28,11 @@ global.cycleAnalytics.StageProductionComponent = Vue.extend({ #{{ issue.iid }} · - Opened + {{ 'Opened' | translate }} {{ issue.createdAt }} - by + {{ 'by' | translate }} {{ issue.author.name }} diff --git a/app/assets/javascripts/cycle_analytics/components/stage_review_component.js b/app/assets/javascripts/cycle_analytics/components/stage_review_component.js index 8a801300647..a047573548d 100644 --- a/app/assets/javascripts/cycle_analytics/components/stage_review_component.js +++ b/app/assets/javascripts/cycle_analytics/components/stage_review_component.js @@ -28,11 +28,11 @@ global.cycleAnalytics.StageReviewComponent = Vue.extend({ !{{ mergeRequest.iid }} · - Opened + {{ 'Opened' | translate }} {{ mergeRequest.createdAt }} - by + {{ 'by' | translate }} {{ mergeRequest.author.name }}