summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG4
-rw-r--r--app/assets/javascripts/application.js6
-rw-r--r--app/assets/javascripts/gl_dropdown.js42
-rw-r--r--app/assets/javascripts/lib/utils/datetime_utility.js38
-rw-r--r--app/assets/javascripts/project.js10
-rw-r--r--app/helpers/application_helper.rb8
-rw-r--r--app/views/projects/ci/pipelines/_pipeline.html.haml2
-rw-r--r--doc/api/repository_files.md16
-rw-r--r--spec/features/projects/ref_switcher_spec.rb29
-rw-r--r--spec/helpers/application_helper_spec.rb17
-rw-r--r--spec/javascripts/datetime_utility_spec.js.coffee31
11 files changed, 175 insertions, 28 deletions
diff --git a/CHANGELOG b/CHANGELOG
index 5f4a3294e67..48235e2c1f7 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -20,6 +20,7 @@ v 8.11.0 (unreleased)
- Add "No one can push" as an option for protected branches. !5081
- Improve performance of AutolinkFilter#text_parse by using XPath
- Environments have an url to link to
+ - Update `timeago` plugin to use multiple string/locale settings
- Remove unused images (ClemMakesApps)
- Limit git rev-list output count to one in forced push check
- Clean up unused routes (Josef Strzibny)
@@ -168,6 +169,9 @@ v 8.10.0
- Fix check for New Branch button on Issue page. !4630 (winniehell)
- Fix GFM autocomplete not working on wiki pages
- Fixed enter key not triggering click on first row when searching in a dropdown
+ - Updated dropdowns in issuable form to use new GitLab dropdown style
+ - Make images fit to the size of the viewport !4810
+ - Fix check for New Branch button on Issue page !4630 (winniehell)
- Fix MR-auto-close text added to description. !4836
- Support U2F devices in Firefox. !5177
- Fix issue, preventing users w/o push access to sort tags. !5105 (redetection)
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 127e568adc9..f1aab067351 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -287,7 +287,7 @@
$('.page-with-sidebar').toggleClass('page-sidebar-collapsed page-sidebar-expanded').removeClass('page-sidebar-pinned');
$('.navbar-fixed-top').removeClass('header-pinned-nav');
}
- return $document.off('click', '.js-nav-pin').on('click', '.js-nav-pin', function(e) {
+ $document.off('click', '.js-nav-pin').on('click', '.js-nav-pin', function(e) {
var $page, $pinBtn, $tooltip, $topNav, doPinNav, tooltipText;
e.preventDefault();
$pinBtn = $(e.currentTarget);
@@ -315,6 +315,8 @@
$tooltip.find('.tooltip-inner').text(tooltipText);
return $pinBtn.attr('title', tooltipText).tooltip('fixTitle');
});
- });
+ // Custom time ago
+ gl.utils.shortTimeAgo($('.js-short-timeago'));
+ });
}).call(this);
diff --git a/app/assets/javascripts/gl_dropdown.js b/app/assets/javascripts/gl_dropdown.js
index c5d92831fbe..cc7e422fd89 100644
--- a/app/assets/javascripts/gl_dropdown.js
+++ b/app/assets/javascripts/gl_dropdown.js
@@ -28,38 +28,43 @@
};
})(this));
timeout = "";
- this.input.on("keyup", (function(_this) {
- return function(e) {
+ this.input
+ .on('keydown', function (e) {
+ var keyCode = e.which;
+
+ if (keyCode === 13) {
+ e.preventDefault()
+ }
+ })
+ .on('keyup', function(e) {
var keyCode;
keyCode = e.which;
if (ARROW_KEY_CODES.indexOf(keyCode) >= 0) {
return;
}
- if (_this.input.val() !== "" && !$inputContainer.hasClass(HAS_VALUE_CLASS)) {
+ if (this.input.val() !== "" && !$inputContainer.hasClass(HAS_VALUE_CLASS)) {
$inputContainer.addClass(HAS_VALUE_CLASS);
- } else if (_this.input.val() === "" && $inputContainer.hasClass(HAS_VALUE_CLASS)) {
+ } else if (this.input.val() === "" && $inputContainer.hasClass(HAS_VALUE_CLASS)) {
$inputContainer.removeClass(HAS_VALUE_CLASS);
}
if (keyCode === 13) {
return false;
}
- if (_this.options.remote) {
+ if (this.options.remote) {
clearTimeout(timeout);
return timeout = setTimeout(function() {
- var blur_field;
- blur_field = _this.shouldBlur(keyCode);
- if (blur_field && _this.filterInputBlur) {
- _this.input.blur();
+ var blurField = this.shouldBlur(keyCode);
+ if (blurField && this.filterInputBlur) {
+ this.input.blur();
}
- return _this.options.query(_this.input.val(), function(data) {
- return _this.options.callback(data);
- });
- }, 250);
+ return this.options.query(this.input.val(), function(data) {
+ return this.options.callback(data);
+ }.bind(this));
+ }.bind(this), 250);
} else {
- return _this.filter(_this.input.val());
+ return this.filter(this.input.val());
}
- };
- })(this));
+ }.bind(this));
}
GitLabDropdownFilter.prototype.shouldBlur = function(keyCode) {
@@ -382,6 +387,7 @@
GitLabDropdown.prototype.opened = function() {
var contentHtml;
+ currentIndex = -1;
this.addArrowKeyEvent();
if (this.options.setIndeterminateIds) {
this.options.setIndeterminateIds.call(this);
@@ -619,7 +625,7 @@
var $input, ARROW_KEY_CODES, selector;
ARROW_KEY_CODES = [38, 40];
$input = this.dropdown.find(".dropdown-input-field");
- selector = '.dropdown-content li:not(.divider,.dropdown-header,.separator)';
+ selector = '.dropdown-content li:not(.divider,.dropdown-header,.separator):visible';
if (this.dropdown.find(".dropdown-toggle-page").length) {
selector = ".dropdown-page-one " + selector;
}
@@ -647,7 +653,7 @@
return false;
}
if (currentKeyCode === 13 && currentIndex !== -1) {
- return _this.selectRowAtIndex(e, currentIndex);
+ return _this.selectRowAtIndex(e, $('.is-focused', _this.dropdown).closest('li').index() - 1);
}
};
})(this));
diff --git a/app/assets/javascripts/lib/utils/datetime_utility.js b/app/assets/javascripts/lib/utils/datetime_utility.js
index e817261f210..10afa7e4329 100644
--- a/app/assets/javascripts/lib/utils/datetime_utility.js
+++ b/app/assets/javascripts/lib/utils/datetime_utility.js
@@ -8,13 +8,16 @@
base.utils = {};
}
w.gl.utils.days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'];
+
w.gl.utils.formatDate = function(datetime) {
return dateFormat(datetime, 'mmm d, yyyy h:MMtt Z');
};
+
w.gl.utils.getDayName = function(date) {
return this.days[date.getDay()];
};
- return w.gl.utils.localTimeAgo = function($timeagoEls, setTimeago) {
+
+ w.gl.utils.localTimeAgo = function($timeagoEls, setTimeago) {
if (setTimeago == null) {
setTimeago = true;
}
@@ -31,6 +34,39 @@
});
}
};
+
+ w.gl.utils.shortTimeAgo = function($el) {
+ var shortLocale, tmpLocale;
+ shortLocale = {
+ prefixAgo: null,
+ prefixFromNow: null,
+ suffixAgo: 'ago',
+ suffixFromNow: 'from now',
+ seconds: '1 min',
+ minute: '1 min',
+ minutes: '%d mins',
+ hour: '1 hr',
+ hours: '%d hrs',
+ day: '1 day',
+ days: '%d days',
+ month: '1 month',
+ months: '%d months',
+ year: '1 year',
+ years: '%d years',
+ wordSeparator: ' ',
+ numbers: []
+ };
+ tmpLocale = $.timeago.settings.strings;
+ $el.each(function(el) {
+ var $el1;
+ $el1 = $(this);
+ return $el1.attr('title', gl.utils.formatDate($el.attr('datetime')));
+ });
+ $.timeago.settings.strings = shortLocale;
+ $el.timeago();
+ $.timeago.settings.strings = tmpLocale;
+ };
+
})(window);
}).call(this);
diff --git a/app/assets/javascripts/project.js b/app/assets/javascripts/project.js
index e6663177161..b97f6d22715 100644
--- a/app/assets/javascripts/project.js
+++ b/app/assets/javascripts/project.js
@@ -89,8 +89,14 @@
toggleLabel: function(obj, $el) {
return $el.text().trim();
},
- clicked: function(e) {
- return $dropdown.closest('form').submit();
+ clicked: function(selected, $el, e) {
+ e.preventDefault()
+ if ($('input[name="ref"]').length) {
+ var $form = $dropdown.closest('form'),
+ action = $form.attr('action'),
+ divider = action.indexOf('?') < 0 ? '?' : '&';
+ Turbolinks.visit(action + '' + divider + '' + $form.serialize());
+ }
}
});
});
diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb
index 50de93d4bdf..c3613bc67dd 100644
--- a/app/helpers/application_helper.rb
+++ b/app/helpers/application_helper.rb
@@ -163,9 +163,13 @@ module ApplicationHelper
# `html_class` argument is provided.
#
# Returns an HTML-safe String
- def time_ago_with_tooltip(time, placement: 'top', html_class: 'time_ago', skip_js: false)
+ def time_ago_with_tooltip(time, placement: 'top', html_class: '', skip_js: false, short_format: false)
+ css_classes = short_format ? 'js-short-timeago' : 'js-timeago'
+ css_classes << " #{html_class}" unless html_class.blank?
+ css_classes << ' js-timeago-pending' unless skip_js
+
element = content_tag :time, time.to_s,
- class: "#{html_class} js-timeago #{"js-timeago-pending" unless skip_js}",
+ class: css_classes,
datetime: time.to_time.getutc.iso8601,
title: time.to_time.in_time_zone.to_s(:medium),
data: { toggle: 'tooltip', placement: placement, container: 'body' }
diff --git a/app/views/projects/ci/pipelines/_pipeline.html.haml b/app/views/projects/ci/pipelines/_pipeline.html.haml
index 558c35553da..9a594877803 100644
--- a/app/views/projects/ci/pipelines/_pipeline.html.haml
+++ b/app/views/projects/ci/pipelines/_pipeline.html.haml
@@ -53,7 +53,7 @@
- if pipeline.finished_at
%p.finished-at
= icon("calendar")
- #{time_ago_with_tooltip(pipeline.finished_at)}
+ #{time_ago_with_tooltip(pipeline.finished_at, short_format: true, skip_js: true)}
%td.pipeline-actions
.controls.hidden-xs.pull-right
diff --git a/doc/api/repository_files.md b/doc/api/repository_files.md
index 623063f357b..1b8ee88b4ed 100644
--- a/doc/api/repository_files.md
+++ b/doc/api/repository_files.md
@@ -12,6 +12,10 @@ Allows you to receive information about file in repository like name, size, cont
GET /projects/:id/repository/files
```
+```bash
+curl -X GET -H 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v3/projects/13083/repository/files?file_path=app/models/key.rb&ref=master'
+```
+
Example response:
```json
@@ -39,6 +43,10 @@ Parameters:
POST /projects/:id/repository/files
```
+```bash
+curl -X POST -H 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v3/projects/13083/repository/files?file_path=app/project.rb&branch_name=master&content=some%20content&commit_message=create%20a%20new%20file'
+```
+
Example response:
```json
@@ -62,6 +70,10 @@ Parameters:
PUT /projects/:id/repository/files
```
+```bash
+curl -X PUT -H 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v3/projects/13083/repository/files?file_path=app/project.rb&branch_name=master&content=some%20other%20content&commit_message=update%20file'
+```
+
Example response:
```json
@@ -94,6 +106,10 @@ Currently gitlab-shell has a boolean return code, preventing GitLab from specify
DELETE /projects/:id/repository/files
```
+```bash
+curl -X PUT -H 'PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK' 'https://gitlab.example.com/api/v3/projects/13083/repository/files?file_path=app/project.rb&branch_name=master&commit_message=delete%20file'
+```
+
Example response:
```json
diff --git a/spec/features/projects/ref_switcher_spec.rb b/spec/features/projects/ref_switcher_spec.rb
new file mode 100644
index 00000000000..b3ba40b35af
--- /dev/null
+++ b/spec/features/projects/ref_switcher_spec.rb
@@ -0,0 +1,29 @@
+require 'rails_helper'
+
+feature 'Ref switcher', feature: true, js: true do
+ include WaitForAjax
+ let(:user) { create(:user) }
+ let(:project) { create(:project, :public) }
+
+ before do
+ project.team << [user, :master]
+ login_as(user)
+ visit namespace_project_tree_path(project.namespace, project, 'master')
+ end
+
+ it 'allow user to change ref by enter key' do
+ click_button 'master'
+ wait_for_ajax
+
+ page.within '.project-refs-form' do
+ input = find('input[type="search"]')
+ input.set 'expand'
+
+ input.native.send_keys :down
+ input.native.send_keys :down
+ input.native.send_keys :enter
+
+ expect(page).to have_content 'expand-collapse-files'
+ end
+ end
+end
diff --git a/spec/helpers/application_helper_spec.rb b/spec/helpers/application_helper_spec.rb
index bb28866f010..3e15a137e33 100644
--- a/spec/helpers/application_helper_spec.rb
+++ b/spec/helpers/application_helper_spec.rb
@@ -218,12 +218,12 @@ describe ApplicationHelper do
end
it 'includes a default js-timeago class' do
- expect(element.attr('class')).to eq 'time_ago js-timeago js-timeago-pending'
+ expect(element.attr('class')).to eq 'js-timeago js-timeago-pending'
end
it 'accepts a custom html_class' do
expect(element(html_class: 'custom_class').attr('class')).
- to eq 'custom_class js-timeago js-timeago-pending'
+ to eq 'js-timeago custom_class js-timeago-pending'
end
it 'accepts a custom tooltip placement' do
@@ -244,6 +244,19 @@ describe ApplicationHelper do
it 'converts to Time' do
expect { helper.time_ago_with_tooltip(Date.today) }.not_to raise_error
end
+
+ it 'add class for the short format and includes inline script' do
+ timeago_element = element(short_format: 'short')
+ expect(timeago_element.attr('class')).to eq 'js-short-timeago js-timeago-pending'
+ script_element = timeago_element.next_element
+ expect(script_element.name).to eq 'script'
+ end
+
+ it 'add class for the short format and does not include inline script' do
+ timeago_element = element(short_format: 'short', skip_js: true)
+ expect(timeago_element.attr('class')).to eq 'js-short-timeago'
+ expect(timeago_element.next_element).to eq nil
+ end
end
describe 'render_markup' do
diff --git a/spec/javascripts/datetime_utility_spec.js.coffee b/spec/javascripts/datetime_utility_spec.js.coffee
new file mode 100644
index 00000000000..6b9617341fe
--- /dev/null
+++ b/spec/javascripts/datetime_utility_spec.js.coffee
@@ -0,0 +1,31 @@
+#= require lib/utils/datetime_utility
+
+describe 'Date time utils', ->
+ describe 'get day name', ->
+ it 'should return Sunday', ->
+ day = gl.utils.getDayName(new Date('07/17/2016'))
+ expect(day).toBe('Sunday')
+
+ it 'should return Monday', ->
+ day = gl.utils.getDayName(new Date('07/18/2016'))
+ expect(day).toBe('Monday')
+
+ it 'should return Tuesday', ->
+ day = gl.utils.getDayName(new Date('07/19/2016'))
+ expect(day).toBe('Tuesday')
+
+ it 'should return Wednesday', ->
+ day = gl.utils.getDayName(new Date('07/20/2016'))
+ expect(day).toBe('Wednesday')
+
+ it 'should return Thursday', ->
+ day = gl.utils.getDayName(new Date('07/21/2016'))
+ expect(day).toBe('Thursday')
+
+ it 'should return Friday', ->
+ day = gl.utils.getDayName(new Date('07/22/2016'))
+ expect(day).toBe('Friday')
+
+ it 'should return Saturday', ->
+ day = gl.utils.getDayName(new Date('07/23/2016'))
+ expect(day).toBe('Saturday')