Merge pull request #1962 from opf/fix/13573_wiki_toolbar_entry

Fix/13573 wiki toolbar entry
pull/1975/head
Alex Coles 10 years ago
commit a4b4158caa
  1. 30
      app/assets/javascripts/angular/controllers/dialogs/share.js
  2. 10
      app/assets/javascripts/angular/layout/query-menu-items.js
  3. 40
      app/assets/javascripts/angular/services/query-service.js
  4. 2
      app/controllers/api/experimental/concerns/query_loading.rb
  5. 4
      karma/tests/controllers/work-package-details-controller-test.js
  6. 5
      karma/tests/controllers/work-packages-controller-test.js
  7. 4
      karma/tests/controllers/work-packages-list-controller-test.js
  8. 4
      karma/tests/directives/work_packages/options-dropdown-directive-test.js
  9. 4
      karma/tests/directives/work_packages/work-package-relations-directive-test.js
  10. 4
      karma/tests/directives/work_packages/work-package-total-sums-directive-test.js
  11. 4
      karma/tests/helpers/work-package-context-menu-helper-test.js
  12. 5
      karma/tests/services/query-service-test.js
  13. 6
      karma/tests/services/work-package-service-test.js
  14. 5
      karma/tests/work_packages/column-context-menu-test.js
  15. 5
      karma/tests/work_packages/directives/work-package-details-toolbar-test.js
  16. 5
      karma/tests/work_packages/work-package-context-menu-test.js
  17. 94
      spec/features/work_packages/saving_queries.rb

@ -42,11 +42,9 @@ angular.module('openproject.workPackages.controllers')
'shareModal',
'QueryService',
'AuthorisationService',
'$rootScope',
'QUERY_MENU_ITEM_TYPE',
'queryMenuItemFactory',
'PathHelper',
function($scope, shareModal, QueryService, AuthorisationService, $rootScope, QUERY_MENU_ITEM_TYPE, queryMenuItemFactory, PathHelper) {
function($scope, shareModal, QueryService, AuthorisationService, queryMenuItemFactory, PathHelper) {
this.name = 'Share';
this.closeMe = shareModal.deactivate;
@ -61,27 +59,6 @@ angular.module('openproject.workPackages.controllers')
$scope.$emit('flashMessage', message);
}
function getQueryPath(query) {
if (query.project_id) {
return PathHelper.projectPath(query.project_id) + PathHelper.workPackagesPath() + '?query_id=' + query.id;
} else {
return PathHelper.workPackagesPath() + '?query_id=' + query.id;
}
}
function addOrRemoveMenuItem(query) {
if (!query) return;
if(query.starred) {
queryMenuItemFactory.generateMenuItem(query.name, getQueryPath(query), query.id);
} else {
$rootScope.$broadcast('openproject.layout.removeMenuItem', {
itemType: QUERY_MENU_ITEM_TYPE,
objectId: query.id
});
}
}
$scope.cannot = AuthorisationService.cannot;
$scope.saveQuery = function() {
@ -95,13 +72,12 @@ angular.module('openproject.workPackages.controllers')
})
.then(function(data){
if($scope.query.starred != $scope.shareSettings.starred){
QueryService.toggleQueryStarred()
QueryService.toggleQueryStarred($scope.query)
.then(function(data){
closeAndReport(data.status || messageObject);
return $scope.query;
})
.then(addOrRemoveMenuItem);
});
} else {
closeAndReport(messageObject);
}

@ -44,8 +44,7 @@ angular.module('openproject.layout')
'$animate',
'$timeout',
'QUERY_MENU_ITEM_TYPE',
'QueryService',
function(menuItemFactory, $stateParams, $animate, $timeout, QUERY_MENU_ITEM_TYPE, QueryService) {
function(menuItemFactory, $stateParams, $animate, $timeout, QUERY_MENU_ITEM_TYPE) {
return menuItemFactory({
type: QUERY_MENU_ITEM_TYPE,
container: '#main-menu-work-packages-wrapper ~ .menu-children',
@ -53,7 +52,7 @@ angular.module('openproject.layout')
scope.queryId = scope.objectId || attrs.objectId;
function setActiveState() {
element.toggleClass('selected', (scope.queryId || null) === $stateParams.query_id);
element.toggleClass('selected', String(scope.queryId || null) === String($stateParams.query_id));
}
$timeout(setActiveState);
scope.$on('$stateChangeSuccess', setActiveState);
@ -72,10 +71,7 @@ angular.module('openproject.layout')
scope.$on('openproject.layout.renameQueryMenuItem', function(event, itemData) {
if (itemData.itemType === QUERY_MENU_ITEM_TYPE && itemData.queryId === scope.queryId) {
QueryService.updateHighlightName()
.then(function() {
element.html(itemData.queryName);
});
element.html(itemData.queryName);
}
});
}

@ -45,7 +45,10 @@ angular.module('openproject.services')
'ProjectService',
'WorkPackagesTableHelper',
'I18n',
function(Query, Sortation, $http, PathHelper, $q, AVAILABLE_WORK_PACKAGE_FILTERS, StatusService, TypeService, PriorityService, UserService, VersionService, RoleService, GroupService, ProjectService, WorkPackagesTableHelper, I18n) {
'queryMenuItemFactory',
'$rootScope',
'QUERY_MENU_ITEM_TYPE',
function(Query, Sortation, $http, PathHelper, $q, AVAILABLE_WORK_PACKAGE_FILTERS, StatusService, TypeService, PriorityService, UserService, VersionService, RoleService, GroupService, ProjectService, WorkPackagesTableHelper, I18n, queryMenuItemFactory, $rootScope, QUERY_MENU_ITEM_TYPE) {
var query;
@ -350,6 +353,12 @@ angular.module('openproject.services')
query.save(response.data.query);
QueryService.fetchAvailableGroupedQueries(query.project_id);
// The starred-state does not get saved via the API. So we manually
// set it, if the old query was starred.
if (query.starred) {
QueryService.starQuery();
}
return angular.extend(response.data, { status: { text: I18n.t('js.notice_successful_create') }} );
});
},
@ -363,7 +372,32 @@ angular.module('openproject.services')
});
},
toggleQueryStarred: function() {
getQueryPath: function(query) {
if (query.project_id) {
return PathHelper.projectPath(query.project_id) + PathHelper.workPackagesPath() + '?query_id=' + query.id;
} else {
return PathHelper.workPackagesPath() + '?query_id=' + query.id;
}
},
addOrRemoveMenuItem: function(query) {
if (!query) return;
if(query.starred) {
queryMenuItemFactory.generateMenuItem(query.name, QueryService.getQueryPath(query), query.id);
$rootScope.$broadcast('$stateChangeSuccess', {
itemType: QUERY_MENU_ITEM_TYPE,
objectId: query.id
});
} else {
$rootScope.$broadcast('openproject.layout.removeMenuItem', {
itemType: QUERY_MENU_ITEM_TYPE,
objectId: query.id
});
}
},
toggleQueryStarred: function(query) {
if(query.starred) {
return QueryService.unstarQuery();
} else {
@ -377,6 +411,7 @@ angular.module('openproject.services')
var success = function(response){
theQuery.star();
QueryService.addOrRemoveMenuItem(theQuery);
return response.data;
};
@ -399,6 +434,7 @@ angular.module('openproject.services')
return QueryService.doPatch(url, function(response){
theQuery.unstar();
QueryService.addOrRemoveMenuItem(theQuery);
return response.data;
});
},

@ -46,6 +46,7 @@ module Api::Experimental::Concerns::QueryLoading
end
def prepare_query
@query.is_public = params[:is_public] if params[:is_public]
@query.is_public = false unless User.current.allowed_to?(:manage_public_queries, @project) || User.current.admin?
view_context.add_filter_from_params if params[:fields] || params[:f] || params[:accept_empty_query_fields]
@query.group_by = params[:group_by] if params[:group_by].present?
@ -54,7 +55,6 @@ module Api::Experimental::Concerns::QueryLoading
@query.column_names = params[:c] if params[:c]
@query.column_names = nil if params[:default_columns]
@query.name = params[:name] if params[:name]
@query.is_public = params[:is_public] if params[:is_public]
end
def prepare_sort_criteria

@ -31,6 +31,7 @@
describe('WorkPackageDetailsController', function() {
var scope;
var buildController;
var stateParams = {};
var I18n = { t: angular.identity },
WorkPackagesHelper = {
formatWorkPackageProperty: angular.identity
@ -93,7 +94,7 @@ describe('WorkPackageDetailsController', function() {
return workPackage;
}
beforeEach(module('openproject.api', 'openproject.services', 'openproject.workPackages.controllers', 'openproject.services'));
beforeEach(module('openproject.api', 'openproject.layout', 'openproject.services', 'openproject.workPackages.controllers', 'openproject.services'));
beforeEach(module('templates', function($provide) {
configurationService = new Object();
@ -106,6 +107,7 @@ describe('WorkPackageDetailsController', function() {
beforeEach(module('templates', function($provide) {
var state = { go: function() { return false; } };
$provide.value('$state', state);
$provide.constant('$stateParams', stateParams);
}));
beforeEach(inject(function($rootScope, $controller, $timeout) {

@ -29,14 +29,15 @@
/*jshint expr: true*/
describe('WorkPackagesController', function() {
var scope, win, testParams, buildController;
var scope, win, testParams, buildController, stateParams = {};
beforeEach(module('openproject.workPackages.controllers', 'openproject.api', 'openproject.services'));
beforeEach(module('openproject.workPackages.controllers', 'openproject.api', 'openproject.layout','openproject.services'));
beforeEach(module('templates', function($provide) {
configurationService = new Object();
configurationService.isTimezoneSet = sinon.stub().returns(false);
$provide.constant('$stateParams', stateParams);
$provide.constant('ConfigurationService', configurationService);
}));
beforeEach(inject(function($rootScope, $controller, $timeout) {

@ -33,13 +33,15 @@ describe('WorkPackagesListController', function() {
testProjectService, testWorkPackageService, testQueryService, testPaginationService;
var testQueries;
var buildController;
var stateParams = {};
beforeEach(module('openproject.api', 'openproject.workPackages.controllers', 'openproject.workPackages.services', 'ng-context-menu', 'btford.modal', 'openproject.services'));
beforeEach(module('openproject.api', 'openproject.workPackages.controllers', 'openproject.workPackages.services', 'ng-context-menu', 'btford.modal', 'openproject.layout', 'openproject.services'));
beforeEach(module('templates', function($provide) {
configurationService = new Object();
configurationService.isTimezoneSet = sinon.stub().returns(false);
$provide.constant('$stateParams', stateParams);
$provide.constant('ConfigurationService', configurationService);
}));
beforeEach(inject(function($rootScope, $controller, $timeout) {

@ -27,18 +27,20 @@
//++
describe('optionsDropdown Directive', function() {
var compile, element, rootScope, scope, I18n;
var compile, element, rootScope, scope, I18n, stateParams = {};
beforeEach(angular.mock.module('openproject.workPackages.directives'));
beforeEach(module('openproject.models',
'openproject.workPackages.controllers',
'openproject.api',
'openproject.layout',
'openproject.services'));
beforeEach(module('templates', function($provide) {
configurationService = new Object();
configurationService.isTimezoneSet = sinon.stub().returns(false);
$provide.constant('$stateParams', stateParams);
$provide.constant('ConfigurationService', configurationService);
}));

@ -27,12 +27,13 @@
//++
describe('Work Package Relations Directive', function() {
var I18n, PathHelper, compile, element, scope, ChildrenRelationsHandler;
var I18n, PathHelper, compile, element, scope, ChildrenRelationsHandler, stateParams = {};
beforeEach(angular.mock.module('openproject.workPackages.tabs',
'openproject.api',
'openproject.helpers',
'openproject.models',
'openproject.layout',
'openproject.services',
'openproject.viewModels',
'ngSanitize'));
@ -42,6 +43,7 @@ describe('Work Package Relations Directive', function() {
configurationService.isTimezoneSet = sinon.stub().returns(false);
$provide.constant('$stateParams', stateParams);
$provide.constant('ConfigurationService', configurationService);
}));

@ -27,10 +27,11 @@
//++
describe('workPackageTotalSums Directive', function() {
var compile, element, rootScope, scope;
var compile, element, rootScope, scope, stateParams = {};
beforeEach(angular.mock.module('openproject.workPackages.directives',
'openproject.models',
'openproject.layout',
'openproject.services'));
beforeEach(module('openproject.api', 'templates', function($provide) {
@ -38,6 +39,7 @@ describe('workPackageTotalSums Directive', function() {
configurationService.isTimezoneSet = sinon.stub().returns(false);
$provide.constant('$stateParams', stateParams);
$provide.constant('ConfigurationService', configurationService);
}));

@ -31,14 +31,16 @@
describe('WorkPackageContextMenuHelper', function() {
var PERMITTED_CONTEXT_MENU_ACTIONS = ['edit', 'log_time', 'update', 'move'];
var WorkPackageContextMenuHelper;
var stateParams = {};
beforeEach(module('openproject.workPackages.helpers', 'openproject.models', 'openproject.api', 'openproject.services'));
beforeEach(module('openproject.workPackages.helpers', 'openproject.models', 'openproject.api', 'openproject.layout','openproject.services'));
beforeEach(module('templates', function($provide) {
configurationService = new Object();
configurationService.isTimezoneSet = sinon.stub().returns(false);
$provide.constant('$stateParams', stateParams);
$provide.constant('ConfigurationService', configurationService);
}));

@ -30,9 +30,9 @@
describe('QueryService', function() {
var QueryService, query, queryData;
var QueryService, query, queryData, stateParams = {};
beforeEach(module('openproject.services',
beforeEach(module('openproject.layout',
'openproject.models',
'openproject.api',
'openproject.services'));
@ -42,6 +42,7 @@ describe('QueryService', function() {
configurationService.isTimezoneSet = sinon.stub().returns(false);
$provide.constant('$stateParams', stateParams);
$provide.constant('ConfigurationService', configurationService);
}));

@ -30,14 +30,16 @@
describe('WorkPackageService', function() {
var WorkPackageService;
beforeEach(module('openproject.api','openproject.services', 'openproject.models'));
var WorkPackageService,
stateParams = {};
beforeEach(module('openproject.api', 'openproject.layout','openproject.services', 'openproject.models'));
beforeEach(module('templates', function($provide) {
configurationService = new Object();
configurationService.isTimezoneSet = sinon.stub().returns(false);
$provide.constant('$stateParams', stateParams);
$provide.constant('ConfigurationService', configurationService);
}));

@ -29,13 +29,15 @@
/*jshint expr: true*/
describe('columnContextMenu', function() {
var container, contextMenu, $rootScope, scope;
var container, contextMenu, $rootScope, scope, stateParams;
stateParams = {};
beforeEach(module('ng-context-menu',
'openproject.workPackages',
'openproject.workPackages.controllers',
'openproject.models',
'openproject.api',
'openproject.layout',
'openproject.services',
'templates'));
@ -44,6 +46,7 @@ describe('columnContextMenu', function() {
configurationService.isTimezoneSet = sinon.stub().returns(false);
$provide.constant('$stateParams', stateParams);
$provide.constant('ConfigurationService', configurationService);
}));

@ -29,12 +29,14 @@
/*jshint expr: true*/
describe('workPackageDetailsToolbar', function() {
var I18n, HookService, compile, scope, element;
var I18n, HookService, compile, scope, element, stateParams;
var html = "<work-package-details-toolbar work-package='workPackage'></work-package-details-toolbar>";
stateParams = {};
beforeEach(module('ui.router',
'openproject.api',
'openproject.models',
'openproject.layout',
'openproject.services',
'openproject.uiComponents',
'openproject.workPackages.directives',
@ -44,6 +46,7 @@ describe('workPackageDetailsToolbar', function() {
beforeEach(module('templates', function($provide) {
configurationService = new Object();
$provide.constant('$stateParams', stateParams);
$provide.constant('ConfigurationService', configurationService);
}));

@ -29,12 +29,14 @@
/*jshint expr: true*/
describe('workPackageContextMenu', function() {
var container, contextMenu, $rootScope;
var container, contextMenu, $rootScope, stateParams;
stateParams = {};
beforeEach(module('ng-context-menu',
'openproject.api',
'openproject.workPackages',
'openproject.models',
'openproject.layout',
'openproject.services',
'templates'));
@ -44,6 +46,7 @@ describe('workPackageContextMenu', function() {
configurationService.isTimezoneSet = sinon.stub().returns(false);
$provide.constant('ConfigurationService', configurationService);
$provide.constant('$stateParams', stateParams);
}));
beforeEach(function() {

@ -0,0 +1,94 @@
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2014 the OpenProject Foundation (OPF)
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version 3.
#
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
# Copyright (C) 2006-2013 Jean-Philippe Lang
# Copyright (C) 2010-2013 the ChiliProject Team
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# See doc/COPYRIGHT.rdoc for more details.
#++
require 'spec_helper'
require 'features/work_packages/work_packages_page'
describe 'Query Saving', type: :feature, js: true do
let(:project) { FactoryGirl.create :project, identifier: 'test_project', is_public: false }
let(:role) { FactoryGirl.create :role, permissions: [:view_work_packages] }
let(:current_user) do
FactoryGirl.create :user, member_in_project: project,
member_through_role: role,
admin: true
end
let(:filter_name) { 'done_ratio' }
let!(:query) do
query = FactoryGirl.build(:query, project: project, is_public: true)
query.filters = [Queries::WorkPackages::Filter.new(filter_name, operator: '>=', values: [10])]
query.save!
query
end
let(:query_item) do
FactoryGirl.create(:query_menu_item,
query: query,
name: 'Query Item',
title: 'Query Item')
end
let(:work_packages_page) { WorkPackagesPage.new(project) }
before do
query.query_menu_item = query_item
allow(User).to receive(:current).and_return current_user
end
context 'when a query is loaded' do
before do
work_packages_page.select_query query
# ensure the page is loaded before expecting anything
find('.filter-fields select option', text: /\AAssignee\Z/,
visible: false)
end
it 'should select its menu item' do
expect(page).to have_css '#main-menu .query.selected'
selected = find('#main-menu .query.selected')
expect(selected).to have_text(query_item.name)
end
context 'after saving under a new name' do
before do
work_packages_page.click_toolbar_button 'Settings'
find('#settingsDropdown').find_link('Save as ...').click
fill_in 'query_name', with: 'newQueryName'
find_button('Save').click
# ensure the page is loaded before expecting anything
find('.filter-fields select option', text: /\AAssignee\Z/,
visible: false)
end
it 'should select the new menu item' do
expect(page).to have_css '#main-menu .query-menu-item.selected'
selected = find('#main-menu .query-menu-item.selected')
expect(selected).to have_text('newQueryName')
end
end
end
end
Loading…
Cancel
Save