Merge pull request #7287 from opf/feature/type-defaults

Type description

[ci skip]
pull/7307/head
Oliver Günther 6 years ago committed by GitHub
commit 6973e27a61
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      app/contracts/types/base_contract.rb
  2. 2
      app/models/permitted_params.rb
  3. 38
      app/services/work_packages/set_attributes_service.rb
  4. 8
      app/views/types/form/_settings.html.erb
  5. 1
      config/locales/en.yml
  6. 5
      db/migrate/20190509071101_add_default_description_to_types.rb
  7. 2
      frontend/src/app/components/work-packages/wp-single-view/wp-single-view.html
  8. 29
      frontend/src/app/components/wp-edit-form/work-package-changeset.ts
  9. 2
      frontend/src/app/modules/fields/edit/edit-field.component.ts
  10. 7
      frontend/src/app/modules/fields/edit/field-types/formattable-edit-field.component.ts
  11. 2
      lib/api/v3/work_packages/work_package_payload_representer.rb
  12. 1
      spec/factories/type_factory.rb
  13. 93
      spec/features/work_packages/new/work_package_default_description_spec.rb

@ -43,6 +43,7 @@ module Types
attribute :is_default
attribute :color_id
attribute :project_ids
attribute :description
attribute :attribute_groups
validate :validate_current_user_is_admin

@ -606,6 +606,8 @@ class PermittedParams
:is_milestone,
:is_default,
:color_id,
:default,
:description,
project_ids: []
],
user: %i(

@ -69,6 +69,7 @@ class WorkPackages::SetAttributesService
update_dates
reset_custom_values
reassign_invalid_status_if_type_changed
set_templated_description
end
def set_static_attributes(attributes)
@ -86,9 +87,40 @@ class WorkPackages::SetAttributesService
work_package.author ||= user
work_package.status ||= Status.default
if Setting.work_package_startdate_is_adddate?
work_package.start_date ||= Date.today
end
work_package.start_date ||= Date.today if Setting.work_package_startdate_is_adddate?
end
def non_or_default_description?
work_package.description.blank? || false
end
def set_templated_description
# We only set this if the work package is new
return unless work_package.new_record?
# And the type was changed
return unless work_package.type_id_changed?
# And the new type has a default text
default_description = work_package.type&.description
return unless default_description.present?
# And the current description matches ANY current default text
return unless work_package.description.blank? || is_default_description?
work_package.description = default_description
end
def is_default_description?
Type
.pluck(:description)
.compact
.map(&method(:normalize_whitespace))
.include?(normalize_whitespace(work_package.description))
end
def normalize_whitespace(string)
string.gsub(/\s/, ' ').squeeze(' ')
end
def set_custom_attributes(attributes)

@ -55,6 +55,14 @@ See docs/COPYRIGHT.rdoc for more details.
container_class: '-slim') %>
</div>
<% end %>
<div class="form--field">
<%= f.text_area :description,
class: 'wiki-edit wiki-toolbar',
container_class: '-xxwide',
with_text_formatting: true %>
</div>
<!--[eoform:type]-->
</div>

@ -435,6 +435,7 @@ en:
spent_on: "Date"
type: "Type"
type:
description: "Default text for description"
attribute_groups: ''
is_in_roadmap: "Displayed in roadmap by default"
is_default: "Activated for new projects by default"

@ -0,0 +1,5 @@
class AddDefaultDescriptionToTypes < ActiveRecord::Migration[5.2]
def change
add_column :types, :description, :text
end
end

@ -40,7 +40,7 @@
<div class="attributes-group--header-container"></div>
</div>
<div>
<p [hidden]="projectContext.href" [textContent]="text.project.required"></p>
<p class="wp-project-context--warning" [hidden]="projectContext.href" [textContent]="text.project.required"></p>
<div class="attributes-key-value"
[ngClass]="{'-span-all-columns': descriptor.spanAll }"
*ngFor="let descriptor of projectContext.field; trackBy:trackByName">

@ -87,6 +87,16 @@ export class WorkPackageChangeset {
this.resetForm();
}
/**
* Remove some of the changes by key
* @param changes
*/
public clearSome(...changes:string[]) {
changes.forEach((key) => {
delete this.changes[key];
});
}
public resetForm() {
this.form = null;
}
@ -157,6 +167,8 @@ export class WorkPackageChangeset {
.then((form:FormResource) => {
this.form = form;
this.rebuildDefaults(form.payload);
this.buildResource();
this.wpFormPromise = null;
@ -231,6 +243,21 @@ export class WorkPackageChangeset {
return promise;
}
/**
* Rebuild default attributes we know might change
* Will only apply for new work packages.
*/
private rebuildDefaults(payload:HalResource) {
if (!this.workPackage.isNew) {
return;
}
// Take over the description from the form
// Either it's the same as our changeset or it was set by
// a default type value.
this.setValue('description', payload.description);
}
/**
* Merge the current changes into the payload resource.
*
@ -359,7 +386,7 @@ export class WorkPackageChangeset {
return;
}
let payload:any = this.workPackage.$source;
let payload:any = this.workPackage.$plain();
const resource = this.halResourceService.createHalResourceOfType('WorkPackage', this.mergeWithPayload(payload));

@ -60,7 +60,7 @@ export class EditFieldComponent extends Field implements OnInit, OnDestroy {
public self = this;
/** JQuery accessor to element ref */
protected $element:JQuery<HTMLElement>;
protected $element:JQuery;
constructor(readonly I18n:I18nService,
readonly elementRef:ElementRef,

@ -155,4 +155,11 @@ export class FormattableEditFieldComponent extends EditFieldComponent implements
public get isFormattable() {
return true;
}
protected initialize() {
if (this.resource.isNew && this.instance) {
// Reset CKEditor when reloading after type/form changes
this.reset();
}
}
}

@ -44,6 +44,8 @@ module API
exec_context: :decorator,
getter: ->(*) {},
setter: ->(fragment:, **) do
next unless fragment.is_a?(Array)
ids = fragment.map do |link|
::API::Utilities::ResourceLinkParser.parse_id link['href'],
property: :attachment,

@ -30,6 +30,7 @@ FactoryBot.define do
factory :type do
sequence(:position) { |p| p }
name { |a| "Type No. #{a.position}" }
description { nil }
created_at { Time.now }
updated_at { Time.now }

@ -0,0 +1,93 @@
require 'spec_helper'
require 'support/work_packages/work_package_field'
require 'features/work_packages/work_packages_page'
require 'features/page_objects/notification'
describe 'new work package', js: true do
let(:type_task) { FactoryBot.create(:type_task, description: "# New Task template\n\nHello there") }
let(:type_bug) { FactoryBot.create(:type_bug, description: "# New Bug template\n\nGeneral Kenobi") }
let!(:status) { FactoryBot.create(:status, is_default: true) }
let!(:priority) { FactoryBot.create(:priority, is_default: true) }
let!(:project) do
FactoryBot.create(:project, types: [type_task, type_bug])
end
let(:user) { FactoryBot.create :admin }
let(:subject_field) { wp_page.edit_field :subject }
let(:description_field) { wp_page.edit_field :description }
let(:project_field) { wp_page.edit_field :project }
let(:type_field) { wp_page.edit_field :type }
let(:notification) { PageObjects::Notifications.new(page) }
let(:wp_page) { Pages::FullWorkPackageCreate.new }
# Changing the type changes the description if it was empty or still the default.
# Changes in the description shall not be overridden.
def change_type_and_expect_description
type_field.openSelectField
type_field.set_value type_task
expect(page).to have_selector('.wp-edit-field.description h1', text: 'New Task template')
type_field.openSelectField
type_field.set_value type_bug
expect(page).to have_selector('.wp-edit-field.description h1', text: 'New Bug template')
description_field.set_value 'Something different than the default.'
type_field.openSelectField
type_field.set_value type_task
expect(page).not_to have_selector('.wp-edit-field.description h1', text: 'New Task template')
description_field.set_value ''
type_field.openSelectField
type_field.set_value type_bug
expect(page).to have_selector('.wp-edit-field.description h1', text: 'New Bug template')
scroll_to_and_click find('#work-packages--edit-actions-save')
wp_page.expect_notification message: 'Successful creation.'
expect(page).to have_selector('.wp-edit-field--display-field.description h1', text: 'New Bug template')
end
before do
login_as(user)
end
describe 'global work package create' do
it 'shows the template after selection of project and type' do
visit '/work_packages/new'
wp_page.expect_fully_loaded
project_field.openSelectField
project_field.set_value project
subject_field.set_value 'Foobar!'
# Wait until project is set
expect(page).to have_no_selector('.wp-project-context--warning')
change_type_and_expect_description
end
end
describe 'project work package create' do
let(:wp_table) { Pages::WorkPackagesTable.new project }
let(:wp_page) { Pages::SplitWorkPackageCreate.new project: project }
it 'shows the template after selection of project and type' do
wp_table.visit!
wp_table.create_wp_split_screen type_task
wp_page.expect_fully_loaded
subject_field.set_value 'Foobar!'
type_field.activate!
change_type_and_expect_description
end
end
end
Loading…
Cancel
Save