diff options
-rw-r--r-- | Gemfile.lock | 2 | ||||
-rw-r--r-- | app/assets/javascripts/broadcast_message.js | 45 | ||||
-rw-r--r-- | app/assets/javascripts/dispatcher.js | 16 | ||||
-rw-r--r-- | app/assets/javascripts/main.js | 3 | ||||
-rw-r--r-- | app/assets/javascripts/member_expiration_date.js | 87 | ||||
-rw-r--r-- | app/assets/javascripts/members.js | 129 | ||||
-rw-r--r-- | app/models/merge_request.rb | 2 | ||||
-rw-r--r-- | app/views/shared/boards/components/sidebar/_labels.html.haml | 2 | ||||
-rw-r--r-- | changelogs/unreleased/39032-improve-merge-ongoing-check-consistency.yml | 5 | ||||
-rw-r--r-- | changelogs/unreleased/es-module-broadcast_message.yml | 5 | ||||
-rw-r--r-- | lib/gitlab/sidekiq_status.rb | 7 | ||||
-rw-r--r-- | spec/features/boards/sidebar_spec.rb | 32 | ||||
-rw-r--r-- | spec/lib/gitlab/sidekiq_status_spec.rb | 12 | ||||
-rw-r--r-- | spec/models/merge_request_spec.rb | 22 | ||||
-rw-r--r-- | spec/support/board_helpers.rb | 16 |
15 files changed, 220 insertions, 165 deletions
diff --git a/Gemfile.lock b/Gemfile.lock index f5712da7508..b8b8054ad74 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -324,7 +324,7 @@ GEM mime-types (~> 3.0) representable (~> 3.0) retriable (>= 2.0, < 4.0) - google-protobuf (3.4.0.2) + google-protobuf (3.4.1.1) googleauth (0.5.3) faraday (~> 0.12) jwt (~> 1.4) diff --git a/app/assets/javascripts/broadcast_message.js b/app/assets/javascripts/broadcast_message.js index f73e489e7b2..ff88083a4b4 100644 --- a/app/assets/javascripts/broadcast_message.js +++ b/app/assets/javascripts/broadcast_message.js @@ -1,33 +1,28 @@ -/* eslint-disable func-names, space-before-function-paren, prefer-arrow-callback, no-var, quotes, no-else-return, object-shorthand, comma-dangle, max-len */ - -$(function() { - var previewPath; - $('input#broadcast_message_color').on('input', function() { - var previewColor; - previewColor = $(this).val(); - return $('div.broadcast-message-preview').css('background-color', previewColor); +export default function initBroadcastMessagesForm() { + $('input#broadcast_message_color').on('input', function onMessageColorInput() { + const previewColor = $(this).val(); + $('div.broadcast-message-preview').css('background-color', previewColor); }); - $('input#broadcast_message_font').on('input', function() { - var previewColor; - previewColor = $(this).val(); - return $('div.broadcast-message-preview').css('color', previewColor); + + $('input#broadcast_message_font').on('input', function onMessageFontInput() { + const previewColor = $(this).val(); + $('div.broadcast-message-preview').css('color', previewColor); }); - previewPath = $('textarea#broadcast_message_message').data('preview-path'); - return $('textarea#broadcast_message_message').on('input', function() { - var message; - message = $(this).val(); + + const previewPath = $('textarea#broadcast_message_message').data('preview-path'); + + $('textarea#broadcast_message_message').on('input', _.debounce(function onMessageInput() { + const message = $(this).val(); if (message === '') { - return $('.js-broadcast-message-preview').text("Your message here"); + $('.js-broadcast-message-preview').text('Your message here'); } else { - return $.ajax({ + $.ajax({ url: previewPath, - type: "POST", + type: 'POST', data: { - broadcast_message: { - message: message - } - } + broadcast_message: { message }, + }, }); } - }); -}); + }, 250)); +} diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js index 0a653d7fefc..aa6ae7c1e95 100644 --- a/app/assets/javascripts/dispatcher.js +++ b/app/assets/javascripts/dispatcher.js @@ -70,6 +70,7 @@ import initSettingsPanels from './settings_panels'; import initExperimentalFlags from './experimental_flags'; import OAuthRememberMe from './oauth_remember_me'; import PerformanceBar from './performance_bar'; +import initBroadcastMessagesForm from './broadcast_message'; import initNotes from './init_notes'; import initLegacyFilters from './init_legacy_filters'; import initIssuableSidebar from './init_issuable_sidebar'; @@ -83,6 +84,8 @@ import AjaxLoadingSpinner from './ajax_loading_spinner'; import GlFieldErrors from './gl_field_errors'; import GLForm from './gl_form'; import U2FAuthenticate from './u2f/authenticate'; +import Members from './members'; +import memberExpirationDate from './member_expiration_date'; (function() { var Dispatcher; @@ -399,15 +402,15 @@ import U2FAuthenticate from './u2f/authenticate'; new ProjectsList(); break; case 'groups:group_members:index': - new gl.MemberExpirationDate(); - new gl.Members(); + memberExpirationDate(); + new Members(); new UsersSelect(); break; case 'projects:project_members:index': - new gl.MemberExpirationDate('.js-access-expiration-date-groups'); + memberExpirationDate('.js-access-expiration-date-groups'); new GroupsSelect(); - new gl.MemberExpirationDate(); - new gl.Members(); + memberExpirationDate(); + new Members(); new UsersSelect(); break; case 'groups:new': @@ -553,6 +556,9 @@ import U2FAuthenticate from './u2f/authenticate'; case 'admin': new Admin(); switch (path[1]) { + case 'broadcast_messages': + initBroadcastMessagesForm(); + break; case 'cohorts': new UsagePing(); break; diff --git a/app/assets/javascripts/main.js b/app/assets/javascripts/main.js index 35982ff413d..1ac8f83a0c7 100644 --- a/app/assets/javascripts/main.js +++ b/app/assets/javascripts/main.js @@ -53,7 +53,6 @@ import './aside'; import './autosave'; import loadAwardsHandler from './awards_handler'; import bp from './breakpoints'; -import './broadcast_message'; import './commits'; import './compare'; import './compare_autocomplete'; @@ -84,8 +83,6 @@ import './layout_nav'; import LazyLoader from './lazy_loader'; import './line_highlighter'; import './logo'; -import './member_expiration_date'; -import './members'; import './merge_request'; import './merge_request_tabs'; import './milestone'; diff --git a/app/assets/javascripts/member_expiration_date.js b/app/assets/javascripts/member_expiration_date.js index cc9016e74da..26b24fdafda 100644 --- a/app/assets/javascripts/member_expiration_date.js +++ b/app/assets/javascripts/member_expiration_date.js @@ -2,54 +2,51 @@ import Pikaday from 'pikaday'; -(() => { - // Add datepickers to all `js-access-expiration-date` elements. If those elements are - // children of an element with the `clearable-input` class, and have a sibling - // `js-clear-input` element, then show that element when there is a value in the - // datepicker, and make clicking on that element clear the field. - // - window.gl = window.gl || {}; - gl.MemberExpirationDate = (selector = '.js-access-expiration-date') => { - function toggleClearInput() { - $(this).closest('.clearable-input').toggleClass('has-value', $(this).val() !== ''); - } - const inputs = $(selector); - - inputs.each((i, el) => { - const $input = $(el); - - const calendar = new Pikaday({ - field: $input.get(0), - theme: 'gitlab-theme animate-picker', - format: 'yyyy-mm-dd', - minDate: new Date(), - container: $input.parent().get(0), - onSelect(dateText) { - $input.val(dateFormat(new Date(dateText), 'yyyy-mm-dd')); - - $input.trigger('change'); - - toggleClearInput.call($input); - }, - }); - - calendar.setDate(new Date($input.val())); - $input.data('pikaday', calendar); +// Add datepickers to all `js-access-expiration-date` elements. If those elements are +// children of an element with the `clearable-input` class, and have a sibling +// `js-clear-input` element, then show that element when there is a value in the +// datepicker, and make clicking on that element clear the field. +// +export default function memberExpirationDate(selector = '.js-access-expiration-date') { + function toggleClearInput() { + $(this).closest('.clearable-input').toggleClass('has-value', $(this).val() !== ''); + } + const inputs = $(selector); + + inputs.each((i, el) => { + const $input = $(el); + + const calendar = new Pikaday({ + field: $input.get(0), + theme: 'gitlab-theme animate-picker', + format: 'yyyy-mm-dd', + minDate: new Date(), + container: $input.parent().get(0), + onSelect(dateText) { + $input.val(dateFormat(new Date(dateText), 'yyyy-mm-dd')); + + $input.trigger('change'); + + toggleClearInput.call($input); + }, }); - inputs.next('.js-clear-input').on('click', function clicked(event) { - event.preventDefault(); + calendar.setDate(new Date($input.val())); + $input.data('pikaday', calendar); + }); - const input = $(this).closest('.clearable-input').find(selector); - const calendar = input.data('pikaday'); + inputs.next('.js-clear-input').on('click', function clicked(event) { + event.preventDefault(); - calendar.setDate(null); - input.trigger('change'); - toggleClearInput.call(input); - }); + const input = $(this).closest('.clearable-input').find(selector); + const calendar = input.data('pikaday'); + + calendar.setDate(null); + input.trigger('change'); + toggleClearInput.call(input); + }); - inputs.on('blur', toggleClearInput); + inputs.on('blur', toggleClearInput); - inputs.each(toggleClearInput); - }; -}).call(window); + inputs.each(toggleClearInput); +} diff --git a/app/assets/javascripts/members.js b/app/assets/javascripts/members.js index 8291b8c4a70..6264750a4fb 100644 --- a/app/assets/javascripts/members.js +++ b/app/assets/javascripts/members.js @@ -1,81 +1,74 @@ -/* eslint-disable class-methods-use-this */ -(() => { - window.gl = window.gl || {}; - - class Members { - constructor() { - this.addListeners(); - this.initGLDropdown(); - } +export default class Members { + constructor() { + this.addListeners(); + this.initGLDropdown(); + } - addListeners() { - $('.project_member, .group_member').off('ajax:success').on('ajax:success', this.removeRow); - $('.js-member-update-control').off('change').on('change', this.formSubmit.bind(this)); - $('.js-edit-member-form').off('ajax:success').on('ajax:success', this.formSuccess.bind(this)); - gl.utils.disableButtonIfEmptyField('#user_ids', 'input[name=commit]', 'change'); - } + addListeners() { + $('.project_member, .group_member').off('ajax:success').on('ajax:success', this.removeRow); + $('.js-member-update-control').off('change').on('change', this.formSubmit.bind(this)); + $('.js-edit-member-form').off('ajax:success').on('ajax:success', this.formSuccess.bind(this)); + gl.utils.disableButtonIfEmptyField('#user_ids', 'input[name=commit]', 'change'); + } - initGLDropdown() { - $('.js-member-permissions-dropdown').each((i, btn) => { - const $btn = $(btn); + initGLDropdown() { + $('.js-member-permissions-dropdown').each((i, btn) => { + const $btn = $(btn); - $btn.glDropdown({ - selectable: true, - isSelectable(selected, $el) { - return !$el.hasClass('is-active'); - }, - fieldName: $btn.data('field-name'), - id(selected, $el) { - return $el.data('id'); - }, - toggleLabel(selected, $el) { - return $el.text(); - }, - clicked: (options) => { - this.formSubmit(null, options.$el); - }, - }); + $btn.glDropdown({ + selectable: true, + isSelectable(selected, $el) { + return !$el.hasClass('is-active'); + }, + fieldName: $btn.data('field-name'), + id(selected, $el) { + return $el.data('id'); + }, + toggleLabel(selected, $el) { + return $el.text(); + }, + clicked: (options) => { + this.formSubmit(null, options.$el); + }, }); - } - - removeRow(e) { - const $target = $(e.target); + }); + } + // eslint-disable-next-line class-methods-use-this + removeRow(e) { + const $target = $(e.target); - if ($target.hasClass('btn-remove')) { - $target.closest('.member') - .fadeOut(function fadeOutMemberRow() { - $(this).remove(); - }); - } + if ($target.hasClass('btn-remove')) { + $target.closest('.member') + .fadeOut(function fadeOutMemberRow() { + $(this).remove(); + }); } + } - formSubmit(e, $el = null) { - const $this = e ? $(e.currentTarget) : $el; - const { $toggle, $dateInput } = this.getMemberListItems($this); - - $this.closest('form').trigger('submit.rails'); - - $toggle.disable(); - $dateInput.disable(); - } + formSubmit(e, $el = null) { + const $this = e ? $(e.currentTarget) : $el; + const { $toggle, $dateInput } = this.getMemberListItems($this); - formSuccess(e) { - const { $toggle, $dateInput } = this.getMemberListItems($(e.currentTarget).closest('.member')); + $this.closest('form').trigger('submit.rails'); - $toggle.enable(); - $dateInput.enable(); - } + $toggle.disable(); + $dateInput.disable(); + } - getMemberListItems($el) { - const $memberListItem = $el.is('.member') ? $el : $(`#${$el.data('el-id')}`); + formSuccess(e) { + const { $toggle, $dateInput } = this.getMemberListItems($(e.currentTarget).closest('.member')); - return { - $memberListItem, - $toggle: $memberListItem.find('.dropdown-menu-toggle'), - $dateInput: $memberListItem.find('.js-access-expiration-date'), - }; - } + $toggle.enable(); + $dateInput.enable(); } + // eslint-disable-next-line class-methods-use-this + getMemberListItems($el) { + const $memberListItem = $el.is('.member') ? $el : $(`#${$el.data('el-id')}`); - gl.Members = Members; -})(); + return { + $memberListItem, + $toggle: $memberListItem.find('.dropdown-menu-toggle'), + $dateInput: $memberListItem.find('.js-access-expiration-date'), + }; + } +} diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index 972a35dde4d..c3fae16d109 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -396,7 +396,7 @@ class MergeRequest < ActiveRecord::Base end def merge_ongoing? - !!merge_jid && !merged? + !!merge_jid && !merged? && Gitlab::SidekiqStatus.running?(merge_jid) end def closed_without_fork? diff --git a/app/views/shared/boards/components/sidebar/_labels.html.haml b/app/views/shared/boards/components/sidebar/_labels.html.haml index 1f540bdaf93..dfc0f9be321 100644 --- a/app/views/shared/boards/components/sidebar/_labels.html.haml +++ b/app/views/shared/boards/components/sidebar/_labels.html.haml @@ -25,7 +25,7 @@ show_any: "true", project_id: @project&.try(:id), labels: labels_filter_path(false), - namespace_path: @project.try(:namespace).try(:full_path), + namespace_path: @namespace_path, project_path: @project.try(:path) }, ":data-issue-update" => "'#{build_issue_link_base}/' + issue.iid + '.json'" } %span.dropdown-toggle-text diff --git a/changelogs/unreleased/39032-improve-merge-ongoing-check-consistency.yml b/changelogs/unreleased/39032-improve-merge-ongoing-check-consistency.yml new file mode 100644 index 00000000000..361b6af196a --- /dev/null +++ b/changelogs/unreleased/39032-improve-merge-ongoing-check-consistency.yml @@ -0,0 +1,5 @@ +--- +title: Make "merge ongoing" check more consistent +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/es-module-broadcast_message.yml b/changelogs/unreleased/es-module-broadcast_message.yml new file mode 100644 index 00000000000..031bcc449ae --- /dev/null +++ b/changelogs/unreleased/es-module-broadcast_message.yml @@ -0,0 +1,5 @@ +--- +title: Fix unnecessary ajax requests in admin broadcast message form +merge_request: 14853 +author: +type: fixed diff --git a/lib/gitlab/sidekiq_status.rb b/lib/gitlab/sidekiq_status.rb index a0a2769cf9e..a1f689d94d9 100644 --- a/lib/gitlab/sidekiq_status.rb +++ b/lib/gitlab/sidekiq_status.rb @@ -51,6 +51,13 @@ module Gitlab self.num_running(job_ids).zero? end + # Returns true if the given job is running + # + # job_id - The Sidekiq job ID to check. + def self.running?(job_id) + num_running([job_id]) > 0 + end + # Returns the number of jobs that are running. # # job_ids - The Sidekiq job IDs to check. diff --git a/spec/features/boards/sidebar_spec.rb b/spec/features/boards/sidebar_spec.rb index c4817eb947b..4965f803883 100644 --- a/spec/features/boards/sidebar_spec.rb +++ b/spec/features/boards/sidebar_spec.rb @@ -1,6 +1,8 @@ require 'rails_helper' describe 'Issue Boards', :js do + include BoardHelpers + let(:user) { create(:user) } let(:user2) { create(:user) } let(:project) { create(:project, :public) } @@ -309,6 +311,21 @@ describe 'Issue Boards', :js do expect(card).to have_selector('.label', count: 1) expect(card).not_to have_content(stretch.title) end + + it 'creates new label' do + click_card(card) + + page.within('.labels') do + click_link 'Edit' + click_link 'Create new label' + fill_in 'new_label_name', with: 'test label' + first('.suggest-colors-dropdown a').click + click_button 'Create' + wait_for_requests + + expect(page).to have_link 'test label' + end + end end context 'subscription' do @@ -322,19 +339,4 @@ describe 'Issue Boards', :js do end end end - - def click_card(card) - page.within(card) do - first('.card-number').click - end - - wait_for_sidebar - end - - def wait_for_sidebar - # loop until the CSS transition is complete - Timeout.timeout(0.5) do - loop until evaluate_script('$(".right-sidebar").outerWidth()') == 290 - end - end end diff --git a/spec/lib/gitlab/sidekiq_status_spec.rb b/spec/lib/gitlab/sidekiq_status_spec.rb index c2e77ef6b6c..884f27b212c 100644 --- a/spec/lib/gitlab/sidekiq_status_spec.rb +++ b/spec/lib/gitlab/sidekiq_status_spec.rb @@ -39,6 +39,18 @@ describe Gitlab::SidekiqStatus do end end + describe '.running?', :clean_gitlab_redis_shared_state do + it 'returns true if job is running' do + described_class.set('123') + + expect(described_class.running?('123')).to be(true) + end + + it 'returns false if job is not found' do + expect(described_class.running?('123')).to be(false) + end + end + describe '.num_running', :clean_gitlab_redis_shared_state do it 'returns 0 if all jobs have been completed' do expect(described_class.num_running(%w(123))).to eq(0) diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index 17c9f15b021..73e038b61ed 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1460,11 +1460,31 @@ describe MergeRequest do end describe '#merge_ongoing?' do - it 'returns true when merge_id is present and MR is not merged' do + it 'returns true when merge_id, MR is not merged and it has no running job' do merge_request = build_stubbed(:merge_request, state: :open, merge_jid: 'foo') + allow(Gitlab::SidekiqStatus).to receive(:running?).with('foo') { true } expect(merge_request.merge_ongoing?).to be(true) end + + it 'returns false when merge_jid is nil' do + merge_request = build_stubbed(:merge_request, state: :open, merge_jid: nil) + + expect(merge_request.merge_ongoing?).to be(false) + end + + it 'returns false if MR is merged' do + merge_request = build_stubbed(:merge_request, state: :merged, merge_jid: 'foo') + + expect(merge_request.merge_ongoing?).to be(false) + end + + it 'returns false if there is no merge job running' do + merge_request = build_stubbed(:merge_request, state: :open, merge_jid: 'foo') + allow(Gitlab::SidekiqStatus).to receive(:running?).with('foo') { false } + + expect(merge_request.merge_ongoing?).to be(false) + end end describe "#closed_without_fork?" do diff --git a/spec/support/board_helpers.rb b/spec/support/board_helpers.rb new file mode 100644 index 00000000000..507d0432d7f --- /dev/null +++ b/spec/support/board_helpers.rb @@ -0,0 +1,16 @@ +module BoardHelpers + def click_card(card) + within card do + first('.card-number').click + end + + wait_for_sidebar + end + + def wait_for_sidebar + # loop until the CSS transition is complete + Timeout.timeout(0.5) do + loop until evaluate_script('$(".right-sidebar").outerWidth()') == 290 + end + end +end |