Merge branch 'dev' into fix/relation_closure

pull/5909/head
Oliver Günther 7 years ago committed by GitHub
commit a9634dbdb6
  1. 2
      Gemfile.lock
  2. 67
      features/menu_items/query_menu_items.feature
  3. 5
      frontend/app/components/api/api-v3/hal-request/hal-request.service.ts
  4. 8
      frontend/app/components/common/loading-indicator/loading-indicator.service.ts
  5. 7
      frontend/app/components/context-menus/create-wp-menu/create-wp-menu.controller.ts
  6. 1
      frontend/app/components/wp-fast-table/builders/rows/single-row-builder.ts
  7. 23
      frontend/app/components/wp-fast-table/handlers/state/selection-transformer.ts
  8. 9
      frontend/app/components/wp-fast-table/helpers/wp-table-row-helpers.ts
  9. 14
      frontend/app/components/wp-fast-table/state/wp-table-selection.service.ts
  10. 1
      frontend/app/components/wp-fast-table/wp-fast-table.ts
  11. 35
      lib/api/root.rb
  12. 6
      lib/api/v3/attachments/attachments_by_work_package_api.rb
  13. 4
      lib/api/v3/render/render_api.rb
  14. 2
      spec/requests/api/v3/attachments/attachment_resource_spec.rb
  15. 2
      spec/requests/api/v3/queries/query_resource_spec.rb
  16. 2
      spec/requests/api/v3/relations/relations_api_spec.rb
  17. 2
      spec/requests/api/v3/render_resource_spec.rb
  18. 2
      spec/requests/api/v3/user/user_resource_spec.rb
  19. 2
      spec/requests/api/v3/user/userlock_resource_spec.rb
  20. 2
      spec/requests/api/v3/watcher_resource_spec.rb
  21. 2
      spec/requests/api/v3/work_package_resource_spec.rb
  22. 2
      spec/requests/api/v3/work_packages/create_project_form_resource_spec.rb
  23. 4
      spec/support/request_with_header.rb

@ -60,7 +60,7 @@ GIT
GIT
remote: https://github.com/opf/openproject-translations.git
revision: 1adbcf87f5a8190556bcb0cb1b9ce1367b91d095
revision: 2e0808789d8d70d8107b355553db0bfd2491bb3e
branch: release/7.3
specs:
openproject-translations (7.3.1)

@ -1,67 +0,0 @@
#-- copyright
# OpenProject is a project management system.
# Copyright (C) 2012-2017 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-2017 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.
#++
Feature: Query menu items
Background:
Given there is 1 project with the following:
| name | Awesome Project |
| identifier | awesome-project |
And there is a role "member"
And the role "member" may have the following rights:
| view_work_packages |
| save_queries |
And there is 1 user with the following:
| login | bob |
And the user "bob" is a "member" in the project "Awesome Project"
And the project "Awesome Project" has the following types:
| name | position |
| Bug | 1 |
| Feature | 2 |
And there are the following issues in project "Awesome Project":
| subject | type | description |
| Bug1 | Bug | "1" |
| Feature1 | Feature | "2" |
| Feature2 | Feature | "3" |
And the user "bob" has the following queries by type in the project "Awesome Project":
| name | type_value |
| Bugs | Bug |
| Features | Feature |
And I am already logged in as "bob"
@javascript @selenium
Scenario: Delete a query menu item
Given the user "bob" has the following query menu items in the project "Awesome Project":
| name | title | navigatable |
| bugs_query | Bugs Query | Bugs |
When I go to the applied query "Bugs" on the work packages index page of the project "Awesome Project"
And the work package table has finished loading
And I click on "Settings"
And I click on "Publish ..."
And I uncheck "Show page in menu"
And I click "Save"
Then I should not see "Bugs Query" within "#main-menu"

@ -39,7 +39,8 @@ export class HalRequestService {
public defaultHeaders = {
caching: {
enabled: true
}
},
'Content-Type': 'application/json'
};
constructor(protected $q:ng.IQService,
@ -55,7 +56,7 @@ export class HalRequestService {
return this.$q.reject();
}
if (method === 'post') {
if (method.toUpperCase() !== 'GET') {
data = data || {};
}

@ -32,7 +32,7 @@ export const indicatorBackgroundSelector = '.loading-indicator--background';
export class LoadingIndicator {
constructor(public indicator:JQuery, public element:JQuery) {}
constructor(public indicator:JQuery, public template:string) {}
public set promise(promise:Promise<any>) {
this.start();
@ -47,11 +47,11 @@ export class LoadingIndicator {
}
public start() {
this.indicator.prepend(this.element);
this.indicator.prepend(this.template);
}
public stop() {
this.element.remove();
this.indicator.find('.loading-indicator--background').remove();
}
}
@ -78,7 +78,7 @@ export class LoadingIndicatorService {
// Return an indicator by name
public indicator(name:string):LoadingIndicator {
let indicator = this.getIndicatorAt(name);
return new LoadingIndicator(indicator, jQuery(this.indicatorTemplate));
return new LoadingIndicator(indicator, this.indicatorTemplate);
}
private getIndicatorAt(name:string):JQuery {

@ -28,11 +28,14 @@
import {opWorkPackagesModule} from '../../../angular-modules';
import {States} from '../../states.service';
import {WorkPackageEditingService} from './../../wp-edit-form/work-package-editing-service';
function CreateWpDropdownMenuController($scope:ng.IScope, states:States) {
function CreateWpDropdownMenuController($scope:ng.IScope, states:States, wpEditing:WorkPackageEditingService) {
const wp = states.workPackages.get('new').value;
if (wp) {
wp.getForm().then(
const changeset = wpEditing.changesetFor(wp!);
changeset.getForm().then(
(loadedForm:any) => {
$scope.configureFormLink = loadedForm.configureForm;
$scope.queryCustomFields = loadedForm.customFields;

@ -84,6 +84,7 @@ export class SingleRowBuilder {
public createEmptyRow(workPackage:WorkPackageResourceInterface) {
const identifier = this.classIdentifier(workPackage);
let tr = document.createElement('tr');
tr.setAttribute('tabindex', '0');
tr.dataset['workPackageId'] = workPackage.id;
tr.dataset['classIdentifier'] = identifier;
tr.classList.add(

@ -2,7 +2,7 @@ import {injectorBridge} from "../../../angular/angular-injector-bridge.functions
import {States} from "../../../states.service";
import {tableRowClassName} from "../../builders/rows/single-row-builder";
import {checkedClassName} from "../../builders/ui-state-link-builder";
import {rowId} from "../../helpers/wp-table-row-helpers";
import {rowId, locateTableRow} from "../../helpers/wp-table-row-helpers";
import {WorkPackageTableSelection} from "../../state/wp-table-selection.service";
import {WorkPackageTable} from "../../wp-fast-table";
import {WPTableRowSelectionState} from "../../wp-table.interfaces";
@ -10,10 +10,29 @@ import {WPTableRowSelectionState} from "../../wp-table.interfaces";
export class SelectionTransformer {
public wpTableSelection:WorkPackageTableSelection;
public states:States;
public FocusHelper:any;
constructor(table:WorkPackageTable) {
injectorBridge(this);
// Focus a single selection when active
this.states.table.rendered.values$()
.takeUntil(this.states.table.stopAllSubscriptions)
.subscribe(() => {
const singleSelection = this.wpTableSelection.getSingleSelection;
if (singleSelection === null) {
return;
}
const element = locateTableRow(singleSelection);
if (element.length) {
element[0].scrollIntoView();
this.FocusHelper.focusElement(element, true);
}
});
// Update selection state
this.wpTableSelection.selectionState.values$()
.takeUntil(this.states.table.stopAllSubscriptions)
.subscribe((state: WPTableRowSelectionState) => {
@ -48,4 +67,4 @@ export class SelectionTransformer {
}
}
SelectionTransformer.$inject = ['wpTableSelection', 'states'];
SelectionTransformer.$inject = ['wpTableSelection', 'states', 'FocusHelper'];

@ -3,14 +3,11 @@
* Return the row html id attribute for the given work package ID.
*/
export function rowId(workPackageId:string):string {
return `wp-table-row-${workPackageId}`;
return `wp-row-${workPackageId}-table`;
}
/**
* Locate the row by its work package ID.
*/
export function locateRow(id:string):HTMLElement|null {
return document.getElementById(rowId(id));
export function locateTableRow(workPackageId:string):JQuery {
return jQuery('.' + rowId(workPackageId));
}

@ -84,6 +84,20 @@ export class WorkPackageTableSelection {
return _.size(this.currentState.selected);
}
public get isSingleSelection():boolean {
return this.getSingleSelection !== null;
}
public get getSingleSelection():string|null {
const selected = _.pickBy(this.currentState.selected, (selected:boolean) => selected === true);
const selectedWps = _.keys(selected);
if (selectedWps.length === 1) {
return selectedWps[0];
}
return null;
}
/**
* Switch the current focused work package to the given id,
* setting selection and focus on this WP.

@ -9,7 +9,6 @@ import {injectorBridge} from '../angular/angular-injector-bridge.functions';
import {WorkPackageTableRow} from './wp-table.interfaces';
import {TableHandlerRegistry} from './handlers/table-handler-registry';
import {locateRow} from './helpers/wp-table-row-helpers';
import {PlainRowsBuilder} from './builders/modes/plain/plain-rows-builder';
import {GroupedRowsBuilder} from './builders/modes/grouped/grouped-rows-builder';
import {HierarchyRowsBuilder} from './builders/modes/hierarchy/hierarchy-rows-builder';

@ -94,6 +94,40 @@ module API
SetLocalizationService.new(User.current, env['HTTP_ACCEPT_LANGUAGE']).call
end
# Global helper to set allowed content_types
# This may be overriden when multipart is allowed (file uploads)
def allowed_content_types
%w(application/json application/hal+json)
end
def enforce_content_type
# Content-Type is not present in GET
return if request.get?
# Raise if missing header
content_type = request.content_type
error!('Missing content-type header', 406) unless content_type.present?
# Allow JSON and JSON+HAL per default
# and anything that each endpoint may optionally add to that
if content_type.present?
allowed_content_types.each do |mime|
# Content-Type header looks like this (e.g.,)
# application/json;encoding=utf8
return if content_type.start_with?(mime)
end
end
bad_type = content_type.presence || I18n.t('api_v3.errors.missing_content_type')
message = I18n.t('api_v3.errors.invalid_content_type',
content_type: allowed_content_types.join(" "),
actual: bad_type)
fail ::API::Errors::UnsupportedMediaType, message
end
def logged_in?
# An admin SystemUser is anonymous but still a valid user to be logged in.
current_user && (current_user.admin? || !current_user.anonymous?)
@ -197,6 +231,7 @@ module API
before do
authenticate
set_localization
enforce_content_type
end
version 'v3', using: :path do

@ -34,6 +34,12 @@ module API
class AttachmentsByWorkPackageAPI < ::API::OpenProjectAPI
resources :attachments do
helpers do
# Global helper to set allowed content_types
# This may be overriden when multipart is allowed (file uploads)
def allowed_content_types
%w(multipart/form-data)
end
def parse_metadata(json)
return nil unless json

@ -39,6 +39,10 @@ module API
SUPPORTED_CONTEXT_NAMESPACES = %w(work_packages projects).freeze
SUPPORTED_MEDIA_TYPE = 'text/plain'
def allowed_content_types
[SUPPORTED_MEDIA_TYPE]
end
def check_content_type
actual = request.content_type

@ -29,7 +29,7 @@
require 'spec_helper'
require 'rack/test'
describe 'API v3 Attachment resource', type: :request do
describe 'API v3 Attachment resource', type: :request, content_type: :json do
include Rack::Test::Methods
include API::V3::Utilities::PathHelper

@ -29,7 +29,7 @@
require 'spec_helper'
require 'rack/test'
describe 'API v3 Query resource', type: :request do
describe 'API v3 Query resource', type: :request, content_type: :json do
include Rack::Test::Methods
include API::V3::Utilities::PathHelper

@ -28,7 +28,7 @@
require 'spec_helper'
describe 'API v3 Relation resource', type: :request do
describe 'API v3 Relation resource', type: :request, content_type: :json do
include API::V3::Utilities::PathHelper
let(:user) { FactoryGirl.create :admin }

@ -29,7 +29,7 @@
require 'spec_helper'
require 'rack/test'
describe 'API v3 Render resource' do
describe 'API v3 Render resource', type: :request do
include Rack::Test::Methods
include API::V3::Utilities::PathHelper

@ -29,7 +29,7 @@
require 'spec_helper'
require 'rack/test'
describe 'API v3 User resource', type: :request do
describe 'API v3 User resource', type: :request, content_type: :json do
include Rack::Test::Methods
include API::V3::Utilities::PathHelper

@ -29,7 +29,7 @@
require 'spec_helper'
require 'rack/test'
describe 'API v3 UserLock resource', type: :request do
describe 'API v3 UserLock resource', type: :request, content_type: :json do
include Rack::Test::Methods
include API::V3::Utilities::PathHelper

@ -29,7 +29,7 @@
require 'spec_helper'
require 'rack/test'
describe 'API v3 Watcher resource', type: :request do
describe 'API v3 Watcher resource', type: :request, content_type: :json do
include Rack::Test::Methods
include API::V3::Utilities::PathHelper

@ -29,7 +29,7 @@
require 'spec_helper'
require 'rack/test'
describe 'API v3 Work package resource', type: :request do
describe 'API v3 Work package resource', type: :request, content_type: :json do
include Rack::Test::Methods
include Capybara::RSpecMatchers
include API::V3::Utilities::PathHelper

@ -29,7 +29,7 @@
require 'spec_helper'
require 'rack/test'
describe ::API::V3::WorkPackages::CreateProjectFormAPI do
describe ::API::V3::WorkPackages::CreateProjectFormAPI, content_type: :json do
include Rack::Test::Methods
include API::V3::Utilities::PathHelper

@ -6,6 +6,10 @@ RSpec.configure do |c|
header('X-Requested-With', 'XMLHttpRequest')
end
end
c.before(:each, type: :request, content_type: :json) do |ex|
header('Content-Type', 'application/json')
end
end
Loading…
Cancel
Save