commit
83f791a345
@ -0,0 +1,45 @@ |
||||
// -- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2015 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.
|
||||
// ++
|
||||
|
||||
angular |
||||
.module('openproject.workPackages.services') |
||||
.factory('loadingIndicator', loadingIndicator); |
||||
|
||||
function loadingIndicator() { |
||||
var config = {}; |
||||
|
||||
return { |
||||
get config() { |
||||
return config; |
||||
}, |
||||
|
||||
on: function (promise) { |
||||
config.promise = promise; |
||||
} |
||||
}; |
||||
} |
@ -0,0 +1,13 @@ |
||||
<label for="work-packages-show-view-button" |
||||
ng-attr-accesskey="{{ accessKey }}" |
||||
class="hidden-for-sighted"> |
||||
|
||||
{{ label }} |
||||
</label> |
||||
<button id="work-packages-show-view-button" |
||||
class="button" |
||||
title="{{ label }}" |
||||
ng-click="showWorkPackageShowView()" |
||||
ng-class="{ '-active': isShowViewActive() }"> |
||||
<i class="icon-fullscreen-view button--icon"></i> |
||||
</button> |
@ -0,0 +1,69 @@ |
||||
// -- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2015 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.
|
||||
// ++
|
||||
|
||||
angular |
||||
.module('openproject.workPackages.directives') |
||||
.directive('wpViewButton', wpViewButton); |
||||
|
||||
function wpViewButton() { |
||||
return { |
||||
restrict: 'E', |
||||
templateUrl: '/components/wp-buttons/view-button/view-button.directive.html', |
||||
|
||||
controller: WorkPackageViewButtonController |
||||
}; |
||||
} |
||||
|
||||
function WorkPackageViewButtonController($scope, $state, $location) { |
||||
$scope.isShowViewActive = function() { |
||||
return $state.includes('work-packages.show'); |
||||
}; |
||||
|
||||
$scope.label = $scope.getActivationActionLabel(!$scope.isShowViewActive()) |
||||
+ I18n.t('js.button_show_view'); |
||||
|
||||
if ($scope.isShowViewActive()) { |
||||
$scope.accessKey = 9; |
||||
} |
||||
|
||||
$scope.showWorkPackageShowView = function() { |
||||
if ($state.is('work-packages.list.new') && $state.params.type) { |
||||
$state.go('work-packages.new', $state.params); |
||||
|
||||
} else { |
||||
var id = $state.params.workPackageId || $scope.preselectedWorkPackageId || |
||||
$scope.nextAvailableWorkPackage(), queryProps = $location.search()['query_props']; |
||||
|
||||
$state.go('work-packages.show.activity', { |
||||
projectPath: $scope.projectIdentifier || '', |
||||
workPackageId: id, |
||||
'query_props': queryProps |
||||
}); |
||||
} |
||||
}; |
||||
} |
@ -0,0 +1,49 @@ |
||||
// -- copyright
|
||||
// OpenProject is a project management system.
|
||||
// Copyright (C) 2012-2015 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.
|
||||
// ++
|
||||
|
||||
describe('Watchers panel directive', function () { |
||||
var $compile, $rootScope, element; |
||||
|
||||
beforeEach(angular.mock.module('openproject.workPackages.controllers', function ($controllerProvider) { |
||||
$controllerProvider.register('WatchersPanelController', function () {}); |
||||
})); |
||||
|
||||
beforeEach(angular.mock.module('openproject.templates')); |
||||
|
||||
beforeEach(inject(function (_$compile_, _$rootScope_) { |
||||
$compile = _$compile_; |
||||
$rootScope = _$rootScope_; |
||||
|
||||
element = $compile('<watchers-panel work-package="workPackage"></watchers-panel>')($rootScope); |
||||
$rootScope.$digest(); |
||||
})); |
||||
|
||||
it('should should be rendered correctly', function () { |
||||
expect(element.html()).to.contain('detail-panel-watchers'); |
||||
}); |
||||
}); |
@ -1,4 +1,4 @@ |
||||
<a id ="{{ activityHtmlId }}" |
||||
<a id ="{{ activityHtmlId }}-link" |
||||
ng-bind="'#' + activityNo" |
||||
tabindex="-1" |
||||
ui-sref="work-packages.show.activity({ workPackageId: workPackageId, '#': activityHtmlId})"></a> |
||||
|
@ -0,0 +1,62 @@ |
||||
#-- copyright |
||||
# OpenProject is a project management system. |
||||
# Copyright (C) 2012-2015 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' |
||||
|
||||
describe 'Toggle watching', type: :feature, js: true do |
||||
let(:project) { FactoryGirl.create(:project) } |
||||
let(:role) { FactoryGirl.create(:role, permissions: [:view_messages, :view_wiki_pages]) } |
||||
let(:user) { FactoryGirl.create(:user, member_in_project: project, member_through_role: role) } |
||||
let(:news) { FactoryGirl.create(:news, project: project) } |
||||
let(:board) { FactoryGirl.create(:board, project: project) } |
||||
let(:message) { FactoryGirl.create(:message, board: board) } |
||||
let(:wiki) { project.wiki } |
||||
let(:wiki_page) { FactoryGirl.create(:wiki_page_with_content, wiki: wiki) } |
||||
|
||||
before do |
||||
allow(User).to receive(:current).and_return user |
||||
end |
||||
|
||||
it 'can toggle watch and unwatch' do |
||||
# Work packages have a different toggle and are hence not considered here |
||||
[news_path(news), |
||||
project_board_path(project, board), |
||||
topic_path(message), |
||||
project_wiki_path(project, wiki_page)].each do |path| |
||||
visit path |
||||
|
||||
click_link(I18n.t('button_watch')) |
||||
|
||||
expect(page).to have_link(I18n.t('button_unwatch')) |
||||
|
||||
click_link(I18n.t('button_unwatch')) |
||||
|
||||
expect(page).to have_link(I18n.t('button_watch')) |
||||
end |
||||
end |
||||
end |
@ -0,0 +1,171 @@ |
||||
require 'spec_helper' |
||||
|
||||
require 'features/work_packages/work_packages_page' |
||||
require 'features/work_packages/details/inplace_editor/work_package_field' |
||||
|
||||
describe 'Activity tab', js: true, selenium: true do |
||||
def alter_work_package_at(work_package, attributes:, at:, user: User.current) |
||||
work_package.update_attributes(attributes.merge({ updated_at: at })) |
||||
|
||||
note_journal = work_package.journals.last |
||||
note_journal.update_attributes(created_at: at, user: attributes[:user]) |
||||
end |
||||
|
||||
let(:project) { FactoryGirl.create :project_with_types, is_public: true } |
||||
let!(:work_package) { |
||||
work_package = FactoryGirl.create(:work_package, |
||||
project: project, |
||||
created_at: 5.days.ago.to_date.to_s(:db), |
||||
subject: initial_subject, |
||||
journal_notes: initial_comment) |
||||
|
||||
note_journal = work_package.journals.last |
||||
note_journal.update_attributes(created_at: 5.days.ago.to_date.to_s) |
||||
|
||||
work_package |
||||
} |
||||
|
||||
let(:initial_subject) { 'My Subject' } |
||||
let(:initial_comment) { 'First comment on this wp.' } |
||||
let(:comments_in_reverse) { false } |
||||
|
||||
let(:initial_note) { |
||||
work_package.journals[0] |
||||
} |
||||
|
||||
let!(:note_1) { |
||||
attributes = { subject: 'New subject', |
||||
description: 'Some not so long description.', |
||||
journal_notes: 'Updated the subject and description' } |
||||
|
||||
alter_work_package_at(work_package, |
||||
attributes: attributes, |
||||
at: 3.days.ago.to_date.to_s(:db), |
||||
user: user) |
||||
|
||||
work_package.journals.last |
||||
} |
||||
|
||||
let!(:note_2) { |
||||
attributes = { journal_notes: 'Another comment by a different user' } |
||||
|
||||
alter_work_package_at(work_package, |
||||
attributes: attributes, |
||||
at: 1.days.ago.to_date.to_s(:db), |
||||
user: FactoryGirl.create(:admin)) |
||||
|
||||
work_package.journals.last |
||||
} |
||||
|
||||
before do |
||||
login_as(user) |
||||
allow(user.pref).to receive(:warn_on_leaving_unsaved?).and_return(false) |
||||
allow(user.pref).to receive(:comments_in_reverse_order?).and_return(comments_in_reverse) |
||||
end |
||||
|
||||
shared_examples 'shows activities in order' do |
||||
let(:journals) { |
||||
journals = [initial_note, note_1, note_2] |
||||
|
||||
journals |
||||
} |
||||
|
||||
it 'shows activities in ascending order' do |
||||
journals.each_with_index do |journal, idx| |
||||
date_selector = ".work-package-details-activities-activity:nth-of-type(#{idx + 1}) " + |
||||
'.activity-date' |
||||
expect(page).to have_selector(date_selector, |
||||
text: journal.created_at.to_date.to_s(:long)) |
||||
|
||||
activity = page.find("#activity-#{idx + 1}") |
||||
expect(activity).to have_selector('.user', text: journal.user.name) |
||||
expect(activity).to have_selector('.user-comment > .message', text: journal.notes) |
||||
|
||||
if activity == note_1 |
||||
expect(activity).to have_selector('.work-package-details-activities-messages .message', |
||||
count: 2) |
||||
expect(activity).to have_selector('.message', |
||||
text: "Subject changed from #{initial_subject} " \ |
||||
"to #{journal.data.subject}") |
||||
end |
||||
end |
||||
end |
||||
end |
||||
|
||||
shared_examples 'activity tab' do |
||||
before do |
||||
work_package_page.visit_tab! 'activity' |
||||
expect(page).to have_selector('.user-comment > .message', |
||||
text: initial_comment) |
||||
end |
||||
|
||||
context 'with permission' do |
||||
let(:role) { |
||||
FactoryGirl.create(:role, permissions: [:view_work_packages, |
||||
:add_work_package_notes]) |
||||
} |
||||
let(:user) { |
||||
FactoryGirl.create(:user, |
||||
member_in_project: project, |
||||
member_through_role: role) |
||||
} |
||||
|
||||
context 'with ascending comments' do |
||||
let(:comments_in_reverse) { false } |
||||
it_behaves_like 'shows activities in order' |
||||
end |
||||
|
||||
context 'with reversed comments' do |
||||
let(:comments_in_reverse) { true } |
||||
it_behaves_like 'shows activities in order' |
||||
end |
||||
|
||||
it 'can quote a previous comment' do |
||||
# Hover comment |
||||
page.find('#activity-1 .work-package-details-activities-activity-contents').hover |
||||
|
||||
# Quote this comment |
||||
page.find('#activity-1 .comments-icons .icon-quote', visible: false).click |
||||
|
||||
field = WorkPackageField.new(page, 'activity', '.work-packages--activity--add-comment') |
||||
|
||||
expect(field.editing?).to be true |
||||
|
||||
# Add our comment |
||||
quote = field.input_element[:value] |
||||
expect(quote).to include("> #{initial_comment}") |
||||
quote << "\nthis is some remark under a quote" |
||||
field.input_element.set(quote) |
||||
field.submit_by_click |
||||
|
||||
expect(page).to have_selector('.user-comment > .message', count: 4) |
||||
expect(page).to have_selector('.user-comment > .message blockquote') |
||||
end |
||||
end |
||||
|
||||
context 'with no permission' do |
||||
let(:role) { |
||||
FactoryGirl.create(:role, permissions: [:view_work_packages]) |
||||
} |
||||
let(:user) { |
||||
FactoryGirl.create(:user, |
||||
member_in_project: project, |
||||
member_through_role: role) |
||||
} |
||||
|
||||
it 'shows the activities, but does not allow commenting' do |
||||
expect(page).not_to have_selector('.work-packages--activity--add-comment', visible: true) |
||||
end |
||||
end |
||||
end |
||||
|
||||
context 'split screen' do |
||||
let(:work_package_page) { Pages::SplitWorkPackage.new(work_package, project) } |
||||
it_behaves_like 'activity tab' |
||||
end |
||||
|
||||
context 'full screen' do |
||||
let(:work_package_page) { Pages::FullWorkPackage.new(work_package) } |
||||
it_behaves_like 'activity tab' |
||||
end |
||||
end |
Loading…
Reference in new issue