From d6deee89671ab9cd1601fe8156f8aa28b450ee79 Mon Sep 17 00:00:00 2001 From: Jens Ulferts Date: Wed, 3 Jun 2015 10:13:22 +0200 Subject: [PATCH 1/4] prevent duplicate prepending of base path Routes generated statically need the base path to be appended to the requested url. Routes received from the server do not need to have it appended as they should already be fully qualified. --- frontend/app/openproject-app.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/app/openproject-app.js b/frontend/app/openproject-app.js index 8c4c349c8c..06ad4c24bd 100644 --- a/frontend/app/openproject-app.js +++ b/frontend/app/openproject-app.js @@ -203,7 +203,12 @@ openprojectApp $httpProvider.interceptors.push(function($q) { return { 'request': function(config) { - if (!config.url.match('(^/templates|\\.html$)')) { + // OpenProject can run in a subpath e.g. https://mydomain/open_project. + // We append the path found as the base-tag value to all http requests + // to the server except: + // * when the path is already appended + // * when we are getting a template + if (!config.url.match('(^/templates|\\.html$|^' + window.appBasePath + ')')) { config.url = window.appBasePath + config.url; } From b3c18e283948d64986c785e2a79b4865949d1925 Mon Sep 17 00:00:00 2001 From: Florian Kraft Date: Thu, 4 Jun 2015 16:45:31 +0200 Subject: [PATCH 2/4] use $primary-color for select highlighting Signed-off-by: Florian Kraft --- app/assets/stylesheets/content/_select2.scss | 4 ++-- app/assets/stylesheets/layout/_top_menu.sass | 2 +- app/assets/stylesheets/open_project_global/_variables.sass | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/assets/stylesheets/content/_select2.scss b/app/assets/stylesheets/content/_select2.scss index 3040b1078c..147db2c0a7 100644 --- a/app/assets/stylesheets/content/_select2.scss +++ b/app/assets/stylesheets/content/_select2.scss @@ -62,7 +62,7 @@ .select2-results .select2-highlighted { border-radius: 5px; - background-color: #24B3E7; + background-color: $drop-down-selected-bg-color; font-weight:bold; } .select2-results .select2-result-unselectable { @@ -172,7 +172,7 @@ $se2-width: 100%; } &.select2-dropdown-open { - + .select2-choice { background-color: $se2-theme-selectable-color; } diff --git a/app/assets/stylesheets/layout/_top_menu.sass b/app/assets/stylesheets/layout/_top_menu.sass index afafd585e3..b0ef9c17a4 100644 --- a/app/assets/stylesheets/layout/_top_menu.sass +++ b/app/assets/stylesheets/layout/_top_menu.sass @@ -216,7 +216,7 @@ padding: 0 .select2-highlighted - background: $header-item-bg-hover-color !important + background: $primary-color !important border-radius: 0 !important font-weight: bold !important color: $header-drop-down-item-font-hover-color diff --git a/app/assets/stylesheets/open_project_global/_variables.sass b/app/assets/stylesheets/open_project_global/_variables.sass index 30a8f03de5..1419499b42 100644 --- a/app/assets/stylesheets/open_project_global/_variables.sass +++ b/app/assets/stylesheets/open_project_global/_variables.sass @@ -165,7 +165,7 @@ $my-page-edit-box-border-color: $primary-color-dark !default $drop-down-unselected-font-color: $main-menu-font-color !default $drop-down-selected-font-color: $main-menu-font-color !default -$drop-down-selected-bg-color: #24B3E7 !default +$drop-down-selected-bg-color: $primary-color !default $action-menu-bg-color: #FFFFFF From e7a451cd3b01f1ea53b8537fd4ed6668370e520a Mon Sep 17 00:00:00 2001 From: Toshi MARUYAMA Date: Thu, 4 Jun 2015 23:46:56 +0900 Subject: [PATCH 3/4] fix Gemfile.lock --- Gemfile.lock | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 95d723105e..cadf36185c 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -559,10 +559,9 @@ DEPENDENCIES rubytree (~> 0.8.3) sass (~> 3.4.12) sass-rails! + selenium-webdriver (~> 2.45.0) shoulda-context (~> 1.2) shoulda-matchers (~> 2.8) - selenium-webdriver (~> 2.45.0) - shoulda simplecov (= 0.8.0.pre) sprockets! sprockets-rails! From 687149dfed228869bad1c4f2292aaf5356e96acf Mon Sep 17 00:00:00 2001 From: Jens Ulferts Date: Thu, 4 Jun 2015 17:46:45 +0200 Subject: [PATCH 4/4] consider all dates without a timezone (i.e. local) on the front end --- frontend/app/services/timezone-service.js | 31 ++++++++++++++----- .../app/ui_components/authoring-directive.js | 2 +- .../helpers/work-packages-helper.js | 4 +-- .../tests/integration/mocks/work-package.json | 4 +-- .../mocks/work-packages/819_patch.json | 4 +-- .../integration/mocks/work-packages/820.json | 4 +-- .../integration/mocks/work-packages/821.json | 4 +-- .../integration/mocks/work-packages/822.json | 4 +-- .../integration/mocks/work-packages/823.json | 2 +- .../integration/mocks/work-packages/824.json | 2 +- .../integration/mocks/work-packages/825.json | 2 +- .../tests/services/timezone-service-test.js | 27 +++++++++++----- .../ui_components/authoring-directive-test.js | 2 +- 13 files changed, 60 insertions(+), 32 deletions(-) diff --git a/frontend/app/services/timezone-service.js b/frontend/app/services/timezone-service.js index 9396a8216f..6704b26694 100644 --- a/frontend/app/services/timezone-service.js +++ b/frontend/app/services/timezone-service.js @@ -33,8 +33,8 @@ module.exports = function(ConfigurationService, I18n) { moment.locale(I18n.locale); }, - parseDate: function(date, format) { - var d = moment.utc(date, format); + parseDatetime: function(datetime, format) { + var d = moment.utc(datetime, format); if (ConfigurationService.isTimezoneSet()) { d.local(); @@ -44,18 +44,27 @@ module.exports = function(ConfigurationService, I18n) { return d; }, + parseDate: function(date, format) { + return moment(date, format); + }, + parseISODate: function(date) { return TimezoneService.parseDate(date, 'YYYY-MM-DD'); }, formattedDate: function(date) { - var format = ConfigurationService.dateFormatPresent() ? ConfigurationService.dateFormat() : 'L'; - return TimezoneService.parseDate(date).format(format); + var d = TimezoneService.parseDate(date); + return d.format(TimezoneService.getDateFormat()); + }, + + formattedTime: function(datetimeString) { + return TimezoneService.parseDatetime(datetimeString).format(TimezoneService.getTimeFormat()); }, - formattedTime: function(date) { - var format = ConfigurationService.timeFormatPresent() ? ConfigurationService.timeFormat() : 'LT'; - return TimezoneService.parseDate(date).format(format); + formattedDatetime: function(datetimeString) { + var d = TimezoneService.parseDatetime(datetimeString); + return d.format(TimezoneService.getDateFormat()) + ' ' + + d.format(TimezoneService.getTimeFormat()); }, formattedISODate: function(date) { @@ -66,6 +75,14 @@ module.exports = function(ConfigurationService, I18n) { var format = dateFormat || (ConfigurationService.dateFormatPresent() ? ConfigurationService.dateFormat() : 'L'); return moment(date, [format]).isValid(); + }, + + getDateFormat: function() { + return ConfigurationService.dateFormatPresent() ? ConfigurationService.dateFormat() : 'L'; + }, + + getTimeFormat: function() { + return ConfigurationService.timeFormatPresent() ? ConfigurationService.timeFormat() : 'LT'; } }; diff --git a/frontend/app/ui_components/authoring-directive.js b/frontend/app/ui_components/authoring-directive.js index fc2dbe4a77..3d047b3efe 100644 --- a/frontend/app/ui_components/authoring-directive.js +++ b/frontend/app/ui_components/authoring-directive.js @@ -36,7 +36,7 @@ module.exports = function(I18n, PathHelper, TimezoneService) { link: function(scope, element, attrs) { moment.locale(I18n.locale); - var createdOn = TimezoneService.parseDate(scope.createdOn); + var createdOn = TimezoneService.parseDatetime(scope.createdOn); var timeago = createdOn.fromNow(); var time = createdOn.format('LLL'); diff --git a/frontend/app/work_packages/helpers/work-packages-helper.js b/frontend/app/work_packages/helpers/work-packages-helper.js index 3d917ddddd..63ad83666c 100644 --- a/frontend/app/work_packages/helpers/work-packages-helper.js +++ b/frontend/app/work_packages/helpers/work-packages-helper.js @@ -141,9 +141,7 @@ module.exports =function(TimezoneService, currencyFilter, CustomFieldHelper) { case 'datetime': var dateTime; if (value) { - dateTime = TimezoneService.formattedDate(value) + - ' ' + - TimezoneService.formattedTime(value); + dateTime = TimezoneService.formattedDatetime(value); } return dateTime || ''; case 'date': diff --git a/frontend/tests/integration/mocks/work-package.json b/frontend/tests/integration/mocks/work-package.json index c57a988e02..6c67609900 100644 --- a/frontend/tests/integration/mocks/work-package.json +++ b/frontend/tests/integration/mocks/work-package.json @@ -86,8 +86,8 @@ "raw": "Sapiente terra dolores tempore debitis stultus. Adeo aduro repellendus. Vereor vulgivagus maxime ulciscor barba deleniti cognomen ustulo. Hic tubineus sumptus argumentum animi arcesso. Voluntarius dolore et. Apostolus vobis ultra delego acervus averto vitae." }, "priority": "Normal", - "startDate": "2014-02-28T00:00:00+00:00", - "dueDate": "2014-04-28T00:00:00+00:00", + "startDate": "2014-02-28", + "dueDate": "2014-04-28", "estimatedTime": { "units": "hours", "value": null diff --git a/frontend/tests/integration/mocks/work-packages/819_patch.json b/frontend/tests/integration/mocks/work-packages/819_patch.json index 55e839a28e..69967bd998 100644 --- a/frontend/tests/integration/mocks/work-packages/819_patch.json +++ b/frontend/tests/integration/mocks/work-packages/819_patch.json @@ -107,8 +107,8 @@ "status": "specified", "isClosed": false, "priority": "Normal", - "startDate": "2014-10-23T00:00:00+00:00", - "dueDate": "2014-12-27T00:00:00+00:00", + "startDate": "2014-10-23", + "dueDate": "2014-12-27", "estimatedTime": "PT0S", "spentTime": "PT0S", "percentageDone": 0, diff --git a/frontend/tests/integration/mocks/work-packages/820.json b/frontend/tests/integration/mocks/work-packages/820.json index 7f51263bae..73d9b9c392 100644 --- a/frontend/tests/integration/mocks/work-packages/820.json +++ b/frontend/tests/integration/mocks/work-packages/820.json @@ -93,8 +93,8 @@ "raw": "#54\n2" }, "priority": "Normal", - "startDate": "2014-10-23T00:00:00+00:00", - "dueDate": "2014-12-27T00:00:00+00:00", + "startDate": "2014-10-23", + "dueDate": "2014-12-27", "estimatedTime": "PT0S", "spentTime": "PT0S", "percentageDone": 0, diff --git a/frontend/tests/integration/mocks/work-packages/821.json b/frontend/tests/integration/mocks/work-packages/821.json index 5c9a5fddde..9766b218c6 100644 --- a/frontend/tests/integration/mocks/work-packages/821.json +++ b/frontend/tests/integration/mocks/work-packages/821.json @@ -103,8 +103,8 @@ "raw": "#54\n2" }, "priority": "Normal", - "startDate": "2014-10-23T00:00:00+00:00", - "dueDate": "2014-12-27T00:00:00+00:00", + "startDate": "2014-10-23", + "dueDate": "2014-12-27", "estimatedTime": "PT0S", "spentTime": "PT0S", "percentageDone": 0, diff --git a/frontend/tests/integration/mocks/work-packages/822.json b/frontend/tests/integration/mocks/work-packages/822.json index 52fccc45f4..9bb8a95941 100644 --- a/frontend/tests/integration/mocks/work-packages/822.json +++ b/frontend/tests/integration/mocks/work-packages/822.json @@ -105,8 +105,8 @@ "description": "", "rawDescription": "", "priority": "Normal", - "startDate": "2014-10-23T00:00:00+00:00", - "dueDate": "2014-12-27T00:00:00+00:00", + "startDate": "2014-10-23", + "dueDate": "2014-12-27", "estimatedTime": "PT0S", "spentTime": "PT12H", "percentageDone": 0, diff --git a/frontend/tests/integration/mocks/work-packages/823.json b/frontend/tests/integration/mocks/work-packages/823.json index 4494a5896f..ee2dc70d9f 100644 --- a/frontend/tests/integration/mocks/work-packages/823.json +++ b/frontend/tests/integration/mocks/work-packages/823.json @@ -109,7 +109,7 @@ }, "priority": "Normal", "startDate": null, - "dueDate": "2014-12-27T00:00:00+00:00", + "dueDate": "2014-12-27", "estimatedTime": "PT0S", "spentTime": "PT0S", "percentageDone": 0, diff --git a/frontend/tests/integration/mocks/work-packages/824.json b/frontend/tests/integration/mocks/work-packages/824.json index cc90188e37..251258402e 100644 --- a/frontend/tests/integration/mocks/work-packages/824.json +++ b/frontend/tests/integration/mocks/work-packages/824.json @@ -108,7 +108,7 @@ "raw": "#54" }, "priority": "Normal", - "startDate": "2014-10-23T00:00:00+00:00", + "startDate": "2014-10-23", "dueDate": null, "estimatedTime": "PT0S", "spentTime": "PT0S", diff --git a/frontend/tests/integration/mocks/work-packages/825.json b/frontend/tests/integration/mocks/work-packages/825.json index f7b2130656..6a1d754d77 100644 --- a/frontend/tests/integration/mocks/work-packages/825.json +++ b/frontend/tests/integration/mocks/work-packages/825.json @@ -112,7 +112,7 @@ "raw": "#54" }, "priority": "Normal", - "startDate": "2014-10-23T00:00:00+00:00", + "startDate": "2014-10-23", "dueDate": null, "estimatedTime": "PT0S", "spentTime": "PT0S", diff --git a/frontend/tests/unit/tests/services/timezone-service-test.js b/frontend/tests/unit/tests/services/timezone-service-test.js index 982be18d0b..27ab994c16 100644 --- a/frontend/tests/unit/tests/services/timezone-service-test.js +++ b/frontend/tests/unit/tests/services/timezone-service-test.js @@ -31,6 +31,7 @@ describe('TimezoneService', function() { var TIME = '2013-02-08T09:30:26'; + var DATE = '2013-02-08'; var TimezoneService; var ConfigurationService; var isTimezoneSetStub; @@ -42,15 +43,15 @@ describe('TimezoneService', function() { TimezoneService = _TimezoneService_; ConfigurationService = _ConfigurationService_; - isTimezoneSetStub = sinon.stub(ConfigurationService, "isTimezoneSet"); - timezoneStub = sinon.stub(ConfigurationService, "timezone"); + isTimezoneSetStub = sinon.stub(ConfigurationService, 'isTimezoneSet'); + timezoneStub = sinon.stub(ConfigurationService, 'timezone'); })); - describe('#parseDate', function() { + describe('#parseDatetime', function() { it('is UTC', function() { - var time = TimezoneService.parseDate(TIME); + var time = TimezoneService.parseDatetime(TIME); expect(time.zone()).to.equal(0); - expect(time.format("HH:mm")).to.eq("09:30"); + expect(time.format('HH:mm')).to.eq('09:30'); }); describe('Non-UTC timezone', function() { @@ -61,12 +62,24 @@ describe('TimezoneService', function() { isTimezoneSetStub.returns(true); timezoneStub.returns(timezone); - date = TimezoneService.parseDate(TIME); + date = TimezoneService.parseDatetime(TIME); }); it('is ' + timezone, function() { - expect(date.format("HH:mm")).to.eq("01:30"); + expect(date.format('HH:mm')).to.eq('01:30'); }); }); }); + + describe('#parseDate', function() { + it('has local time zone', function() { + var time = TimezoneService.parseDate(DATE); + expect(time.zone()).to.equal(time.clone().local().zone()); + }); + + it('has no time information', function() { + var time = TimezoneService.parseDate(DATE); + expect(time.format('HH:mm')).to.eq('00:00'); + }); + }); }); diff --git a/frontend/tests/unit/tests/ui_components/authoring-directive-test.js b/frontend/tests/unit/tests/ui_components/authoring-directive-test.js index a503913fab..3197a6b0d7 100644 --- a/frontend/tests/unit/tests/ui_components/authoring-directive-test.js +++ b/frontend/tests/unit/tests/ui_components/authoring-directive-test.js @@ -37,7 +37,7 @@ describe('authoring Directive', function() { beforeEach(module('openproject.templates', function($provide) { timezoneService = {}; - timezoneService.parseDate = sinon.stub().returns(createdOn); + timezoneService.parseDatetime = sinon.stub().returns(createdOn); $provide.constant('TimezoneService', timezoneService); }));