From a1b3cd40647e8f7768b6db0bc64179e60f5d5937 Mon Sep 17 00:00:00 2001 From: Mircea Danila Dumitrescu Date: Mon, 2 Oct 2017 20:32:36 +0000 Subject: namespace should be lowercased in kubernetes. This is also true for the scenario where the namespace is generated from the project group-name. --- app/models/project_services/kubernetes_service.rb | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/models/project_services/kubernetes_service.rb b/app/models/project_services/kubernetes_service.rb index 8ba07173c74..45a544e3674 100644 --- a/app/models/project_services/kubernetes_service.rb +++ b/app/models/project_services/kubernetes_service.rb @@ -153,7 +153,17 @@ class KubernetesService < DeploymentService end def default_namespace - "#{project.path}-#{project.id}" if project.present? + return unless project + + # 1. lowercase + # 2. replace non kubernetes characters with dash + # 3. trim dash from the beginning and end + + slugified = "#{project.path}-#{project.id}" + slugified.downcase! + slugified.gsub!(/[^a-z0-9]/, '-') + slugified.gsub!(/^-+|-+$/, '') + slugified end def build_kubeclient!(api_path: 'api', api_version: 'v1') -- cgit v1.2.1 From b0c2772a900bd4390d0ead7192e1bda3acd01bab Mon Sep 17 00:00:00 2001 From: Mike Greiling Date: Thu, 12 Oct 2017 11:31:29 -0500 Subject: convert Autosave into pure es module and remove global export --- app/assets/javascripts/autosave.js | 31 +++++++++------------- app/assets/javascripts/issuable_form.js | 2 +- app/assets/javascripts/notes.js | 4 +-- .../notes/components/issue_comment_form.vue | 3 +-- app/assets/javascripts/notes/mixins/autosave.js | 3 +-- 5 files changed, 18 insertions(+), 25 deletions(-) (limited to 'app') diff --git a/app/assets/javascripts/autosave.js b/app/assets/javascripts/autosave.js index 4d2d4db7c0e..73bdab4ecb7 100644 --- a/app/assets/javascripts/autosave.js +++ b/app/assets/javascripts/autosave.js @@ -1,8 +1,9 @@ -/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-param-reassign, quotes, prefer-template, no-var, one-var, no-unused-vars, one-var-declaration-per-line, no-void, consistent-return, no-empty, max-len */ +/* eslint-disable no-param-reassign, prefer-template, no-var, no-void, consistent-return */ + import AccessorUtilities from './lib/utils/accessor'; -window.Autosave = (function() { - function Autosave(field, key, resource) { +export default class Autosave { + constructor(field, key, resource) { this.field = field; this.isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe(); this.resource = resource; @@ -12,14 +13,10 @@ window.Autosave = (function() { this.key = 'autosave/' + key; this.field.data('autosave', this); this.restore(); - this.field.on('input', (function(_this) { - return function() { - return _this.save(); - }; - })(this)); + this.field.on('input', () => this.save()); } - Autosave.prototype.restore = function() { + restore() { var text; if (!this.isLocalStorageAvailable) return; @@ -40,9 +37,9 @@ window.Autosave = (function() { field.dispatchEvent(event); } } - }; + } - Autosave.prototype.save = function() { + save() { var text; text = this.field.val(); @@ -51,15 +48,13 @@ window.Autosave = (function() { } return this.reset(); - }; + } - Autosave.prototype.reset = function() { + reset() { if (!this.isLocalStorageAvailable) return; return window.localStorage.removeItem(this.key); - }; - - return Autosave; -})(); + } +} -export default window.Autosave; +window.Autosave = Autosave; diff --git a/app/assets/javascripts/issuable_form.js b/app/assets/javascripts/issuable_form.js index 470c39c6f76..10f853066ca 100644 --- a/app/assets/javascripts/issuable_form.js +++ b/app/assets/javascripts/issuable_form.js @@ -1,9 +1,9 @@ /* eslint-disable func-names, space-before-function-paren, no-var, prefer-rest-params, wrap-iife, no-use-before-define, no-useless-escape, no-new, quotes, object-shorthand, no-unused-vars, comma-dangle, no-alert, consistent-return, no-else-return, prefer-template, one-var, one-var-declaration-per-line, curly, max-len */ /* global GitLab */ -/* global Autosave */ /* global dateFormat */ import Pikaday from 'pikaday'; +import Autosave from './autosave'; import UsersSelect from './users_select'; import GfmAutoComplete from './gfm_auto_complete'; import ZenMode from './zen_mode'; diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js index 790f78d2e11..a09f938a281 100644 --- a/app/assets/javascripts/notes.js +++ b/app/assets/javascripts/notes.js @@ -5,7 +5,7 @@ default-case, prefer-template, consistent-return, no-alert, no-return-assign, no-param-reassign, prefer-arrow-callback, no-else-return, comma-dangle, no-new, brace-style, no-lonely-if, vars-on-top, no-unused-vars, no-sequences, no-shadow, newline-per-chained-call, no-useless-escape, class-methods-use-this */ -/* global Autosave */ + /* global ResolveService */ /* global mrRefreshWidgetUrl */ @@ -21,7 +21,7 @@ import Flash from './flash'; import CommentTypeToggle from './comment_type_toggle'; import GLForm from './gl_form'; import loadAwardsHandler from './awards_handler'; -import './autosave'; +import Autosave from './autosave'; import './dropzone_input'; import TaskList from './task_list'; import { ajaxPost, isInViewport, getPagePath, scrollToElement, isMetaKey } from './lib/utils/common_utils'; diff --git a/app/assets/javascripts/notes/components/issue_comment_form.vue b/app/assets/javascripts/notes/components/issue_comment_form.vue index 2ce52e4538a..ad384a1cc36 100644 --- a/app/assets/javascripts/notes/components/issue_comment_form.vue +++ b/app/assets/javascripts/notes/components/issue_comment_form.vue @@ -1,10 +1,9 @@ @@ -73,8 +91,13 @@ export default { :img-alt="imgAlt" :css-classes="imgCssClasses" :size="imgSize" - :tooltip-text="tooltipText" + :tooltip-text="avatarTooltipText" + :tooltip-placement="tooltipPlacement" + /> + >{{username}} -- cgit v1.2.1 From 1ab8aeeefd2ee826485a0be9d1c862782eaba3d4 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Thu, 19 Oct 2017 10:36:20 +0100 Subject: Moves placeholders components into shared folder with documentation. Makes them easier to reuse in MR and Snippets comments --- .../notes/components/issue_discussion.vue | 4 +- .../notes/components/issue_notes_app.vue | 10 +-- .../notes/components/issue_placeholder_note.vue | 53 ---------------- .../components/issue_placeholder_system_note.vue | 21 ------- .../notes/components/issue_system_note.vue | 54 ---------------- .../components/notes/placeholder_note.vue | 70 +++++++++++++++++++++ .../components/notes/placeholder_system_note.vue | 29 +++++++++ .../vue_shared/components/notes/system_note.vue | 73 ++++++++++++++++++++++ 8 files changed, 179 insertions(+), 135 deletions(-) delete mode 100644 app/assets/javascripts/notes/components/issue_placeholder_note.vue delete mode 100644 app/assets/javascripts/notes/components/issue_placeholder_system_note.vue delete mode 100644 app/assets/javascripts/notes/components/issue_system_note.vue create mode 100644 app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue create mode 100644 app/assets/javascripts/vue_shared/components/notes/placeholder_system_note.vue create mode 100644 app/assets/javascripts/vue_shared/components/notes/system_note.vue (limited to 'app') diff --git a/app/assets/javascripts/notes/components/issue_discussion.vue b/app/assets/javascripts/notes/components/issue_discussion.vue index baf43190d9e..0f13221b81e 100644 --- a/app/assets/javascripts/notes/components/issue_discussion.vue +++ b/app/assets/javascripts/notes/components/issue_discussion.vue @@ -9,8 +9,8 @@ import issueNoteSignedOutWidget from './issue_note_signed_out_widget.vue'; import issueNoteEditedText from './issue_note_edited_text.vue'; import issueNoteForm from './issue_note_form.vue'; - import placeholderNote from './issue_placeholder_note.vue'; - import placeholderSystemNote from './issue_placeholder_system_note.vue'; + import placeholderNote from '../../vue_shared/components/notes/placeholder_note.vue'; + import placeholderSystemNote from '../../vue_shared/components/notes/placeholder_system_note.vue'; import autosave from '../mixins/autosave'; export default { diff --git a/app/assets/javascripts/notes/components/issue_notes_app.vue b/app/assets/javascripts/notes/components/issue_notes_app.vue index aecd1f957e5..5c9119644e3 100644 --- a/app/assets/javascripts/notes/components/issue_notes_app.vue +++ b/app/assets/javascripts/notes/components/issue_notes_app.vue @@ -5,10 +5,10 @@ import * as constants from '../constants'; import issueNote from './issue_note.vue'; import issueDiscussion from './issue_discussion.vue'; - import issueSystemNote from './issue_system_note.vue'; + import systemNote from '../../vue_shared/components/notes/system_note.vue'; import issueCommentForm from './issue_comment_form.vue'; - import placeholderNote from './issue_placeholder_note.vue'; - import placeholderSystemNote from './issue_placeholder_system_note.vue'; + import placeholderNote from '../../vue_shared/components/notes/placeholder_note.vue'; + import placeholderSystemNote from '../../vue_shared/components/notes/placeholder_system_note.vue'; import loadingIcon from '../../vue_shared/components/loading_icon.vue'; export default { @@ -37,7 +37,7 @@ components: { issueNote, issueDiscussion, - issueSystemNote, + systemNote, issueCommentForm, loadingIcon, placeholderNote, @@ -68,7 +68,7 @@ } return placeholderNote; } else if (note.individual_note) { - return note.notes[0].system ? issueSystemNote : issueNote; + return note.notes[0].system ? systemNote : issueNote; } return issueDiscussion; diff --git a/app/assets/javascripts/notes/components/issue_placeholder_note.vue b/app/assets/javascripts/notes/components/issue_placeholder_note.vue deleted file mode 100644 index 6921d91372f..00000000000 --- a/app/assets/javascripts/notes/components/issue_placeholder_note.vue +++ /dev/null @@ -1,53 +0,0 @@ - - - diff --git a/app/assets/javascripts/notes/components/issue_placeholder_system_note.vue b/app/assets/javascripts/notes/components/issue_placeholder_system_note.vue deleted file mode 100644 index 80a8ef56a83..00000000000 --- a/app/assets/javascripts/notes/components/issue_placeholder_system_note.vue +++ /dev/null @@ -1,21 +0,0 @@ - - - diff --git a/app/assets/javascripts/notes/components/issue_system_note.vue b/app/assets/javascripts/notes/components/issue_system_note.vue deleted file mode 100644 index 0cfb6522e77..00000000000 --- a/app/assets/javascripts/notes/components/issue_system_note.vue +++ /dev/null @@ -1,54 +0,0 @@ - - - diff --git a/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue b/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue new file mode 100644 index 00000000000..e467ca56704 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/notes/placeholder_note.vue @@ -0,0 +1,70 @@ + + + diff --git a/app/assets/javascripts/vue_shared/components/notes/placeholder_system_note.vue b/app/assets/javascripts/vue_shared/components/notes/placeholder_system_note.vue new file mode 100644 index 00000000000..d805fea8006 --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/notes/placeholder_system_note.vue @@ -0,0 +1,29 @@ + + + diff --git a/app/assets/javascripts/vue_shared/components/notes/system_note.vue b/app/assets/javascripts/vue_shared/components/notes/system_note.vue new file mode 100644 index 00000000000..98f8f32557d --- /dev/null +++ b/app/assets/javascripts/vue_shared/components/notes/system_note.vue @@ -0,0 +1,73 @@ + + + -- cgit v1.2.1 From 6d04f3789cc16f7211fb3d465956bbd84c9430b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Thu, 19 Oct 2017 15:57:20 -0300 Subject: Avoid calling underlying methods on non-existing repos This saves us Rugged/gRPC invocations --- app/models/repository.rb | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/models/repository.rb b/app/models/repository.rb index 4324ea46aac..8a1b81b5337 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -1031,6 +1031,10 @@ class Repository if instance_variable_defined?(ivar) instance_variable_get(ivar) else + # If the repository doesn't exist and a fallback was specified we return + # that value inmediately. This saves us Rugged/gRPC invocations. + return fallback unless fallback.nil? || exists? + begin value = if memoize_only @@ -1040,8 +1044,9 @@ class Repository end instance_variable_set(ivar, value) rescue Rugged::ReferenceError, Gitlab::Git::Repository::NoRepository - # if e.g. HEAD or the entire repository doesn't exist we want to - # gracefully handle this and not cache anything. + # Even if the above `#exists?` check passes these errors might still + # occur (for example because of a non-existing HEAD). We want to + # gracefully handle this and not cache anything fallback end end -- cgit v1.2.1 From 1cf35c3d1d274a24bf7b6283bf5d43ca0ffe8a10 Mon Sep 17 00:00:00 2001 From: George Andrinopoulos Date: Sun, 22 Oct 2017 17:50:58 +0300 Subject: Add case insensitive branches search --- app/finders/branches_finder.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/finders/branches_finder.rb b/app/finders/branches_finder.rb index 533076585c0..852eac3647d 100644 --- a/app/finders/branches_finder.rb +++ b/app/finders/branches_finder.rb @@ -23,7 +23,7 @@ class BranchesFinder def filter_by_name(branches) if search - branches.select { |branch| branch.name.include?(search) } + branches.select { |branch| branch.name.upcase.include?(search.upcase) } else branches end -- cgit v1.2.1 From 57a275791ff0e263dbe07ba7f1bfc4fdf53842cf Mon Sep 17 00:00:00 2001 From: Brett Walker Date: Mon, 23 Oct 2017 19:04:57 +0300 Subject: grab the correct username when confirming secondary email --- app/controllers/confirmations_controller.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb index 80ab681ed87..43b5d557429 100644 --- a/app/controllers/confirmations_controller.rb +++ b/app/controllers/confirmations_controller.rb @@ -15,7 +15,8 @@ class ConfirmationsController < Devise::ConfirmationsController if signed_in?(:user) after_sign_in(resource) else - Gitlab::AppLogger.info("Email Confirmed: username=#{resource.username} email=#{resource.email} ip=#{request.remote_ip}") + username = (_resource_name == :email ? resource.user.username : resource.username) + Gitlab::AppLogger.info("Email Confirmed: username=#{username} email=#{resource.email} ip=#{request.remote_ip}") flash[:notice] += " Please sign in." new_session_path(:user) end -- cgit v1.2.1 From 196df264467c2332fbeed1ff350ef176e92d0fd6 Mon Sep 17 00:00:00 2001 From: Brett Walker Date: Tue, 24 Oct 2017 09:23:35 +0300 Subject: fix to pass static-analysis --- app/controllers/confirmations_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb index 43b5d557429..8ca01a6e2c6 100644 --- a/app/controllers/confirmations_controller.rb +++ b/app/controllers/confirmations_controller.rb @@ -10,12 +10,12 @@ class ConfirmationsController < Devise::ConfirmationsController users_almost_there_path end - def after_confirmation_path_for(_resource_name, resource) + def after_confirmation_path_for(resource_name, resource) # incoming resource can either be a :user or an :email if signed_in?(:user) after_sign_in(resource) else - username = (_resource_name == :email ? resource.user.username : resource.username) + username = (resource_name == :email ? resource.user.username : resource.username) Gitlab::AppLogger.info("Email Confirmed: username=#{username} email=#{resource.email} ip=#{request.remote_ip}") flash[:notice] += " Please sign in." new_session_path(:user) -- cgit v1.2.1 From cc5ba3d907c42175b70d3374c3772d0d25d12080 Mon Sep 17 00:00:00 2001 From: Robert Schilling Date: Tue, 24 Oct 2017 10:35:21 +0300 Subject: Validate username/pw for Jiraservice, require them in the API --- app/models/project_services/jira_service.rb | 2 ++ 1 file changed, 2 insertions(+) (limited to 'app') diff --git a/app/models/project_services/jira_service.rb b/app/models/project_services/jira_service.rb index 9ee3a533c1e..b487378edd2 100644 --- a/app/models/project_services/jira_service.rb +++ b/app/models/project_services/jira_service.rb @@ -3,6 +3,8 @@ class JiraService < IssueTrackerService validates :url, url: true, presence: true, if: :activated? validates :api_url, url: true, allow_blank: true + validates :username, presence: true, if: :activated? + validates :password, presence: true, if: :activated? prop_accessor :username, :password, :url, :api_url, :jira_issue_transition_id, :title, :description -- cgit v1.2.1 From a64601b9298d4b79bfc5d4f782b4dcc79ff33b74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Rodr=C3=ADguez?= Date: Mon, 23 Oct 2017 14:16:10 -0300 Subject: Move all rugged operation for ff_merge inside Gitlab::Git We also delete some unused code related to the aforementioned feature. --- app/models/repository.rb | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) (limited to 'app') diff --git a/app/models/repository.rb b/app/models/repository.rb index 4324ea46aac..327dbd2ea18 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -862,22 +862,12 @@ class Repository end def ff_merge(user, source, target_branch, merge_request: nil) - our_commit = rugged.branches[target_branch].target - their_commit = - if source.is_a?(Gitlab::Git::Commit) - source.raw_commit - else - rugged.lookup(source) - end + their_commit_id = commit(source)&.id + raise 'Invalid merge source' if their_commit_id.nil? - raise 'Invalid merge target' if our_commit.nil? - raise 'Invalid merge source' if their_commit.nil? + merge_request&.update(in_progress_merge_commit_sha: their_commit_id) - with_branch(user, target_branch) do |start_commit| - merge_request&.update(in_progress_merge_commit_sha: their_commit.oid) - - their_commit.oid - end + with_cache_hooks { raw.ff_merge(user, their_commit_id, target_branch) } end def revert( -- cgit v1.2.1 From cd0a7b475f77d7b7f76784e37b3cee7c547ce29b Mon Sep 17 00:00:00 2001 From: Annabel Dunstone Gray Date: Thu, 19 Oct 2017 15:06:48 -0700 Subject: Remove filter icon from search bar --- app/assets/stylesheets/framework/filters.scss | 13 +------------ app/views/shared/issuable/_search_bar.html.haml | 1 - 2 files changed, 1 insertion(+), 13 deletions(-) (limited to 'app') diff --git a/app/assets/stylesheets/framework/filters.scss b/app/assets/stylesheets/framework/filters.scss index b2847c348eb..0d80a85d521 100644 --- a/app/assets/stylesheets/framework/filters.scss +++ b/app/assets/stylesheets/framework/filters.scss @@ -65,7 +65,7 @@ display: flex; flex: 1; -webkit-flex: 1; - padding-left: 30px; + padding-left: 12px; position: relative; margin-bottom: 0; } @@ -221,10 +221,6 @@ box-shadow: 0 0 4px $search-input-focus-shadow-color; } - &.focus .fa-filter { - color: $common-gray-dark; - } - gl-emoji { display: inline-block; font-family: inherit; @@ -251,13 +247,6 @@ } } - .fa-filter { - position: absolute; - top: 10px; - left: 10px; - color: $gray-darkest; - } - .fa-times { right: 10px; color: $gray-darkest; diff --git a/app/views/shared/issuable/_search_bar.html.haml b/app/views/shared/issuable/_search_bar.html.haml index 161b1c9fd72..fabb17c7340 100644 --- a/app/views/shared/issuable/_search_bar.html.haml +++ b/app/views/shared/issuable/_search_bar.html.haml @@ -25,7 +25,6 @@ %ul.tokens-container.list-unstyled %li.input-token %input.form-control.filtered-search{ search_filter_input_options(type) } - = icon('filter') #js-dropdown-hint.filtered-search-input-dropdown-menu.dropdown-menu.hint-dropdown %ul{ data: { dropdown: true } } %li.filter-dropdown-item{ data: { action: 'submit' } } -- cgit v1.2.1 From 7d20b693d07e79bbe8387ee2d2da4a2b6e3534e3 Mon Sep 17 00:00:00 2001 From: Victor Wu Date: Wed, 25 Oct 2017 08:26:58 +0000 Subject: Resolve "Remove overzealous tooltips in projects page tabs" --- app/views/dashboard/_projects_head.html.haml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/views/dashboard/_projects_head.html.haml b/app/views/dashboard/_projects_head.html.haml index fd2ba9ac1ca..9038c4fbebd 100644 --- a/app/views/dashboard/_projects_head.html.haml +++ b/app/views/dashboard/_projects_head.html.haml @@ -6,13 +6,13 @@ .fade-right= icon('angle-right') %ul.nav-links.scrolling-tabs = nav_link(page: [dashboard_projects_path, root_path]) do - = link_to dashboard_projects_path, title: 'Home', class: 'shortcuts-activity', data: {placement: 'right'} do + = link_to dashboard_projects_path, class: 'shortcuts-activity', data: {placement: 'right'} do Your projects = nav_link(page: starred_dashboard_projects_path) do - = link_to starred_dashboard_projects_path, title: 'Starred Projects', data: {placement: 'right'} do + = link_to starred_dashboard_projects_path, data: {placement: 'right'} do Starred projects = nav_link(page: [explore_root_path, trending_explore_projects_path, starred_explore_projects_path, explore_projects_path]) do - = link_to explore_root_path, title: 'Explore', data: {placement: 'right'} do + = link_to explore_root_path, data: {placement: 'right'} do Explore projects .nav-controls -- cgit v1.2.1 From 294f40e2c8f51239bfa0e3514e7fe4f3c8ae00cb Mon Sep 17 00:00:00 2001 From: Francisco Lopez Date: Thu, 24 Aug 2017 16:34:36 +0200 Subject: Added ssh fingerprint, gitlab ci and pages information in an instance configuration page Closes #25142 --- app/controllers/help_controller.rb | 4 ++ app/helpers/instance_configuration_helper.rb | 18 ++++++ app/models/instance_configuration.rb | 71 ++++++++++++++++++++++ app/views/help/index.html.haml | 2 + app/views/help/instance_configuration.html.haml | 17 ++++++ .../instance_configuration/_gitlab_ci.html.haml | 24 ++++++++ .../instance_configuration/_gitlab_pages.html.haml | 35 +++++++++++ .../instance_configuration/_ssh_info.html.haml | 27 ++++++++ 8 files changed, 198 insertions(+) create mode 100644 app/helpers/instance_configuration_helper.rb create mode 100644 app/models/instance_configuration.rb create mode 100644 app/views/help/instance_configuration.html.haml create mode 100644 app/views/help/instance_configuration/_gitlab_ci.html.haml create mode 100644 app/views/help/instance_configuration/_gitlab_pages.html.haml create mode 100644 app/views/help/instance_configuration/_ssh_info.html.haml (limited to 'app') diff --git a/app/controllers/help_controller.rb b/app/controllers/help_controller.rb index 572915a4930..38f379dbf4f 100644 --- a/app/controllers/help_controller.rb +++ b/app/controllers/help_controller.rb @@ -57,6 +57,10 @@ class HelpController < ApplicationController def shortcuts end + def instance_configuration + @instance_configuration = InstanceConfiguration.new + end + def ui @user = User.new(id: 0, name: 'John Doe', username: '@johndoe') end diff --git a/app/helpers/instance_configuration_helper.rb b/app/helpers/instance_configuration_helper.rb new file mode 100644 index 00000000000..cee319f20bc --- /dev/null +++ b/app/helpers/instance_configuration_helper.rb @@ -0,0 +1,18 @@ +module InstanceConfigurationHelper + def instance_configuration_cell_html(value, &block) + return '-' unless value.to_s.presence + + block_given? ? yield(value) : value + end + + def instance_configuration_host(host) + @instance_configuration_host ||= instance_configuration_cell_html(host).capitalize + end + + # Value must be in bytes + def instance_configuration_human_size_cell(value) + instance_configuration_cell_html(value) do |v| + number_to_human_size(v, strip_insignificant_zeros: true, significant: false) + end + end +end diff --git a/app/models/instance_configuration.rb b/app/models/instance_configuration.rb new file mode 100644 index 00000000000..b30b707e5fe --- /dev/null +++ b/app/models/instance_configuration.rb @@ -0,0 +1,71 @@ +require 'resolv' + +class InstanceConfiguration + SSH_ALGORITHMS = %w(DSA ECDSA ED25519 RSA).freeze + SSH_ALGORITHMS_PATH = '/etc/ssh/'.freeze + CACHE_KEY = 'instance_configuration'.freeze + EXPIRATION_TIME = 24.hours + + def settings + @configuration ||= Rails.cache.fetch(CACHE_KEY, expires_in: EXPIRATION_TIME) do + { ssh_algorithms_hashes: ssh_algorithms_hashes, + host: host, + gitlab_pages: gitlab_pages, + gitlab_ci: gitlab_ci }.deep_symbolize_keys + end + end + + private + + def ssh_algorithms_hashes + SSH_ALGORITHMS.map { |algo| ssh_algorithm_hashes(algo) }.compact + end + + def host + Settings.gitlab.host + end + + def gitlab_pages + Settings.pages.to_h.merge(ip_address: resolv_dns(Settings.pages.host)) + end + + def resolv_dns(dns) + Resolv.getaddress(dns) + rescue Resolv::ResolvError + end + + def gitlab_ci + Settings.gitlab_ci + .to_h + .merge(artifacts_max_size: { value: Settings.artifacts.max_size&.megabytes, + default: 100.megabytes }) + end + + def ssh_algorithm_file(algorithm) + File.join(SSH_ALGORITHMS_PATH, "ssh_host_#{algorithm.downcase}_key.pub") + end + + def ssh_algorithm_hashes(algorithm) + content = ssh_algorithm_file_content(algorithm) + return unless content.present? + + { name: algorithm, + md5: ssh_algorithm_md5(content), + sha256: ssh_algorithm_sha256(content) } + end + + def ssh_algorithm_file_content(algorithm) + file = ssh_algorithm_file(algorithm) + return unless File.exist?(file) + + File.read(file) + end + + def ssh_algorithm_md5(ssh_file_content) + OpenSSL::Digest::MD5.hexdigest(ssh_file_content).scan(/../).join(':') + end + + def ssh_algorithm_sha256(ssh_file_content) + OpenSSL::Digest::SHA256.hexdigest(ssh_file_content) + end +end diff --git a/app/views/help/index.html.haml b/app/views/help/index.html.haml index c25eae63eec..d0c2e0b1d69 100644 --- a/app/views/help/index.html.haml +++ b/app/views/help/index.html.haml @@ -11,6 +11,7 @@ %span= Gitlab::VERSION %small= link_to Gitlab::REVISION, Gitlab::COM_URL + namespace_project_commits_path('gitlab-org', 'gitlab-ce', Gitlab::REVISION) = version_status_badge + %p.slead GitLab is open source software to collaborate on code. %br @@ -23,6 +24,7 @@ Used by more than 100,000 organizations, GitLab is the most popular solution to manage git repositories on-premises. %br Read more about GitLab at #{link_to promo_host, promo_url, target: '_blank', rel: 'noopener noreferrer'}. + %p= link_to 'Check the current instance configuration ', help_instance_configuration_url %hr .row.prepend-top-default diff --git a/app/views/help/instance_configuration.html.haml b/app/views/help/instance_configuration.html.haml new file mode 100644 index 00000000000..f09e3825a4b --- /dev/null +++ b/app/views/help/instance_configuration.html.haml @@ -0,0 +1,17 @@ +- page_title 'Instance Configuration' +.wiki.documentation + %h1 Instance Configuration + + %p + In this page you will find information about the settings that are used in your current instance. + + = render 'help/instance_configuration/ssh_info' + = render 'help/instance_configuration/gitlab_pages' + = render 'help/instance_configuration/gitlab_ci' + %p + %strong Table of contents + + %ul + = content_for :table_content + + = content_for :settings_content diff --git a/app/views/help/instance_configuration/_gitlab_ci.html.haml b/app/views/help/instance_configuration/_gitlab_ci.html.haml new file mode 100644 index 00000000000..7fa8bd086d4 --- /dev/null +++ b/app/views/help/instance_configuration/_gitlab_ci.html.haml @@ -0,0 +1,24 @@ +- content_for :table_content do + %li= link_to 'GitLab CI', '#gitlab-ci' + +- content_for :settings_content do + %h2#gitlab-ci + GitLab CI + + %p + Below are the current settings regarding + = succeed('.') { link_to('GitLab CI', 'https://about.gitlab.com/gitlab-ci', target: '_blank') } + + .table-responsive + %table + %thead + %tr + %th Setting + %th= instance_configuration_host(@instance_configuration.settings[:host]) + %th Default + %tbody + %tr + - artifacts_size = @instance_configuration.settings[:gitlab_ci][:artifacts_max_size] + %td Artifacts maximum size + %td= instance_configuration_human_size_cell(artifacts_size[:value]) + %td= instance_configuration_human_size_cell(artifacts_size[:default]) diff --git a/app/views/help/instance_configuration/_gitlab_pages.html.haml b/app/views/help/instance_configuration/_gitlab_pages.html.haml new file mode 100644 index 00000000000..bdd77730dcc --- /dev/null +++ b/app/views/help/instance_configuration/_gitlab_pages.html.haml @@ -0,0 +1,35 @@ +- gitlab_pages = @instance_configuration.settings[:gitlab_pages] +- content_for :table_content do + %li= link_to 'GitLab Pages', '#gitlab-pages' + +- content_for :settings_content do + %h2#gitlab-pages + GitLab Pages + + %p + Below are the settings for + = succeed('.') { link_to('Gitlab Pages', gitlab_pages[:url], target: '_blank') } + .table-responsive + %table + %thead + %tr + %th Setting + %th= instance_configuration_host(@instance_configuration.settings[:host]) + %tbody + %tr + %td Domain Name + %td + %code= instance_configuration_cell_html(gitlab_pages[:host]) + %tr + %td IP Address + %td + %code= instance_configuration_cell_html(gitlab_pages[:ip_address]) + %tr + %td Port + %td + %code= instance_configuration_cell_html(gitlab_pages[:port]) + %br + + %p + The maximum size of your Pages site is regulated by the artifacts maximum + size which is part of #{succeed('.') { link_to('GitLab CI', '#gitlab-ci') }} diff --git a/app/views/help/instance_configuration/_ssh_info.html.haml b/app/views/help/instance_configuration/_ssh_info.html.haml new file mode 100644 index 00000000000..987cc61b3f6 --- /dev/null +++ b/app/views/help/instance_configuration/_ssh_info.html.haml @@ -0,0 +1,27 @@ +- ssh_info = @instance_configuration.settings[:ssh_algorithms_hashes] +- if ssh_info.any? + - content_for :table_content do + %li= link_to 'SSH host keys fingerprints', '#ssh-host-keys-fingerprints' + + - content_for :settings_content do + %h2#ssh-host-keys-fingerprints + SSH host keys fingerprints + + %p + Below are the fingerprints for the current instance SSH host keys. + + .table-responsive + %table + %thead + %tr + %th Algorithm + %th MD5 + %th SHA256 + %tbody + - ssh_info.each do |algorithm| + %tr + %td= algorithm[:name] + %td + %code= instance_configuration_cell_html(algorithm[:md5]) + %td + %code= instance_configuration_cell_html(algorithm[:sha256]) -- cgit v1.2.1 From 17b4367045ec7943717d11cf1cafc19560da5f40 Mon Sep 17 00:00:00 2001 From: Sean McGivern Date: Thu, 26 Oct 2017 12:04:07 +0100 Subject: Revert "Merge branch '36670-remove-edit-form' into 'master'" This reverts commit 915e35a2992a4e51db2ac32aac8d7a29b1f4449e, reversing changes made to 9533786f522e358f372d8a0ec4b4990ae9d88f37. --- app/controllers/projects/issues_controller.rb | 10 +++++++++- app/views/projects/issues/edit.html.haml | 7 +++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 app/views/projects/issues/edit.html.haml (limited to 'app') diff --git a/app/controllers/projects/issues_controller.rb b/app/controllers/projects/issues_controller.rb index b7a108a0ebd..fe1334c0cfe 100644 --- a/app/controllers/projects/issues_controller.rb +++ b/app/controllers/projects/issues_controller.rb @@ -16,7 +16,7 @@ class Projects::IssuesController < Projects::ApplicationController before_action :authorize_create_issue!, only: [:new, :create] # Allow modify issue - before_action :authorize_update_issue!, only: [:update, :move] + before_action :authorize_update_issue!, only: [:edit, :update, :move] # Allow create a new branch and empty WIP merge request from current issue before_action :authorize_create_merge_request!, only: [:create_merge_request] @@ -63,6 +63,10 @@ class Projects::IssuesController < Projects::ApplicationController respond_with(@issue) end + def edit + respond_with(@issue) + end + def show @noteable = @issue @note = @project.notes.new(noteable: @issue) @@ -122,6 +126,10 @@ class Projects::IssuesController < Projects::ApplicationController @issue = Issues::UpdateService.new(project, current_user, update_params).execute(issue) respond_to do |format| + format.html do + recaptcha_check_with_fallback { render :edit } + end + format.json do render_issue_json end diff --git a/app/views/projects/issues/edit.html.haml b/app/views/projects/issues/edit.html.haml new file mode 100644 index 00000000000..1b7d878c38c --- /dev/null +++ b/app/views/projects/issues/edit.html.haml @@ -0,0 +1,7 @@ +- page_title "Edit", "#{@issue.title} (#{@issue.to_reference})", "Issues" + +%h3.page-title + Edit Issue ##{@issue.iid} +%hr + += render "form" -- cgit v1.2.1 From 3aafcc16fbdde08bf333eab97c5b1b3c4249a5cf Mon Sep 17 00:00:00 2001 From: Alessio Caiazza Date: Thu, 26 Oct 2017 16:38:10 +0200 Subject: Add KubernetesService#default_namespace tests --- app/models/project_services/kubernetes_service.rb | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) (limited to 'app') diff --git a/app/models/project_services/kubernetes_service.rb b/app/models/project_services/kubernetes_service.rb index 45a544e3674..5c0b3338a62 100644 --- a/app/models/project_services/kubernetes_service.rb +++ b/app/models/project_services/kubernetes_service.rb @@ -155,15 +155,8 @@ class KubernetesService < DeploymentService def default_namespace return unless project - # 1. lowercase - # 2. replace non kubernetes characters with dash - # 3. trim dash from the beginning and end - - slugified = "#{project.path}-#{project.id}" - slugified.downcase! - slugified.gsub!(/[^a-z0-9]/, '-') - slugified.gsub!(/^-+|-+$/, '') - slugified + slug = "#{project.path}-#{project.id}".downcase + slug.gsub(/[^-a-z0-9]/, '-').gsub(/^-+/, '') end def build_kubeclient!(api_path: 'api', api_version: 'v1') -- cgit v1.2.1 From 9a2b9d2345c504f888386012a1fefa29de837640 Mon Sep 17 00:00:00 2001 From: Clement Ho Date: Fri, 27 Oct 2017 16:11:02 +0800 Subject: Rename to shouldShowUsername --- .../vue_shared/components/user_avatar/user_avatar_link.vue | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue index 792d8b29593..dc32e783258 100644 --- a/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue +++ b/app/assets/javascripts/vue_shared/components/user_avatar/user_avatar_link.vue @@ -69,11 +69,11 @@ export default { }, }, computed: { - showUsername() { + shouldShowUsername() { return this.username.length > 0; }, avatarTooltipText() { - return this.showUsername ? '' : this.tooltipText; + return this.shouldShowUsername ? '' : this.tooltipText; }, }, directives: { @@ -94,7 +94,7 @@ export default { :tooltip-text="avatarTooltipText" :tooltip-placement="tooltipPlacement" /> Date: Thu, 19 Oct 2017 13:03:41 -0500 Subject: Change default disabled merge request widget message to "Merge is not allowed yet" Fix https://gitlab.com/gitlab-org/gitlab-ce/issues/39188 --- .../components/states/mr_widget_ready_to_merge.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js index b8a96b23012..be37dd87de9 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_ready_to_merge.js @@ -286,6 +286,7 @@ export default { Remove source branch @@ -311,8 +312,8 @@ export default { -- cgit v1.2.1 From fed51d1eaacc0d9e327cb2b67b19848d6cafd666 Mon Sep 17 00:00:00 2001 From: Filipa Lacerda Date: Fri, 27 Oct 2017 09:05:03 +0000 Subject: Remove groups_select from global namespace & simplifies the code --- app/assets/javascripts/dispatcher.js | 4 +- app/assets/javascripts/groups_select.js | 185 +++++++++++++------------------- app/assets/javascripts/main.js | 1 - 3 files changed, 77 insertions(+), 113 deletions(-) (limited to 'app') diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index f20162c48e9..970e83c0ecb 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -13,7 +13,7 @@ import GroupLabelSubscription from './group_label_subscription'; /* global LineHighlighter */ import BuildArtifacts from './build_artifacts'; import CILintEditor from './ci_lint_editor'; -/* global GroupsSelect */ +import groupsSelect from './groups_select'; /* global Search */ /* global Admin */ /* global NamespaceSelects */ @@ -414,7 +414,7 @@ import Diff from './diff'; break; case 'projects:project_members:index': memberExpirationDate('.js-access-expiration-date-groups'); - new GroupsSelect(); + groupsSelect(); memberExpirationDate(); new Members(); new UsersSelect(); diff --git a/app/assets/javascripts/groups_select.js b/app/assets/javascripts/groups_select.js index 90ca70289ab..a69a0bde17b 100644 --- a/app/assets/javascripts/groups_select.js +++ b/app/assets/javascripts/groups_select.js @@ -1,121 +1,86 @@ -/* eslint-disable func-names, space-before-function-paren, no-var, wrap-iife, one-var, - camelcase, one-var-declaration-per-line, quotes, object-shorthand, - prefer-arrow-callback, comma-dangle, consistent-return, yoda, - prefer-rest-params, prefer-spread, no-unused-vars, prefer-template, - promise/catch-or-return */ import Api from './api'; import { normalizeCRLFHeaders } from './lib/utils/common_utils'; -var slice = [].slice; +export default function groupsSelect() { + // Needs to be accessible in rspec + window.GROUP_SELECT_PER_PAGE = 20; + $('.ajax-groups-select').each(function setAjaxGroupsSelect2() { + const $select = $(this); + const allAvailable = $select.data('all-available'); + const skipGroups = $select.data('skip-groups') || []; + $select.select2({ + placeholder: 'Search for a group', + multiple: $select.hasClass('multiselect'), + minimumInputLength: 0, + ajax: { + url: Api.buildUrl(Api.groupsPath), + dataType: 'json', + quietMillis: 250, + transport(params) { + return $.ajax(params) + .then((data, status, xhr) => { + const results = data || []; -window.GroupsSelect = (function() { - function GroupsSelect() { - $('.ajax-groups-select').each((function(_this) { - const self = _this; - - return function(i, select) { - var all_available, skip_groups; - const $select = $(select); - all_available = $select.data('all-available'); - skip_groups = $select.data('skip-groups') || []; - - $select.select2({ - placeholder: "Search for a group", - multiple: $select.hasClass('multiselect'), - minimumInputLength: 0, - ajax: { - url: Api.buildUrl(Api.groupsPath), - dataType: 'json', - quietMillis: 250, - transport: function (params) { - $.ajax(params).then((data, status, xhr) => { - const results = data || []; - - const headers = normalizeCRLFHeaders(xhr.getAllResponseHeaders()); - const currentPage = parseInt(headers['X-PAGE'], 10) || 0; - const totalPages = parseInt(headers['X-TOTAL-PAGES'], 10) || 0; - const more = currentPage < totalPages; - - return { - results, - pagination: { - more, - }, - }; - }).then(params.success).fail(params.error); - }, - data: function (search, page) { - return { - search, - page, - per_page: GroupsSelect.PER_PAGE, - all_available, - }; - }, - results: function (data, page) { - if (data.length) return { results: [] }; - - const groups = data.length ? data : data.results || []; - const more = data.pagination ? data.pagination.more : false; - const results = groups.filter(group => skip_groups.indexOf(group.id) === -1); + const headers = normalizeCRLFHeaders(xhr.getAllResponseHeaders()); + const currentPage = parseInt(headers['X-PAGE'], 10) || 0; + const totalPages = parseInt(headers['X-TOTAL-PAGES'], 10) || 0; + const more = currentPage < totalPages; return { results, - page, - more, + pagination: { + more, + }, }; - }, - }, - initSelection: function(element, callback) { - var id; - id = $(element).val(); - if (id !== "") { - return Api.group(id, callback); - } - }, - formatResult: function() { - var args; - args = 1 <= arguments.length ? slice.call(arguments, 0) : []; - return self.formatResult.apply(self, args); - }, - formatSelection: function() { - var args; - args = 1 <= arguments.length ? slice.call(arguments, 0) : []; - return self.formatSelection.apply(self, args); - }, - dropdownCssClass: "ajax-groups-dropdown select2-infinite", - // we do not want to escape markup since we are displaying html in results - escapeMarkup: function(m) { - return m; - } - }); - - self.dropdown = document.querySelector('.select2-infinite .select2-results'); - - $select.on('select2-loaded', self.forceOverflow.bind(self)); - }; - })(this)); - } - - GroupsSelect.prototype.formatResult = function(group) { - var avatar; - if (group.avatar_url) { - avatar = group.avatar_url; - } else { - avatar = gon.default_avatar_url; - } - return "
" + group.full_name + "
" + group.full_path + "
"; - }; - - GroupsSelect.prototype.formatSelection = function(group) { - return group.full_name; - }; + }) + .then(params.success) + .fail(params.error); + }, + data(search, page) { + return { + search, + page, + per_page: window.GROUP_SELECT_PER_PAGE, + all_available: allAvailable, + }; + }, + results(data, page) { + if (data.length) return { results: [] }; - GroupsSelect.prototype.forceOverflow = function (e) { - this.dropdown.style.height = `${Math.floor(this.dropdown.scrollHeight)}px`; - }; + const groups = data.length ? data : data.results || []; + const more = data.pagination ? data.pagination.more : false; + const results = groups.filter(group => skipGroups.indexOf(group.id) === -1); - GroupsSelect.PER_PAGE = 20; + return { + results, + page, + more, + }; + }, + }, + // eslint-disable-next-line consistent-return + initSelection(element, callback) { + const id = $(element).val(); + if (id !== '') { + return Api.group(id, callback); + } + }, + formatResult(object) { + return `
${object.full_name}
${object.full_path}
`; + }, + formatSelection(object) { + return object.full_name; + }, + dropdownCssClass: 'ajax-groups-dropdown select2-infinite', + // we do not want to escape markup since we are displaying html in results + escapeMarkup(m) { + return m; + }, + }); - return GroupsSelect; -})(); + $select.on('select2-loaded', () => { + const dropdown = document.querySelector('.select2-infinite .select2-results'); + dropdown.style.height = `${Math.floor(dropdown.scrollHeight)}px`; + }); + }); +} diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 52715fba43f..38403fdaf6e 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -55,7 +55,6 @@ import './gl_dropdown'; import './gl_field_error'; import './gl_field_errors'; import './gl_form'; -import './groups_select'; import './header'; import './importer_status'; import './issuable_index'; -- cgit v1.2.1 From 3411fef1df22295cc68b1d39576917dd533da580 Mon Sep 17 00:00:00 2001 From: Zeger-Jan van de Weg Date: Fri, 13 Oct 2017 10:37:31 +0200 Subject: Cache commits on the repository model Now, when requesting a commit from the Repository model, the results are not cached. This means we're fetching the same commit by oid multiple times during the same request. To prevent us from doing this, we now cache results. Caching is done only based on object id (aka SHA). Given we cache on the Repository model, results are scoped to the associated project, eventhough the change of two repositories having the same oids for different commits is small. --- app/models/ci/pipeline.rb | 4 +--- app/models/project.rb | 6 +++++- app/models/repository.rb | 38 +++++++++++++++++++++++++------------- 3 files changed, 31 insertions(+), 17 deletions(-) (limited to 'app') diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index cf3ce3c9e54..ca65e81f27a 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -249,9 +249,7 @@ module Ci end def commit - @commit ||= project.commit(sha) - rescue - nil + @commit ||= project.commit_by(oid: sha) end def branch? diff --git a/app/models/project.rb b/app/models/project.rb index 4689b588906..7185b4d44fc 100644 --- a/app/models/project.rb +++ b/app/models/project.rb @@ -540,6 +540,10 @@ class Project < ActiveRecord::Base repository.commit(ref) end + def commit_by(oid:) + repository.commit_by(oid: oid) + end + # ref can't be HEAD, can only be branch/tag name or SHA def latest_successful_builds_for(ref = default_branch) latest_pipeline = pipelines.latest_successful_for(ref) @@ -553,7 +557,7 @@ class Project < ActiveRecord::Base def merge_base_commit(first_commit_id, second_commit_id) sha = repository.merge_base(first_commit_id, second_commit_id) - repository.commit(sha) if sha + commit_by(oid: sha) if sha end def saved? diff --git a/app/models/repository.rb b/app/models/repository.rb index 4324ea46aac..1d1987ec322 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -76,6 +76,7 @@ class Repository @full_path = full_path @disk_path = disk_path || full_path @project = project + @commit_cache = {} end def ==(other) @@ -103,18 +104,17 @@ class Repository def commit(ref = 'HEAD') return nil unless exists? + return ref if ref.is_a?(::Commit) - commit = - if ref.is_a?(Gitlab::Git::Commit) - ref - else - Gitlab::Git::Commit.find(raw_repository, ref) - end + find_commit(ref) + end - commit = ::Commit.new(commit, @project) if commit - commit - rescue Rugged::OdbError, Rugged::TreeError - nil + # Finding a commit by the passed SHA + # Also takes care of caching, based on the SHA + def commit_by(oid:) + return @commit_cache[oid] if @commit_cache.key?(oid) + + @commit_cache[oid] = find_commit(oid) end def commits(ref, path: nil, limit: nil, offset: nil, skip_merges: false, after: nil, before: nil) @@ -231,7 +231,7 @@ class Repository # branches or tags, but we want to keep some of these commits around, for # example if they have comments or CI builds. def keep_around(sha) - return unless sha && commit(sha) + return unless sha && commit_by(oid: sha) return if kept_around?(sha) @@ -1069,6 +1069,18 @@ class Repository private + # TODO Generice finder, later split this on finders by Ref or Oid + # gitlab-org/gitlab-ce#39239 + def find_commit(oid_or_ref) + commit = if oid_or_ref.is_a?(Gitlab::Git::Commit) + oid_or_ref + else + Gitlab::Git::Commit.find(raw_repository, oid_or_ref) + end + + ::Commit.new(commit, @project) if commit + end + def blob_data_at(sha, path) blob = blob_at(sha, path) return unless blob @@ -1107,12 +1119,12 @@ class Repository def last_commit_for_path_by_gitaly(sha, path) c = raw_repository.gitaly_commit_client.last_commit_for_path(sha, path) - commit(c) + commit_by(oid: c) end def last_commit_for_path_by_rugged(sha, path) sha = last_commit_id_for_path_by_shelling_out(sha, path) - commit(sha) + commit_by(oid: sha) end def last_commit_id_for_path_by_shelling_out(sha, path) -- cgit v1.2.1 From a2894b7ad2b26ff65d36b9c87b79c60ff4ddda59 Mon Sep 17 00:00:00 2001 From: Brett Walker Date: Fri, 27 Oct 2017 16:32:48 +0200 Subject: use a delegate for `username` to be more future friendly --- app/controllers/confirmations_controller.rb | 3 +-- app/models/email.rb | 2 ++ 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/controllers/confirmations_controller.rb b/app/controllers/confirmations_controller.rb index 8ca01a6e2c6..bc0948cd3fb 100644 --- a/app/controllers/confirmations_controller.rb +++ b/app/controllers/confirmations_controller.rb @@ -15,8 +15,7 @@ class ConfirmationsController < Devise::ConfirmationsController if signed_in?(:user) after_sign_in(resource) else - username = (resource_name == :email ? resource.user.username : resource.username) - Gitlab::AppLogger.info("Email Confirmed: username=#{username} email=#{resource.email} ip=#{request.remote_ip}") + Gitlab::AppLogger.info("Email Confirmed: username=#{resource.username} email=#{resource.email} ip=#{request.remote_ip}") flash[:notice] += " Please sign in." new_session_path(:user) end diff --git a/app/models/email.rb b/app/models/email.rb index 384f38f2db7..2da8b050149 100644 --- a/app/models/email.rb +++ b/app/models/email.rb @@ -14,6 +14,8 @@ class Email < ActiveRecord::Base devise :confirmable self.reconfirmable = false # currently email can't be changed, no need to reconfirm + delegate :username, to: :user + def email=(value) write_attribute(:email, value.downcase.strip) end -- cgit v1.2.1 From 57d7ed05d96928f7e33135e7397bdd6b3b0d25e0 Mon Sep 17 00:00:00 2001 From: "Lin Jen-Shin (godfat)" Date: Fri, 27 Oct 2017 15:55:08 +0000 Subject: Fetch the merged branches at once --- app/controllers/projects/branches_controller.rb | 2 ++ app/models/repository.rb | 21 +++++++++++++++------ app/views/projects/branches/_branch.html.haml | 5 +++-- app/views/projects/branches/index.html.haml | 2 +- 4 files changed, 21 insertions(+), 9 deletions(-) (limited to 'app') diff --git a/app/controllers/projects/branches_controller.rb b/app/controllers/projects/branches_controller.rb index 7f03ce07dec..f28df83d5a5 100644 --- a/app/controllers/projects/branches_controller.rb +++ b/app/controllers/projects/branches_controller.rb @@ -15,6 +15,8 @@ class Projects::BranchesController < Projects::ApplicationController respond_to do |format| format.html do @refs_pipelines = @project.pipelines.latest_successful_for_refs(@branches.map(&:name)) + @merged_branch_names = + repository.merged_branch_names(@branches.map(&:name)) # n+1: https://gitlab.com/gitlab-org/gitlab-ce/issues/37429 Gitlab::GitalyClient.allow_n_plus_1_calls do @max_commits = @branches.reduce(0) do |memo, branch| diff --git a/app/models/repository.rb b/app/models/repository.rb index 54388d1c8b4..44a1e9ce529 100644 --- a/app/models/repository.rb +++ b/app/models/repository.rb @@ -902,18 +902,27 @@ class Repository end end - def merged_to_root_ref?(branch_name) - branch_commit = commit(branch_name) - root_ref_commit = commit(root_ref) + def merged_to_root_ref?(branch_or_name, pre_loaded_merged_branches = nil) + branch = Gitlab::Git::Branch.find(self, branch_or_name) + + if branch + root_ref_sha = commit(root_ref).sha + same_head = branch.target == root_ref_sha + merged = + if pre_loaded_merged_branches + pre_loaded_merged_branches.include?(branch.name) + else + ancestor?(branch.target, root_ref_sha) + end - if branch_commit - same_head = branch_commit.id == root_ref_commit.id - !same_head && ancestor?(branch_commit.id, root_ref_commit.id) + !same_head && merged else nil end end + delegate :merged_branch_names, to: :raw_repository + def merge_base(first_commit_id, second_commit_id) first_commit_id = commit(first_commit_id).try(:id) || first_commit_id second_commit_id = commit(second_commit_id).try(:id) || second_commit_id diff --git a/app/views/projects/branches/_branch.html.haml b/app/views/projects/branches/_branch.html.haml index 49101d1efa4..6e02ae6c9cc 100644 --- a/app/views/projects/branches/_branch.html.haml +++ b/app/views/projects/branches/_branch.html.haml @@ -1,3 +1,4 @@ +- merged = local_assigns.fetch(:merged, false) - commit = @repository.commit(branch.dereferenced_target) - bar_graph_width_factor = @max_commits > 0 ? 100.0/@max_commits : 0 - diverging_commit_counts = @repository.diverging_commit_counts(branch) @@ -12,7 +13,7 @@   - if branch.name == @repository.root_ref %span.label.label-primary default - - elsif @repository.merged_to_root_ref? branch.name + - elsif merged %span.label.label-info.has-tooltip{ title: s_('Branches|Merged into %{default_branch}') % { default_branch: @repository.root_ref } } = s_('Branches|merged') @@ -47,7 +48,7 @@ target: "#modal-delete-branch", delete_path: project_branch_path(@project, branch.name), branch_name: branch.name, - is_merged: ("true" if @repository.merged_to_root_ref?(branch.name)) } } + is_merged: ("true" if merged) } } = icon("trash-o") - else %button{ class: "btn btn-remove remove-row js-ajax-loading-spinner has-tooltip disabled", diff --git a/app/views/projects/branches/index.html.haml b/app/views/projects/branches/index.html.haml index 7d9645d79e6..aade310236e 100644 --- a/app/views/projects/branches/index.html.haml +++ b/app/views/projects/branches/index.html.haml @@ -38,7 +38,7 @@ - if @branches.any? %ul.content-list.all-branches - @branches.each do |branch| - = render "projects/branches/branch", branch: branch + = render "projects/branches/branch", branch: branch, merged: @repository.merged_to_root_ref?(branch, @merged_branch_names) = paginate @branches, theme: 'gitlab' - else .nothing-here-block -- cgit v1.2.1 From a6c52c4e593850eb270e5bfbd021cdfb56e6eed6 Mon Sep 17 00:00:00 2001 From: Oswaldo Ferreira Date: Fri, 27 Oct 2017 22:11:21 +0200 Subject: Make merge_jid handling less stateful in MergeService --- app/models/merge_request.rb | 4 +++- app/services/merge_requests/merge_service.rb | 9 +-------- app/workers/stuck_merge_jobs_worker.rb | 2 +- 3 files changed, 5 insertions(+), 10 deletions(-) (limited to 'app') diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index c3fae16d109..c952ab862d7 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -396,7 +396,9 @@ class MergeRequest < ActiveRecord::Base end def merge_ongoing? - !!merge_jid && !merged? && Gitlab::SidekiqStatus.running?(merge_jid) + # While the MergeRequest is locked, it should present itself as 'merge ongoing'. + # The unlocking process is handled by StuckMergeJobsWorker scheduled in Cron. + locked? || !!merge_jid && !merged? && Gitlab::SidekiqStatus.running?(merge_jid) end def closed_without_fork? diff --git a/app/services/merge_requests/merge_service.rb b/app/services/merge_requests/merge_service.rb index 8c5821aa870..156e7b2f078 100644 --- a/app/services/merge_requests/merge_service.rb +++ b/app/services/merge_requests/merge_service.rb @@ -82,16 +82,9 @@ module MergeRequests @merge_request.can_remove_source_branch?(branch_deletion_user) end - # Logs merge error message and cleans `MergeRequest#merge_jid`. - # def handle_merge_error(log_message:, save_message_on_model: false) Rails.logger.error("MergeService ERROR: #{merge_request_info} - #{log_message}") - - if save_message_on_model - @merge_request.update(merge_error: log_message, merge_jid: nil) - else - clean_merge_jid - end + @merge_request.update(merge_error: log_message) if save_message_on_model end def merge_request_info diff --git a/app/workers/stuck_merge_jobs_worker.rb b/app/workers/stuck_merge_jobs_worker.rb index 7843179d77c..a396c0f27b2 100644 --- a/app/workers/stuck_merge_jobs_worker.rb +++ b/app/workers/stuck_merge_jobs_worker.rb @@ -23,7 +23,7 @@ class StuckMergeJobsWorker merge_requests = MergeRequest.where(id: completed_ids) merge_requests.where.not(merge_commit_sha: nil).update_all(state: :merged) - merge_requests.where(merge_commit_sha: nil).update_all(state: :opened) + merge_requests.where(merge_commit_sha: nil).update_all(state: :opened, merge_jid: nil) Rails.logger.info("Updated state of locked merge jobs. JIDs: #{completed_jids.join(', ')}") end -- cgit v1.2.1 From 7dbf114f595f8ff3ff41339d81d41b7722b97d2a Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Fri, 27 Oct 2017 16:09:11 +0200 Subject: Use the correct project visibility in system hooks --- app/services/system_hooks_service.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb index a1c2f8d0180..5d275967821 100644 --- a/app/services/system_hooks_service.rb +++ b/app/services/system_hooks_service.rb @@ -83,7 +83,7 @@ class SystemHooksService project_id: model.id, owner_name: owner.name, owner_email: owner.respond_to?(:email) ? owner.email : "", - project_visibility: Project.visibility_levels.key(model.visibility_level_value).downcase + project_visibility: model.visibility.downcase } end -- cgit v1.2.1 From cd784a80d7c779edc468d6255ffdeb8ea692661a Mon Sep 17 00:00:00 2001 From: Oswaldo Ferreira Date: Mon, 30 Oct 2017 09:10:09 +0000 Subject: [CE backport] Saved configuration for issue board --- .../javascripts/boards/filtered_search_boards.js | 9 +- .../javascripts/boards/stores/boards_store.js | 8 +- .../javascripts/filtered_search/dropdown_utils.js | 10 ++ .../filtered_search/filtered_search_manager.js | 10 +- .../filtered_search_visual_tokens.js | 15 +-- app/assets/javascripts/labels_select.js | 13 ++- app/assets/javascripts/milestone_select.js | 17 +++- app/assets/javascripts/users_select.js | 7 +- .../vue_shared/components/loading_icon.vue | 8 +- .../vue_shared/components/popup_dialog.vue | 101 +++++++++++++-------- app/assets/stylesheets/framework/common.scss | 3 + app/assets/stylesheets/framework/dropdowns.scss | 1 + app/assets/stylesheets/framework/modal.scss | 8 ++ .../framework/tw_bootstrap_variables.scss | 33 +++++++ app/assets/stylesheets/pages/repo.scss | 13 --- app/helpers/boards_helper.rb | 11 --- 16 files changed, 174 insertions(+), 93 deletions(-) (limited to 'app') diff --git a/app/assets/javascripts/boards/filtered_search_boards.js b/app/assets/javascripts/boards/filtered_search_boards.js index 3f083655f95..184665f395c 100644 --- a/app/assets/javascripts/boards/filtered_search_boards.js +++ b/app/assets/javascripts/boards/filtered_search_boards.js @@ -11,7 +11,8 @@ export default class FilteredSearchBoards extends gl.FilteredSearchManager { // Issue boards is slightly different, we handle all the requests async // instead or reloading the page, we just re-fire the list ajax requests this.isHandledAsync = true; - this.cantEdit = cantEdit; + this.cantEdit = cantEdit.filter(i => typeof i === 'string'); + this.cantEditWithValue = cantEdit.filter(i => typeof i === 'object'); } updateObject(path) { @@ -42,7 +43,9 @@ export default class FilteredSearchBoards extends gl.FilteredSearchManager { this.filteredSearchInput.dispatchEvent(new Event('input')); } - canEdit(tokenName) { - return this.cantEdit.indexOf(tokenName) === -1; + canEdit(tokenName, tokenValue) { + if (this.cantEdit.includes(tokenName)) return false; + return this.cantEditWithValue.findIndex(token => token.name === tokenName && + token.value === tokenValue) === -1; } } diff --git a/app/assets/javascripts/boards/stores/boards_store.js b/app/assets/javascripts/boards/stores/boards_store.js index ea82958e80d..798d7e0d147 100644 --- a/app/assets/javascripts/boards/stores/boards_store.js +++ b/app/assets/javascripts/boards/stores/boards_store.js @@ -14,16 +14,18 @@ gl.issueBoards.BoardsStore = { }, state: {}, detail: { - issue: {} + issue: {}, }, moving: { issue: {}, - list: {} + list: {}, }, create () { this.state.lists = []; this.filter.path = getUrlParamsArray().join('&'); - this.detail = { issue: {} }; + this.detail = { + issue: {}, + }; }, addList (listObj, defaultAvatar) { const list = new List(listObj, defaultAvatar); diff --git a/app/assets/javascripts/filtered_search/dropdown_utils.js b/app/assets/javascripts/filtered_search/dropdown_utils.js index 8d711e3213c..cf8a9b0402b 100644 --- a/app/assets/javascripts/filtered_search/dropdown_utils.js +++ b/app/assets/javascripts/filtered_search/dropdown_utils.js @@ -147,6 +147,16 @@ class DropdownUtils { return dataValue !== null; } + static getVisualTokenValues(visualToken) { + const tokenName = visualToken && visualToken.querySelector('.name').textContent.trim(); + let tokenValue = visualToken && visualToken.querySelector('.value') && visualToken.querySelector('.value').textContent.trim(); + if (tokenName === 'label' && tokenValue) { + // remove leading symbol and wrapping quotes + tokenValue = tokenValue.replace(/^~("|')?(.*)/, '$2').replace(/("|')$/, ''); + } + return { tokenName, tokenValue }; + } + // Determines the full search query (visual tokens + input) static getSearchQuery(untilInput = false) { const container = FilteredSearchContainer.container; diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js index 7b233842d5a..69c57f923b6 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_manager.js +++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js @@ -185,8 +185,8 @@ class FilteredSearchManager { if (e.keyCode === 8 || e.keyCode === 46) { const { lastVisualToken } = gl.FilteredSearchVisualTokens.getLastVisualTokenBeforeInput(); - const sanitizedTokenName = lastVisualToken && lastVisualToken.querySelector('.name').textContent.trim(); - const canEdit = sanitizedTokenName && this.canEdit && this.canEdit(sanitizedTokenName); + const { tokenName, tokenValue } = gl.DropdownUtils.getVisualTokenValues(lastVisualToken); + const canEdit = tokenName && this.canEdit && this.canEdit(tokenName, tokenValue); if (this.filteredSearchInput.value === '' && lastVisualToken && canEdit) { this.filteredSearchInput.value = gl.FilteredSearchVisualTokens.getLastTokenPartial(); gl.FilteredSearchVisualTokens.removeLastTokenPartial(); @@ -336,8 +336,8 @@ class FilteredSearchManager { let canClearToken = t.classList.contains('js-visual-token'); if (canClearToken) { - const tokenKey = t.querySelector('.name').textContent.trim(); - canClearToken = this.canEdit && this.canEdit(tokenKey); + const { tokenName, tokenValue } = gl.DropdownUtils.getVisualTokenValues(t); + canClearToken = this.canEdit && this.canEdit(tokenName, tokenValue); } if (canClearToken) { @@ -469,7 +469,7 @@ class FilteredSearchManager { } hasFilteredSearch = true; - const canEdit = this.canEdit && this.canEdit(sanitizedKey); + const canEdit = this.canEdit && this.canEdit(sanitizedKey, sanitizedValue); gl.FilteredSearchVisualTokens.addFilterVisualToken( sanitizedKey, `${symbol}${quotationsToUse}${sanitizedValue}${quotationsToUse}`, diff --git a/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js b/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js index d2f92929b8a..6139e81fe6d 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js +++ b/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js @@ -38,21 +38,14 @@ class FilteredSearchVisualTokens { } static createVisualTokenElementHTML(canEdit = true) { - let removeTokenMarkup = ''; - if (canEdit) { - removeTokenMarkup = ` -
- -
- `; - } - return ` -
+
- ${removeTokenMarkup} +
+ +
`; diff --git a/app/assets/javascripts/labels_select.js b/app/assets/javascripts/labels_select.js index 84602cf9207..1e52963b1dd 100644 --- a/app/assets/javascripts/labels_select.js +++ b/app/assets/javascripts/labels_select.js @@ -8,7 +8,7 @@ import CreateLabelDropdown from './create_label'; (function() { this.LabelsSelect = (function() { - function LabelsSelect(els) { + function LabelsSelect(els, options = {}) { var _this, $els; _this = this; @@ -58,6 +58,7 @@ import CreateLabelDropdown from './create_label'; labelHTMLTemplate = _.template('<% _.each(labels, function(label){ %> issues?label_name[]=<%- encodeURIComponent(label.title) %>"> <%- label.title %> <% }); %>'); labelNoneHTMLTemplate = 'None'; } + const handleClick = options.handleClick; $sidebarLabelTooltip.tooltip(); @@ -316,9 +317,9 @@ import CreateLabelDropdown from './create_label'; }, multiSelect: $dropdown.hasClass('js-multiselect'), vue: $dropdown.hasClass('js-issue-board-sidebar'), - clicked: function(options) { - const { $el, e, isMarking } = options; - const label = options.selectedObj; + clicked: function(clickEvent) { + const { $el, e, isMarking } = clickEvent; + const label = clickEvent.selectedObj; var isIssueIndex, isMRIndex, page, boardsModel; var fadeOutLoader = () => { @@ -391,6 +392,10 @@ import CreateLabelDropdown from './create_label'; .then(fadeOutLoader) .catch(fadeOutLoader); } + else if (handleClick) { + e.preventDefault(); + handleClick(label); + } else { if ($dropdown.hasClass('js-multiselect')) { diff --git a/app/assets/javascripts/milestone_select.js b/app/assets/javascripts/milestone_select.js index e7d5325a509..74e5a4f1cea 100644 --- a/app/assets/javascripts/milestone_select.js +++ b/app/assets/javascripts/milestone_select.js @@ -5,7 +5,7 @@ import _ from 'underscore'; (function() { this.MilestoneSelect = (function() { - function MilestoneSelect(currentProject, els) { + function MilestoneSelect(currentProject, els, options = {}) { var _this, $els; if (currentProject != null) { _this = this; @@ -136,19 +136,26 @@ import _ from 'underscore'; }, opened: function(e) { const $el = $(e.currentTarget); - if ($dropdown.hasClass('js-issue-board-sidebar')) { + if ($dropdown.hasClass('js-issue-board-sidebar') || options.handleClick) { selectedMilestone = $dropdown[0].dataset.selected || selectedMilestoneDefault; } $('a.is-active', $el).removeClass('is-active'); $(`[data-milestone-id="${selectedMilestone}"] > a`, $el).addClass('is-active'); }, vue: $dropdown.hasClass('js-issue-board-sidebar'), - clicked: function(options) { - const { $el, e } = options; - let selected = options.selectedObj; + clicked: function(clickEvent) { + const { $el, e } = clickEvent; + let selected = clickEvent.selectedObj; var data, isIssueIndex, isMRIndex, isSelecting, page, boardsStore; if (!selected) return; + + if (options.handleClick) { + e.preventDefault(); + options.handleClick(selected); + return; + } + page = $('body').attr('data-page'); isIssueIndex = page === 'projects:issues:index'; isMRIndex = (page === page && page === 'projects:merge_requests:index'); diff --git a/app/assets/javascripts/users_select.js b/app/assets/javascripts/users_select.js index a0883b32593..759cc9925f4 100644 --- a/app/assets/javascripts/users_select.js +++ b/app/assets/javascripts/users_select.js @@ -6,7 +6,7 @@ import _ from 'underscore'; // TODO: remove eventHub hack after code splitting refactor window.emitSidebarEvent = window.emitSidebarEvent || $.noop; -function UsersSelect(currentUser, els) { +function UsersSelect(currentUser, els, options = {}) { var $els; this.users = this.users.bind(this); this.user = this.user.bind(this); @@ -20,6 +20,8 @@ function UsersSelect(currentUser, els) { } } + const { handleClick } = options; + $els = $(els); if (!els) { @@ -442,6 +444,9 @@ function UsersSelect(currentUser, els) { } if ($el.closest('.add-issues-modal').length) { gl.issueBoards.ModalStore.store.filter[$dropdown.data('field-name')] = user.id; + } else if (handleClick) { + e.preventDefault(); + handleClick(user, isMarking); } else if ($dropdown.hasClass('js-filter-submit') && (isIssueIndex || isMRIndex)) { return Issuable.filterResults($dropdown.closest('form')); } else if ($dropdown.hasClass('js-filter-submit')) { diff --git a/app/assets/javascripts/vue_shared/components/loading_icon.vue b/app/assets/javascripts/vue_shared/components/loading_icon.vue index 15581d5c2a0..494fe4468d9 100644 --- a/app/assets/javascripts/vue_shared/components/loading_icon.vue +++ b/app/assets/javascripts/vue_shared/components/loading_icon.vue @@ -18,6 +18,12 @@ required: false, default: false, }, + + class: { + type: String, + required: false, + default: '', + }, }, computed: { @@ -25,7 +31,7 @@ return this.inline ? 'span' : 'div'; }, cssClass() { - return `fa-${this.size}x`; + return `fa-${this.size}x ${this.class}`.trim(); }, }, }; diff --git a/app/assets/javascripts/vue_shared/components/popup_dialog.vue b/app/assets/javascripts/vue_shared/components/popup_dialog.vue index 9e8c10bdc1a..fc6421fecb9 100644 --- a/app/assets/javascripts/vue_shared/components/popup_dialog.vue +++ b/app/assets/javascripts/vue_shared/components/popup_dialog.vue @@ -5,17 +5,27 @@ export default { props: { title: { type: String, - required: true, + required: false, }, text: { type: String, required: false, }, + hideFooter: { + type: Boolean, + required: false, + default: false, + }, kind: { type: String, required: false, default: 'primary', }, + modalDialogClass: { + type: String, + required: false, + default: '', + }, closeKind: { type: String, required: false, @@ -30,6 +40,11 @@ export default { type: String, required: true, }, + submitDisabled: { + type: Boolean, + required: false, + default: false, + }, }, computed: { @@ -57,43 +72,57 @@ export default { diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index 96f9dda26c4..1cfd7ef01a8 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -4,6 +4,9 @@ .cred { color: $common-red; } .cgreen { color: $common-green; } .cdark { color: $common-gray-dark; } +.text-secondary { + color: $gl-text-color-secondary; +} /** COMMON CLASSES **/ .prepend-top-0 { margin-top: 0; } diff --git a/app/assets/stylesheets/framework/dropdowns.scss b/app/assets/stylesheets/framework/dropdowns.scss index a9d804e735d..63697fd38a7 100644 --- a/app/assets/stylesheets/framework/dropdowns.scss +++ b/app/assets/stylesheets/framework/dropdowns.scss @@ -37,6 +37,7 @@ .dropdown-menu-nav { @include set-visible; display: block; + min-height: 40px; @media (max-width: $screen-xs-max) { width: 100%; diff --git a/app/assets/stylesheets/framework/modal.scss b/app/assets/stylesheets/framework/modal.scss index 1cebd02df48..d218fb6d702 100644 --- a/app/assets/stylesheets/framework/modal.scss +++ b/app/assets/stylesheets/framework/modal.scss @@ -42,3 +42,11 @@ body.modal-open { width: 98%; } } + +.modal.popup-dialog { + display: block; +} + +.modal-body { + background-color: $modal-body-bg; +} diff --git a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss index 3ea77eb7a43..a23131e0818 100644 --- a/app/assets/stylesheets/framework/tw_bootstrap_variables.scss +++ b/app/assets/stylesheets/framework/tw_bootstrap_variables.scss @@ -164,3 +164,36 @@ $pre-border-color: $border-color; $table-bg-accent: $gray-light; $zindex-popover: 900; + +//== Modals +// +//## + +//** Padding applied to the modal body +$modal-inner-padding: $gl-padding; + +//** Padding applied to the modal title +$modal-title-padding: $gl-padding; +//** Modal title line-height +// $modal-title-line-height: $line-height-base + +//** Background color of modal content area +$modal-content-bg: $gray-light; +$modal-body-bg: $white-light; +//** Modal content border color +// $modal-content-border-color: rgba(0,0,0,.2) +//** Modal content border color **for IE8** +// $modal-content-fallback-border-color: #999 + +//** Modal backdrop background color +// $modal-backdrop-bg: #000 +//** Modal backdrop opacity +// $modal-backdrop-opacity: .5 +//** Modal header border color +// $modal-header-border-color: #e5e5e5 +//** Modal footer border color +// $modal-footer-border-color: $modal-header-border-color + +// $modal-lg: 900px +// $modal-md: 600px +// $modal-sm: 300px diff --git a/app/assets/stylesheets/pages/repo.scss b/app/assets/stylesheets/pages/repo.scss index 6a363b1710e..e8c7f8a8fc0 100644 --- a/app/assets/stylesheets/pages/repo.scss +++ b/app/assets/stylesheets/pages/repo.scss @@ -7,19 +7,6 @@ background: $black-transparent; } -.modal.popup-dialog { - display: block; - background-color: $black-transparent; - z-index: 2100; - - @media (min-width: $screen-md-min) { - .modal-dialog { - width: 600px; - margin: 30px auto; - } - } -} - .project-refs-form, .project-refs-target-form { display: inline-block; diff --git a/app/helpers/boards_helper.rb b/app/helpers/boards_helper.rb index 7112c6ee470..c4a621160af 100644 --- a/app/helpers/boards_helper.rb +++ b/app/helpers/boards_helper.rb @@ -20,17 +20,6 @@ module BoardsHelper project_issues_path(@project) end - def current_board_json - board = @board || @boards.first - - board.to_json( - only: [:id, :name, :milestone_id], - include: { - milestone: { only: [:title] } - } - ) - end - def board_base_url project_boards_path(@project) end -- cgit v1.2.1 From c4124fce48e83db603d69a83bb912ae5d0d54f65 Mon Sep 17 00:00:00 2001 From: Oswaldo Ferreira Date: Mon, 30 Oct 2017 11:21:23 +0100 Subject: Move locked check to a guard-clause --- app/models/merge_request.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'app') diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index c952ab862d7..07352db5d2d 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -398,7 +398,9 @@ class MergeRequest < ActiveRecord::Base def merge_ongoing? # While the MergeRequest is locked, it should present itself as 'merge ongoing'. # The unlocking process is handled by StuckMergeJobsWorker scheduled in Cron. - locked? || !!merge_jid && !merged? && Gitlab::SidekiqStatus.running?(merge_jid) + return true if locked? + + !!merge_jid && !merged? && Gitlab::SidekiqStatus.running?(merge_jid) end def closed_without_fork? -- cgit v1.2.1