summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/dispatcher.js2
-rw-r--r--app/assets/javascripts/issue.js226
-rw-r--r--app/assets/stylesheets/framework/nav.scss2
-rw-r--r--app/views/dashboard/issues.html.haml4
-rw-r--r--changelogs/unreleased/29162-refactor-dropdown-milestone-spec.yml4
-rw-r--r--changelogs/unreleased/es6-class-issue.yml4
-rw-r--r--doc/administration/high_availability/load_balancer.md6
-rw-r--r--features/support/capybara.rb2
-rw-r--r--spec/factories/projects.rb4
-rw-r--r--spec/features/dashboard_issues_spec.rb2
-rw-r--r--spec/features/issues/filtered_search/dropdown_milestone_spec.rb58
-rw-r--r--spec/javascripts/issue_spec.js43
-rw-r--r--spec/support/capybara.rb2
13 files changed, 180 insertions, 179 deletions
diff --git a/app/assets/javascripts/dispatcher.js b/app/assets/javascripts/dispatcher.js
index 546bdc9c8d7..017980271b1 100644
--- a/app/assets/javascripts/dispatcher.js
+++ b/app/assets/javascripts/dispatcher.js
@@ -5,7 +5,6 @@ import PrometheusGraph from './monitoring/prometheus_graph'; // TODO: Maybe Make
/* global ShortcutsNavigation */
/* global Build */
/* global Issuable */
-/* global Issue */
/* global ShortcutsIssuable */
/* global ZenMode */
/* global Milestone */
@@ -35,6 +34,7 @@ import PrometheusGraph from './monitoring/prometheus_graph'; // TODO: Maybe Make
/* global ProjectShow */
/* global Labels */
/* global Shortcuts */
+import Issue from './issue';
import BindInOut from './behaviors/bind_in_out';
import GroupsList from './groups_list';
diff --git a/app/assets/javascripts/issue.js b/app/assets/javascripts/issue.js
index 52457f70d90..ef4029a8623 100644
--- a/app/assets/javascripts/issue.js
+++ b/app/assets/javascripts/issue.js
@@ -5,131 +5,125 @@ require('./flash');
require('vendor/jquery.waitforimages');
require('./task_list');
-(function() {
- var bind = function(fn, me) { return function() { return fn.apply(me, arguments); }; };
-
- this.Issue = (function() {
- function Issue() {
- this.submitNoteForm = bind(this.submitNoteForm, this);
- if ($('a.btn-close').length) {
- this.taskList = new gl.TaskList({
- dataType: 'issue',
- fieldName: 'description',
- selector: '.detail-page-description',
- onSuccess: (result) => {
- document.querySelector('#task_status').innerText = result.task_status;
- document.querySelector('#task_status_short').innerText = result.task_status_short;
- }
- });
- this.initIssueBtnEventListeners();
- }
- this.initMergeRequests();
- this.initRelatedBranches();
- this.initCanCreateBranch();
+class Issue {
+ constructor() {
+ if ($('a.btn-close').length) {
+ this.taskList = new gl.TaskList({
+ dataType: 'issue',
+ fieldName: 'description',
+ selector: '.detail-page-description',
+ onSuccess: (result) => {
+ document.querySelector('#task_status').innerText = result.task_status;
+ document.querySelector('#task_status_short').innerText = result.task_status_short;
+ }
+ });
+ Issue.initIssueBtnEventListeners();
}
+ Issue.initMergeRequests();
+ Issue.initRelatedBranches();
+ Issue.initCanCreateBranch();
+ }
- Issue.prototype.initIssueBtnEventListeners = function() {
- var _this, issueFailMessage;
- _this = this;
- issueFailMessage = 'Unable to update this issue at this time.';
- return $('a.btn-close, a.btn-reopen').on('click', function(e) {
- var $this, isClose, shouldSubmit, url;
- e.preventDefault();
- e.stopImmediatePropagation();
- $this = $(this);
- isClose = $this.hasClass('btn-close');
- shouldSubmit = $this.hasClass('btn-comment');
- if (shouldSubmit) {
- _this.submitNoteForm($this.closest('form'));
- }
- $this.prop('disabled', true);
- url = $this.attr('href');
- return $.ajax({
- type: 'PUT',
- url: url,
- error: function(jqXHR, textStatus, errorThrown) {
- var issueStatus;
- issueStatus = isClose ? 'close' : 'open';
- return new Flash(issueFailMessage, 'alert');
- },
- success: function(data, textStatus, jqXHR) {
- if ('id' in data) {
- $(document).trigger('issuable:change');
- const currentTotal = Number($('.issue_counter').text());
- if (isClose) {
- $('a.btn-close').addClass('hidden');
- $('a.btn-reopen').removeClass('hidden');
- $('div.status-box-closed').removeClass('hidden');
- $('div.status-box-open').addClass('hidden');
- $('.issue_counter').text(currentTotal - 1);
- } else {
- $('a.btn-reopen').addClass('hidden');
- $('a.btn-close').removeClass('hidden');
- $('div.status-box-closed').addClass('hidden');
- $('div.status-box-open').removeClass('hidden');
- $('.issue_counter').text(currentTotal + 1);
- }
+ static initIssueBtnEventListeners() {
+ var issueFailMessage;
+ issueFailMessage = 'Unable to update this issue at this time.';
+ return $('a.btn-close, a.btn-reopen').on('click', function(e) {
+ var $this, isClose, shouldSubmit, url;
+ e.preventDefault();
+ e.stopImmediatePropagation();
+ $this = $(this);
+ isClose = $this.hasClass('btn-close');
+ shouldSubmit = $this.hasClass('btn-comment');
+ if (shouldSubmit) {
+ Issue.submitNoteForm($this.closest('form'));
+ }
+ $this.prop('disabled', true);
+ url = $this.attr('href');
+ return $.ajax({
+ type: 'PUT',
+ url: url,
+ error: function(jqXHR, textStatus, errorThrown) {
+ var issueStatus;
+ issueStatus = isClose ? 'close' : 'open';
+ return new Flash(issueFailMessage, 'alert');
+ },
+ success: function(data, textStatus, jqXHR) {
+ if ('id' in data) {
+ $(document).trigger('issuable:change');
+ const currentTotal = Number($('.issue_counter').text());
+ if (isClose) {
+ $('a.btn-close').addClass('hidden');
+ $('a.btn-reopen').removeClass('hidden');
+ $('div.status-box-closed').removeClass('hidden');
+ $('div.status-box-open').addClass('hidden');
+ $('.issue_counter').text(currentTotal - 1);
} else {
- new Flash(issueFailMessage, 'alert');
+ $('a.btn-reopen').addClass('hidden');
+ $('a.btn-close').removeClass('hidden');
+ $('div.status-box-closed').addClass('hidden');
+ $('div.status-box-open').removeClass('hidden');
+ $('.issue_counter').text(currentTotal + 1);
}
- return $this.prop('disabled', false);
+ } else {
+ new Flash(issueFailMessage, 'alert');
}
- });
+ return $this.prop('disabled', false);
+ }
});
- };
+ });
+ }
- Issue.prototype.submitNoteForm = function(form) {
- var noteText;
- noteText = form.find("textarea.js-note-text").val();
- if (noteText.trim().length > 0) {
- return form.submit();
- }
- };
+ static submitNoteForm(form) {
+ var noteText;
+ noteText = form.find("textarea.js-note-text").val();
+ if (noteText.trim().length > 0) {
+ return form.submit();
+ }
+ }
- Issue.prototype.initMergeRequests = function() {
- var $container;
- $container = $('#merge-requests');
- return $.getJSON($container.data('url')).error(function() {
- return new Flash('Failed to load referenced merge requests', 'alert');
- }).success(function(data) {
- if ('html' in data) {
- return $container.html(data.html);
- }
- });
- };
+ static initMergeRequests() {
+ var $container;
+ $container = $('#merge-requests');
+ return $.getJSON($container.data('url')).error(function() {
+ return new Flash('Failed to load referenced merge requests', 'alert');
+ }).success(function(data) {
+ if ('html' in data) {
+ return $container.html(data.html);
+ }
+ });
+ }
- Issue.prototype.initRelatedBranches = function() {
- var $container;
- $container = $('#related-branches');
- return $.getJSON($container.data('url')).error(function() {
- return new Flash('Failed to load related branches', 'alert');
- }).success(function(data) {
- if ('html' in data) {
- return $container.html(data.html);
- }
- });
- };
+ static initRelatedBranches() {
+ var $container;
+ $container = $('#related-branches');
+ return $.getJSON($container.data('url')).error(function() {
+ return new Flash('Failed to load related branches', 'alert');
+ }).success(function(data) {
+ if ('html' in data) {
+ return $container.html(data.html);
+ }
+ });
+ }
- Issue.prototype.initCanCreateBranch = function() {
- var $container;
- $container = $('#new-branch');
- // If the user doesn't have the required permissions the container isn't
- // rendered at all.
- if ($container.length === 0) {
- return;
+ static initCanCreateBranch() {
+ var $container;
+ $container = $('#new-branch');
+ // If the user doesn't have the required permissions the container isn't
+ // rendered at all.
+ if ($container.length === 0) {
+ return;
+ }
+ return $.getJSON($container.data('path')).error(function() {
+ $container.find('.unavailable').show();
+ return new Flash('Failed to check if a new branch can be created.', 'alert');
+ }).success(function(data) {
+ if (data.can_create_branch) {
+ $container.find('.available').show();
+ } else {
+ return $container.find('.unavailable').show();
}
- return $.getJSON($container.data('path')).error(function() {
- $container.find('.unavailable').show();
- return new Flash('Failed to check if a new branch can be created.', 'alert');
- }).success(function(data) {
- if (data.can_create_branch) {
- $container.find('.available').show();
- } else {
- return $container.find('.unavailable').show();
- }
- });
- };
+ });
+ }
+}
- return Issue;
- })();
-}).call(window);
+export default Issue;
diff --git a/app/assets/stylesheets/framework/nav.scss b/app/assets/stylesheets/framework/nav.scss
index 674d3bb45aa..ea45aaa0253 100644
--- a/app/assets/stylesheets/framework/nav.scss
+++ b/app/assets/stylesheets/framework/nav.scss
@@ -294,7 +294,7 @@
.nav-control {
@media (max-width: $screen-sm-max) {
- margin-right: 75px;
+ margin-right: 2px;
}
}
}
diff --git a/app/views/dashboard/issues.html.haml b/app/views/dashboard/issues.html.haml
index 9a4e423f896..10867140d4f 100644
--- a/app/views/dashboard/issues.html.haml
+++ b/app/views/dashboard/issues.html.haml
@@ -6,10 +6,8 @@
.top-area
= render 'shared/issuable/nav', type: :issues
.nav-controls
- = link_to params.merge(rss_url_options), class: 'btn' do
+ = link_to params.merge(rss_url_options), class: 'btn has-tooltip', title: 'Subscribe' do
= icon('rss')
- %span.icon-label
- Subscribe
= render 'shared/new_project_item_select', path: 'issues/new', label: "New Issue"
= render 'shared/issuable/filter', type: :issues
diff --git a/changelogs/unreleased/29162-refactor-dropdown-milestone-spec.yml b/changelogs/unreleased/29162-refactor-dropdown-milestone-spec.yml
new file mode 100644
index 00000000000..ad0c513f525
--- /dev/null
+++ b/changelogs/unreleased/29162-refactor-dropdown-milestone-spec.yml
@@ -0,0 +1,4 @@
+---
+title: Refactor dropdown_milestone_spec.rb
+merge_request:
+author: George Andrinopoulos
diff --git a/changelogs/unreleased/es6-class-issue.yml b/changelogs/unreleased/es6-class-issue.yml
new file mode 100644
index 00000000000..9d1c3ac7421
--- /dev/null
+++ b/changelogs/unreleased/es6-class-issue.yml
@@ -0,0 +1,4 @@
+---
+title: Convert Issue into ES6 class
+merge_request: 9636
+author: winniehell
diff --git a/doc/administration/high_availability/load_balancer.md b/doc/administration/high_availability/load_balancer.md
index dad8e956c0e..3245988fc14 100644
--- a/doc/administration/high_availability/load_balancer.md
+++ b/doc/administration/high_availability/load_balancer.md
@@ -19,8 +19,8 @@ you need to use with GitLab.
## GitLab Pages Ports
If you're using GitLab Pages you will need some additional port configurations.
-GitLab Pages requires a separate VIP. Configure DNS to point the
-`pages_external_url` from `/etc/gitlab/gitlab.rb` at the new VIP. See the
+GitLab Pages requires a separate virtual IP address. Configure DNS to point the
+`pages_external_url` from `/etc/gitlab/gitlab.rb` at the new virtual IP address. See the
[GitLab Pages documentation][gitlab-pages] for more information.
| LB Port | Backend Port | Protocol |
@@ -32,7 +32,7 @@ GitLab Pages requires a separate VIP. Configure DNS to point the
Some organizations have policies against opening SSH port 22. In this case,
it may be helpful to configure an alternate SSH hostname that allows users
-to use SSH on port 443. An alternate SSH hostname will require a new VIP
+to use SSH on port 443. An alternate SSH hostname will require a new virtual IP address
compared to the other GitLab HTTP configuration above.
Configure DNS for an alternate SSH hostname such as altssh.gitlab.example.com.
diff --git a/features/support/capybara.rb b/features/support/capybara.rb
index 47372df152d..a5fcbb65131 100644
--- a/features/support/capybara.rb
+++ b/features/support/capybara.rb
@@ -2,7 +2,7 @@ require 'spinach/capybara'
require 'capybara/poltergeist'
# Give CI some extra time
-timeout = (ENV['CI'] || ENV['CI_SERVER']) ? 90 : 15
+timeout = (ENV['CI'] || ENV['CI_SERVER']) ? 30 : 10
Capybara.javascript_driver = :poltergeist
Capybara.register_driver :poltergeist do |app|
diff --git a/spec/factories/projects.rb b/spec/factories/projects.rb
index c6f91e05d83..0db2fe04edd 100644
--- a/spec/factories/projects.rb
+++ b/spec/factories/projects.rb
@@ -38,7 +38,7 @@ FactoryGirl.define do
trait :empty_repo do
after(:create) do |project|
- project.create_repository
+ raise "Failed to create repository!" unless project.create_repository
# We delete hooks so that gitlab-shell will not try to authenticate with
# an API that isn't running
@@ -48,7 +48,7 @@ FactoryGirl.define do
trait :broken_repo do
after(:create) do |project|
- project.create_repository
+ raise "Failed to create repository!" unless project.create_repository
FileUtils.rm_r(File.join(project.repository_storage_path, "#{project.path_with_namespace}.git", 'refs'))
end
diff --git a/spec/features/dashboard_issues_spec.rb b/spec/features/dashboard_issues_spec.rb
index aa75e1140f6..8c61cdebc4b 100644
--- a/spec/features/dashboard_issues_spec.rb
+++ b/spec/features/dashboard_issues_spec.rb
@@ -48,7 +48,7 @@ describe "Dashboard Issues filtering", feature: true, js: true do
it 'updates atom feed link' do
visit_issues(milestone_title: '', assignee_id: user.id)
- link = find('.nav-controls a', text: 'Subscribe')
+ link = find('.nav-controls a[title="Subscribe"]')
params = CGI.parse(URI.parse(link[:href]).query)
auto_discovery_link = find('link[type="application/atom+xml"]', visible: false)
auto_discovery_params = CGI.parse(URI.parse(auto_discovery_link[:href]).query)
diff --git a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
index 0324fcad0a0..85ffffe4b6d 100644
--- a/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
+++ b/spec/features/issues/filtered_search/dropdown_milestone_spec.rb
@@ -1,8 +1,7 @@
require 'rails_helper'
-describe 'Dropdown milestone', js: true, feature: true do
+describe 'Dropdown milestone', :feature, :js do
include FilteredSearchHelpers
- include WaitForAjax
let!(:project) { create(:empty_project) }
let!(:user) { create(:user) }
@@ -15,18 +14,10 @@ describe 'Dropdown milestone', js: true, feature: true do
let(:filtered_search) { find('.filtered-search') }
let(:js_dropdown_milestone) { '#js-dropdown-milestone' }
-
- def send_keys_to_filtered_search(input)
- input.split("").each do |i|
- filtered_search.send_keys(i)
- sleep 3
- wait_for_ajax
- sleep 3
- end
- end
+ let(:filter_dropdown) { find("#{js_dropdown_milestone} .filter-dropdown") }
def dropdown_milestone_size
- page.all('#js-dropdown-milestone .filter-dropdown .filter-dropdown-item').size
+ filter_dropdown.all('.filter-dropdown-item').size
end
def click_milestone(text)
@@ -65,13 +56,14 @@ describe 'Dropdown milestone', js: true, feature: true do
end
it 'should hide loading indicator when loaded' do
- send_keys_to_filtered_search('milestone:')
+ filtered_search.set('milestone:')
- expect(page).not_to have_css('#js-dropdown-milestone .filter-dropdown-loading')
+ expect(find(js_dropdown_milestone)).to have_css('.filter-dropdown-loading')
+ expect(find(js_dropdown_milestone)).not_to have_css('.filter-dropdown-loading')
end
it 'should load all the milestones when opened' do
- send_keys_to_filtered_search('milestone:')
+ filtered_search.set('milestone:')
expect(dropdown_milestone_size).to be > 0
end
@@ -79,41 +71,48 @@ describe 'Dropdown milestone', js: true, feature: true do
describe 'filtering' do
before do
- filtered_search.set('milestone')
+ filtered_search.set('milestone:')
+
+ expect(find("#{js_dropdown_milestone} .filter-dropdown")).to have_content(milestone.title)
+ expect(find("#{js_dropdown_milestone} .filter-dropdown")).to have_content(uppercase_milestone.title)
+ expect(find("#{js_dropdown_milestone} .filter-dropdown")).to have_content(two_words_milestone.title)
+ expect(find("#{js_dropdown_milestone} .filter-dropdown")).to have_content(wont_fix_milestone.title)
+ expect(find("#{js_dropdown_milestone} .filter-dropdown")).to have_content(special_milestone.title)
+ expect(find("#{js_dropdown_milestone} .filter-dropdown")).to have_content(long_milestone.title)
end
it 'filters by name' do
- send_keys_to_filtered_search(':v1')
+ filtered_search.send_keys('v1')
expect(dropdown_milestone_size).to eq(1)
end
it 'filters by case insensitive name' do
- send_keys_to_filtered_search(':V1')
+ filtered_search.send_keys('V1')
expect(dropdown_milestone_size).to eq(1)
end
it 'filters by name with symbol' do
- send_keys_to_filtered_search(':%v1')
+ filtered_search.send_keys('%v1')
expect(dropdown_milestone_size).to eq(1)
end
it 'filters by case insensitive name with symbol' do
- send_keys_to_filtered_search(':%V1')
+ filtered_search.send_keys('%V1')
expect(dropdown_milestone_size).to eq(1)
end
it 'filters by special characters' do
- send_keys_to_filtered_search(':(+')
+ filtered_search.send_keys('(+')
expect(dropdown_milestone_size).to eq(1)
end
it 'filters by special characters with symbol' do
- send_keys_to_filtered_search(':%(+')
+ filtered_search.send_keys('%(+')
expect(dropdown_milestone_size).to eq(1)
end
@@ -122,6 +121,13 @@ describe 'Dropdown milestone', js: true, feature: true do
describe 'selecting from dropdown' do
before do
filtered_search.set('milestone:')
+
+ expect(find("#{js_dropdown_milestone} .filter-dropdown")).to have_content(milestone.title)
+ expect(find("#{js_dropdown_milestone} .filter-dropdown")).to have_content(uppercase_milestone.title)
+ expect(find("#{js_dropdown_milestone} .filter-dropdown")).to have_content(two_words_milestone.title)
+ expect(find("#{js_dropdown_milestone} .filter-dropdown")).to have_content(wont_fix_milestone.title)
+ expect(find("#{js_dropdown_milestone} .filter-dropdown")).to have_content(special_milestone.title)
+ expect(find("#{js_dropdown_milestone} .filter-dropdown")).to have_content(long_milestone.title)
end
it 'fills in the milestone name when the milestone has not been filled' do
@@ -133,7 +139,7 @@ describe 'Dropdown milestone', js: true, feature: true do
end
it 'fills in the milestone name when the milestone is partially filled' do
- send_keys_to_filtered_search('v')
+ filtered_search.send_keys('v')
click_milestone(milestone.title)
expect(page).to have_css(js_dropdown_milestone, visible: false)
@@ -232,16 +238,14 @@ describe 'Dropdown milestone', js: true, feature: true do
describe 'caching requests' do
it 'caches requests after the first load' do
- filtered_search.set('milestone')
- send_keys_to_filtered_search(':')
+ filtered_search.set('milestone:')
initial_size = dropdown_milestone_size
expect(initial_size).to be > 0
create(:milestone, project: project)
find('.filtered-search-input-container .clear-search').click
- filtered_search.set('milestone')
- send_keys_to_filtered_search(':')
+ filtered_search.set('milestone:')
expect(dropdown_milestone_size).to eq(initial_size)
end
diff --git a/spec/javascripts/issue_spec.js b/spec/javascripts/issue_spec.js
index e7530f61385..8d25500b9fd 100644
--- a/spec/javascripts/issue_spec.js
+++ b/spec/javascripts/issue_spec.js
@@ -1,10 +1,9 @@
/* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-use-before-define, comma-dangle, max-len */
-/* global Issue */
+import Issue from '~/issue';
require('~/lib/utils/text_utility');
-require('~/issue');
-(function() {
+describe('Issue', function() {
var INVALID_URL = 'http://goesnowhere.nothing/whereami';
var $boxClosed, $boxOpen, $btnClose, $btnReopen;
@@ -59,28 +58,26 @@ require('~/issue');
expect($btnReopen).toHaveText('Reopen issue');
}
- describe('Issue', function() {
- describe('task lists', function() {
- beforeEach(function() {
- loadFixtures('issues/issue-with-task-list.html.raw');
- this.issue = new Issue();
- });
-
- it('modifies the Markdown field', function() {
- spyOn(jQuery, 'ajax').and.stub();
- $('input[type=checkbox]').attr('checked', true).trigger('change');
- expect($('.js-task-list-field').val()).toBe('- [x] Task List Item');
- });
+ describe('task lists', function() {
+ beforeEach(function() {
+ loadFixtures('issues/issue-with-task-list.html.raw');
+ this.issue = new Issue();
+ });
- it('submits an ajax request on tasklist:changed', function() {
- spyOn(jQuery, 'ajax').and.callFake(function(req) {
- expect(req.type).toBe('PATCH');
- expect(req.url).toBe(gl.TEST_HOST + '/frontend-fixtures/issues-project/issues/1.json'); // eslint-disable-line prefer-template
- expect(req.data.issue.description).not.toBe(null);
- });
+ it('modifies the Markdown field', function() {
+ spyOn(jQuery, 'ajax').and.stub();
+ $('input[type=checkbox]').attr('checked', true).trigger('change');
+ expect($('.js-task-list-field').val()).toBe('- [x] Task List Item');
+ });
- $('.js-task-list-field').trigger('tasklist:changed');
+ it('submits an ajax request on tasklist:changed', function() {
+ spyOn(jQuery, 'ajax').and.callFake(function(req) {
+ expect(req.type).toBe('PATCH');
+ expect(req.url).toBe(gl.TEST_HOST + '/frontend-fixtures/issues-project/issues/1.json'); // eslint-disable-line prefer-template
+ expect(req.data.issue.description).not.toBe(null);
});
+
+ $('.js-task-list-field').trigger('tasklist:changed');
});
});
@@ -165,4 +162,4 @@ require('~/issue');
expect($('.issue_counter')).toHaveText(1);
});
});
-}).call(window);
+});
diff --git a/spec/support/capybara.rb b/spec/support/capybara.rb
index 16d5f2bf0b8..62740ec29fd 100644
--- a/spec/support/capybara.rb
+++ b/spec/support/capybara.rb
@@ -3,7 +3,7 @@ require 'capybara/rspec'
require 'capybara/poltergeist'
# Give CI some extra time
-timeout = (ENV['CI'] || ENV['CI_SERVER']) ? 90 : 10
+timeout = (ENV['CI'] || ENV['CI_SERVER']) ? 30 : 10
Capybara.javascript_driver = :poltergeist
Capybara.register_driver :poltergeist do |app|