Merge branch 'release/8.0' into dev

pull/6681/head
Jens Ulferts 6 years ago
commit 0a06e8a7f0
No known key found for this signature in database
GPG Key ID: 3CAA4B1182CF5308
  1. 6
      app/assets/stylesheets/content/_colors.sass
  2. 3
      app/assets/stylesheets/content/_modal.sass
  3. 16
      app/assets/stylesheets/content/_user_mention.sass
  4. 2
      app/controllers/highlighting_controller.rb
  5. 2
      app/controllers/timelog_controller.rb
  6. 2
      app/controllers/users_controller.rb
  7. 2
      app/helpers/colors_helper.rb
  8. 2
      app/models/attribute_help_text/work_package.rb
  9. 2
      app/models/project.rb
  10. 4
      app/models/version.rb
  11. 2
      app/models/work_package.rb
  12. 10
      app/models/work_package/scheduling_rules.rb
  13. 2
      app/views/highlighting/styles.css.erb
  14. 4
      config/locales/en.seeders.yml
  15. 10
      config/locales/en.yml
  16. 4
      config/locales/js-en.yml
  17. 20
      docs/api/apiv3/endpoints/queries.apib
  18. 4
      docs/api/apiv3/endpoints/work-packages.apib
  19. 2
      docs/configuration/incoming-emails.md
  20. 15
      docs/installation/packaged/4-faq.md
  21. 13
      frontend/src/app/components/op-context-menu/handlers/op-types-context-menu.directive.ts
  22. 6
      frontend/src/app/components/wp-table/timeline/cells/timeline-cell-renderer.ts
  23. 2
      frontend/src/app/components/wp-table/timeline/cells/timeline-milestone-cell-renderer.ts
  24. 2
      frontend/src/app/components/wp-table/timeline/container/wp-timeline-container.directive.ts
  25. 13
      frontend/src/app/modules/common/colors/colors-autocompleter.component.ts
  26. 3
      frontend/src/app/modules/common/path-helper/apiv3/apiv3-paths.ts
  27. 3
      frontend/src/app/modules/common/path-helper/apiv3/projects/apiv3-project-paths.ts
  28. 38
      frontend/src/app/modules/common/path-helper/apiv3/types/apiv3-types-paths.ts
  29. 2
      frontend/src/app/modules/fields/edit/field-types/date-edit-field.ts
  30. 4
      frontend/src/app/modules/hal/dm-services/type-dm.service.ts
  31. 1
      lib/open_project/object_linking.rb
  32. 5
      lib/open_project/text_formatting/matchers/link_handlers/hash_separator.rb
  33. 2
      lib/open_project/text_formatting/matchers/link_handlers/work_packages.rb
  34. 36
      packaging/scripts/backup
  35. 2
      spec/contracts/work_packages/base_contract_spec.rb
  36. 2
      spec/features/work_packages/table/milestones_spec.rb
  37. 8
      spec/features/work_packages/table/queries/filter_spec.rb
  38. 2
      spec/features/work_packages/timeline/timeline_labels_spec.rb
  39. 2
      spec/lib/api/v3/work_packages/schema/specific_work_package_schema_spec.rb
  40. 2
      spec/lib/api/v3/work_packages/schema/typed_work_package_schema_spec.rb
  41. 4
      spec/lib/api/v3/work_packages/work_package_payload_representer_spec.rb
  42. 4
      spec/lib/api/v3/work_packages/work_package_representer_spec.rb
  43. 4
      spec/lib/open_project/text_formatting/markdown/markdown_formatting_spec.rb
  44. 26
      spec/lib/open_project/text_formatting/markdown/markdown_spec.rb
  45. 2
      spec/models/custom_actions/actions/date_spec.rb
  46. 2
      spec/models/version_spec.rb
  47. 28
      spec/models/work_package/work_package_reschedule_after_spec.rb
  48. 2
      spec/models/work_package/work_package_scheduling_spec.rb
  49. 8
      spec/models/work_package_spec.rb
  50. 4
      spec/requests/api/v3/work_package_resource_spec.rb
  51. 2
      spec/requests/api/v3/work_packages/form/work_package_form_resource_spec.rb
  52. 8
      spec/services/work_packages/update_service_integration_spec.rb
  53. 4
      spec_legacy/unit/project_spec.rb

@ -38,9 +38,11 @@
&.standalone
margin-left: initial
vertical-align: middle
.color--text-preview
padding: 2px 4px
.color--text-preview
padding: 1px 4px
font-size: 0.9rem
font-weight: bold
.color--milestone-icon,
.color--phase-icon

@ -188,6 +188,9 @@ ul.export-options
label.option-label
float: left
margin-right: 20px
// Ensure label and text are centered
display: flex
align-items: center
input
margin-top: 0px

@ -26,6 +26,16 @@
// See docs/COPYRIGHT.rdoc for more details.
//++
.user-mention:before
content: '@'
color: $gray-dark
.user-mention
@include varprop(color, content-link-color)
&:hover
text-decoration: underline
&:before
content: '@'
color: $gray-dark
span.user-mention
// Remove text selection cursor for group
cursor: default

@ -29,8 +29,10 @@
class HighlightingController < ApplicationController
before_action :determine_freshness
skip_before_action :check_if_login_required, only: [:styles]
def styles
expires_in 5.minute, public: false, must_revalidate: true
if stale?(last_modified: @last_modified_times.max, etag: cache_key, public: true)
OpenProject::Cache.fetch(@last_modified_times.max) do
render template: 'highlighting/styles', formats: [:css]

@ -191,8 +191,6 @@ class TimelogController < ApplicationController
end
end
end
rescue ::ActionController::RedirectBackError
redirect_to action: 'index', project_id: @time_entry.project
end
private

@ -198,8 +198,6 @@ class UsersController < ApplicationController
end
end
end
rescue ::ActionController::RedirectBackError
redirect_to controller: '/users', action: 'edit', id: @user
end
def change_status_info

@ -29,7 +29,7 @@
#++
module ColorsHelper
def options_for_colors(colored_thing, default_label: I18n.t('colors.label_no_color'), default_color: nil)
def options_for_colors(colored_thing, default_label: I18n.t('colors.label_no_color'), default_color: '')
s = content_tag(:option, default_label, value: default_color)
Color.find_each do |c|
options = {}

@ -30,7 +30,7 @@ class AttributeHelpText::WorkPackage < AttributeHelpText
def self.available_attributes
attributes = ::Type.translated_work_package_form_attributes
# Start and due dates are joined into a single field for non-milestones
# Start and finish dates are joined into a single field for non-milestones
attributes.delete 'start_date'
attributes.delete 'due_date'

@ -563,7 +563,7 @@ class Project < ActiveRecord::Base
].flatten.compact.min
end
# The latest due date of an issue or version
# The latest finish date of an issue or version
def due_date
[
work_packages.maximum('due_date'),

@ -107,7 +107,7 @@ class Version < ActiveRecord::Base
status == 'open'
end
# Returns true if the version is completed: due date reached and no open issues
# Returns true if the version is completed: finish date reached and no open issues
def completed?
effective_date && (effective_date <= Date.today) && open_issues_count.zero?
end
@ -146,7 +146,7 @@ class Version < ActiveRecord::Base
end
deprecated_alias :closed_pourcent, :closed_percent
# Returns true if the version is overdue: due date reached and some open issues
# Returns true if the version is overdue: finish date reached and some open issues
def overdue?
effective_date && (effective_date < Date.today) && (open_issues_count > 0)
end

@ -369,7 +369,7 @@ class WorkPackage < ActiveRecord::Base
end
end
# Is the amount of work done less than it should for the due date
# Is the amount of work done less than it should for the finish date
def behind_schedule?
return false if start_date.nil? || due_date.nil?
done_date = start_date + (duration * done_ratio / 100).floor

@ -39,7 +39,7 @@ module WorkPackage::SchedulingRules
end
# Calculates the minimum date that
# will not violate the precedes relations (max(due date, start date) + delay)
# will not violate the precedes relations (max(finish date, start date) + delay)
# of this work package or its ancestors
# e.g.
# AP(due_date: 2017/07/24, delay: 1)-precedes-A
@ -74,10 +74,10 @@ module WorkPackage::SchedulingRules
# Returns the time scheduled for this work package.
#
# Example:
# Start Date: 2/26/09, Due Date: 3/04/09, duration => 7
# Start Date: 2/26/09, Due Date: 2/26/09, duration => 1
# Start Date: 2/26/09, Due Date: - , duration => 1
# Start Date: - , Due Date: 2/26/09, duration => 1
# Start Date: 2/26/09, Finish Date: 3/04/09, duration => 7
# Start Date: 2/26/09, Finish Date: 2/26/09, duration => 1
# Start Date: 2/26/09, Finish Date: - , duration => 1
# Start Date: - , Finish Date: 2/26/09, duration => 1
def duration
if start_date && due_date
due_date - start_date + 1

@ -1,6 +1,6 @@
<%
colored_resource = Proc.new do |name, scope|
scope.where.not(color_id: nil).includes(:color).find_each do |entry|
scope.where.not(colors: { id: nil }).includes(:color).find_each do |entry|
color = entry.color
styles = color.color_styles

@ -224,7 +224,7 @@ en:
**You can:**
* create new phases and milestones by simply clicking in the project plan,
* change phases and milestones with drag and drop,
* add labels, such as start and due date, title, or assignee,
* add labels, such as start and finish date, title, or assignee,
* add dependencies by right clicking on a phase or milestone and choose pre-decessor or follower,
* custom columns, group, filter and save timeline reports to have them at your fingertips.
@ -248,7 +248,7 @@ en:
* change title or description,
* assign it to a team member,
* comment on topics or notify team members with @-notifications,
* set status, priority, due dates or other custom fields,
* set status, priority, finish dates or other custom fields,
* include documents or screenshots with copy & paste,
* add relations to other work packages,
* change forms in the Administration settings.

@ -215,7 +215,7 @@ en:
edit_query: "Edit embedded query"
reset: "Reset to defaults"
type_color_text: |
Click to assign or change the color of this type. The selected color will is used to distinguish work packages
Click to assign or change the color of this type. The selected color distinguishes work packages
in Gantt charts.
versions:
@ -413,7 +413,7 @@ en:
auto_hide_popups: "Auto-hide success notifications"
warn_on_leaving_unsaved: "Warn me when leaving a work package with unsaved changes"
version:
effective_date: "Due date"
effective_date: "Finish date"
sharing: "Sharing"
wiki_content:
text: "Text"
@ -645,7 +645,7 @@ en:
default_columns: "Default columns"
description: "Description"
display_sums: "Display Sums"
due_date: "Due date"
due_date: "Finish date"
estimated_hours: "Estimated time"
estimated_time: "Estimated time"
firstname: "First name"
@ -1257,6 +1257,7 @@ en:
label_group_by: "Group by"
label_group_new: "New group"
label_group: "Group"
label_group_named: "Group %{name}"
label_group_plural: "Groups"
label_help: "Help"
label_here: here
@ -1516,6 +1517,7 @@ en:
label_used_by_types: "Used by types"
label_used_in_projects: "Used in projects"
label_user: "User"
label_user_named: "User %{name}"
label_user_activity: "%{value}'s activity"
label_user_anonymous: "Anonymous"
label_user_mail_option_all: "For any event on all my projects"
@ -2542,7 +2544,7 @@ en:
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "Done ratio cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Due date cannot be set on parent work packages."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Estimated hours cannot be set on parent work packages."
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."

@ -434,7 +434,7 @@ en:
button_deactivate: 'Hide Gantt chart'
cancel: Cancel
change: "Change in planning"
due_date: "Due date"
due_date: "Finish date"
empty: "(empty)"
error: "An error has occurred."
errors:
@ -569,7 +569,7 @@ en:
createdAt: "Created on"
description: "Description"
date: "Date"
dueDate: "Due date"
dueDate: "Finish date"
estimatedTime: "Estimated time"
spentTime: "Spent time"
category: "Category"

@ -56,14 +56,14 @@ The list of values can either consist of a list of links or of a list of strings
```
{
"_type": "DueDateQueryFilter",
"name": "Due date",
"name": "Finish date",
"values": [
"1"
],
"_links": {
"filter": {
"href": "/api/v3/queries/filters/dueDate",
"title": "Due date"
"title": "Finish date"
},
"operator": {
"href": "/api/v3/queries/operators/<t+",
@ -134,14 +134,14 @@ If the values are nonprimitive (e.g. User, Project), they will be listed as obje
},
{
"_type": "DueDateQueryFilter",
"name": "Due date",
"name": "Finish date",
"values": [
"1"
],
"_links": {
"filter": {
"href": "/api/v3/queries/filters/dueDate",
"title": "Due date"
"title": "Finish date"
},
"operator": {
"href": "/api/v3/queries/operators/<t+",
@ -775,14 +775,14 @@ Same as [viewing an existing, persisted Query](#queries-query-get) in its respon
},
{
"_type": "DueDateQueryFilter",
"name": "Due date",
"name": "Finish date",
"values": [
"1"
],
"_links": {
"filter": {
"href": "/api/v3/queries/filters/dueDate",
"title": "Due date"
"title": "Finish date"
},
"operator": {
"href": "/api/v3/queries/operators/<t+",
@ -974,14 +974,14 @@ Same as [viewing an existing, persisted Query](#queries-query-get) in its respon
},
{
"_type": "DueDateQueryFilter",
"name": "Due date",
"name": "Finish date",
"values": [
"1"
],
"_links": {
"filter": {
"href": "/api/v3/queries/filters/dueDate",
"title": "Due date"
"title": "Finish date"
},
"operator": {
"href": "/api/v3/queries/operators/<t+",
@ -1187,14 +1187,14 @@ Same as [viewing an existing, persisted Query](#queries-query-get) in its respon
},
{
"_type": "DueDateQueryFilter",
"name": "Due date",
"name": "Finish date",
"values": [
"1"
],
"_links": {
"filter": {
"href": "/api/v3/queries/filters/dueDate",
"title": "Due date"
"title": "Finish date"
},
"operator": {
"href": "/api/v3/queries/operators/<t+",

@ -71,11 +71,11 @@ the human readable name of custom fields.
Properties that cannot be set directly on parent work packages are inferred from their children instead:
* `startDate` is the earliest start date from its children
* `dueDate` is the latest due date from its children
* `dueDate` is the latest finish date from its children
* `estimatedTime` is the sum of estimated times from its children
* `percentageDone` is the weighted average of the sum of its children percentages done. The weight is given by the average of its children estimatedHours. However, if the percentage done is given by a work package's status, then only the status matters and no value is inferred.
Start date can also not be earlier than a due date of any predecessor.
Start date can also not be earlier than a finish date of any predecessor.
While attachments are returned as a link which's content is to be fetched separately, clients can choose to
replace the work package's attachments by providing an array of already uploaded [Attachment resources](#attachments) on [create](#work-packages-work-packages-post)

@ -127,7 +127,7 @@ Other available keys for the email are:
| Type | sets the type | type:Milestone |
| Version | sets the version | version:v4.1.0 |
| Start date | sets the start date | start date:2015-02-28 |
| Due date | sets the due date | |
| Due date | sets the finish date | |
| Done ratio | sets the done ratio. Use a number | Done ratio:40 |
| Status | sets the status | Status:closed |
| priority | sets the priority | priority:High |

@ -37,6 +37,19 @@ You can either try the manual installation, or ask in the forum whether this cou
Linux packages are currently the most stable option, since they are regularly tested and provide an installer to help you configure your OpenProject installation. Docker images do not get the same level of testing.
### Do you provide different release channels?
Yes! We release OpenProject in separate release channels that you can try out. For production environments, **always** use the `stable/MAJOR` (e.g., stable/8) package source that will receive stable and release updates. Every major upgrade will result in a source switch (from `stable/7` to `stable/8` for example).
A closer look at the available branches:
* **stable/8**: Next or current stable releases, starting with 8.0.0 until the last minor and patch releases of 8.X.Y are released, this will receive updates. As of this writing, we're in the last days before releasing 8.0.0 in this channel.
* **stable/7**: Previous stable release, will receive critical updates and bug fixes while enterprise support depends on it.
* **release/8.0/**: Regular (usually daily) release builds for the current next patch release (or for the first release in this version, such as 8.0.0). This will contain early bugfixes before they are being release into stable. **Do not use in production**. But, for upgrading to the next major version, this can be regarded as a _release candidate channel_ that you can use to test your upgrade on a copy of your production environment.
* **dev**: Daily builds of the current development build of OpenProject. While we try to keep this operable, this may result in broken code and/or migrations from time to time. Use when you're interested what the next release of OpenProject will look like. **Do not use in production!**
### How to upgrade my OpenProject installation?
Please refer to the documentation at https://www.openproject.org/operations/upgrading/
@ -62,7 +75,7 @@ Here is how you do it using [certbot](https://github.com/certbot/certbot):
curl https://dl.eff.org/certbot-auto > /usr/local/bin/certbot-auto
chmod a+x /usr/local/bin/certbot-auto
certbot-auto certonly --webroot --webroot-path /opt/openproject/public -d openprojecct.mydomain.com
This requires your OpenProject server to be available from the Internet on port 443 or 80.

@ -36,6 +36,7 @@ import {OpContextMenuTrigger} from "core-components/op-context-menu/handlers/op-
import {TypeResource} from 'core-app/modules/hal/resources/type-resource';
import {CollectionResource} from 'core-app/modules/hal/resources/collection-resource';
import {IWorkPackageCreateServiceToken} from "core-components/wp-new/wp-create.service.interface";
import {TypeDmService} from "core-app/modules/hal/dm-services/type-dm.service";
@Directive({
selector: '[opTypesCreateDropdown]'
@ -50,8 +51,7 @@ export class OpTypesContextMenuDirective extends OpContextMenuTrigger {
constructor(readonly elementRef:ElementRef,
readonly opContextMenu:OPContextMenuService,
readonly $state:StateService,
@Inject(IWorkPackageCreateServiceToken) protected wpCreate:WorkPackageCreateService) {
readonly typeDmService:TypeDmService) {
super(elementRef, opContextMenu);
}
@ -67,10 +67,9 @@ export class OpTypesContextMenuDirective extends OpContextMenuTrigger {
this.stateName = 'work-packages.new';
}
this.loadingPromise = this.wpCreate.getEmptyForm(this.projectIdentifier)
.then((form:any) => {
return this.buildItems(form.schema.type.allowedValues);
});
this.loadingPromise = this.typeDmService
.loadAll(this.projectIdentifier)
.then(types => this.buildItems(types));
}
protected open(evt:Event) {
@ -100,7 +99,7 @@ export class OpTypesContextMenuDirective extends OpContextMenuTrigger {
};
}
private buildItems(types:CollectionResource<TypeResource>) {
private buildItems(types:TypeResource[]) {
this.items = types.map((type:TypeResource) => {
return {
disabled: false,

@ -95,7 +95,7 @@ export class TimelineCellRenderer {
/**
* Assign changed dates to the work package.
* For generic work packages, assigns start and due date.
* For generic work packages, assigns start and finish date.
*
*/
public assignDateValues(changeset:WorkPackageChangeset,
@ -227,7 +227,7 @@ export class TimelineCellRenderer {
bar.style.backgroundImage = `linear-gradient(90deg, #F1F1F1 0%, rgba(255,255,255,0) 80%)`;
}
// only due date, fade out bar to the left
// only finish date, fade out bar to the left
if (_.isNaN(start.valueOf()) && !_.isNaN(due.valueOf())) {
start = due.clone();
bar.style.backgroundImage = `linear-gradient(90deg, rgba(255,255,255,0) 0%, #F1F1F1 100%)`;
@ -306,7 +306,7 @@ export class TimelineCellRenderer {
/**
* Render the generic cell element, a bar spanning from
* start to due date.
* start to finish date.
*/
public render(renderInfo:RenderInfo):HTMLDivElement {
const bar = document.createElement('div');

@ -58,7 +58,7 @@ export class TimelineMilestoneCellRenderer extends TimelineCellRenderer {
/**
* Assign changed dates to the work package.
* For generic work packages, assigns start and due date.
* For generic work packages, assigns start and finish date .
*
*/
public assignDateValues(changeset:WorkPackageChangeset,

@ -372,7 +372,7 @@ export class WorkPackageTimelineTableController implements AfterViewInit, OnDest
startDate,
date);
// due date
// finish date
newParams.dateDisplayEnd = moment.max(
newParams.dateDisplayEnd,
currentParams.now,

@ -57,14 +57,23 @@ export class ColorsAutocompleter implements OnInit {
const contrastingColor = item.data('background');
const bright = item.data('bright');
// Special case, no color
if (!color) {
const div = jQuery('<div>')
.append(item.text())
.addClass('ui-menu-item-wrapper');
return div;
}
const colorSquare = jQuery('<span>')
.addClass('color--preview')
.css('background-color', color);
const colorText = jQuery('<span>')
.addClass('color--text-preview')
.css('color', bright ? '#333333' : color)
.css('background-color', bright ? color : contrastingColor)
.css('color', bright ? '#333333' : '#FFFFFF')
.css('background-color', color)
.text(item.text());
const div = jQuery('<div>')

@ -36,6 +36,7 @@ import {
import {Apiv3QueriesPaths} from 'core-app/modules/common/path-helper/apiv3/queries/apiv3-queries-paths';
import {Apiv3ProjectPaths} from 'core-app/modules/common/path-helper/apiv3/projects/apiv3-project-paths';
import {ApiV3FilterBuilder} from "core-components/api/api-v3/api-v3-filter-builder";
import {Apiv3TypesPaths} from "core-app/modules/common/path-helper/apiv3/types/apiv3-types-paths";
export class ApiV3Paths {
// Base path
@ -60,7 +61,7 @@ export class ApiV3Paths {
public readonly priorities = new SimpleResourceCollection(this.apiV3Base, 'priorities');
// /api/v3/types
public readonly types = new SimpleResourceCollection(this.apiV3Base, 'types');
public readonly types = new Apiv3TypesPaths(this.apiV3Base);
// /api/v3/work_packages
public readonly work_packages = new ApiV3WorkPackagesPaths(this.apiV3Base);

@ -28,6 +28,7 @@
import {SimpleResource} from 'core-app/modules/common/path-helper/apiv3/path-resources';
import {Apiv3QueriesPaths} from 'core-app/modules/common/path-helper/apiv3/queries/apiv3-queries-paths';
import {Apiv3TypesPaths} from "core-app/modules/common/path-helper/apiv3/types/apiv3-types-paths";
export class Apiv3ProjectPaths extends SimpleResource {
// Base path
@ -39,6 +40,8 @@ export class Apiv3ProjectPaths extends SimpleResource {
public readonly queries = new Apiv3QueriesPaths(this.path);
public readonly types = new Apiv3TypesPaths(this.path);
public readonly work_packages = {
form: new SimpleResource(this.path, 'work_packages/form')
};

@ -0,0 +1,38 @@
// -- 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.
// ++
import {
SimpleResourceCollection
} from 'core-app/modules/common/path-helper/apiv3/path-resources';
import {Apiv3QueryPaths} from 'core-app/modules/common/path-helper/apiv3/queries/apiv3-query-paths';
export class Apiv3TypesPaths extends SimpleResourceCollection<Apiv3QueryPaths> {
constructor(basePath:string) {
super(basePath, 'types');
}
}

@ -85,7 +85,7 @@ export class DateEditField extends EditField {
/**
* Return the default date for the datepicker instance.
* If this field is the due date, we select the start date + 1 as the default.
* If this field is the finish date, we select the start date + 1 as the default.
*/
public get defaultDate():String {
const isDueDate = this.name === 'dueDate';

@ -41,8 +41,8 @@ export class TypeDmService {
protected pathHelper:PathHelperService) {
}
public loadAll():Promise<TypeResource[]> {
const typeUrl = this.pathHelper.api.v3.types.toString();
public loadAll(projectIdentifier:string|undefined):Promise<TypeResource[]> {
const typeUrl = this.pathHelper.api.v3.withOptionalProject(projectIdentifier).types.toString();
return this.halResourceService
.get<CollectionResource<TypeResource>>(typeUrl)

@ -49,6 +49,7 @@ module OpenProject
if user.active? || user.registered? || user.invited?
href = only_path ? user_path(user) : user_url(user)
options[:title] ||= I18n.t(:label_user_named, name: name)
link_to(name, href, options)
else

@ -91,7 +91,10 @@ module OpenProject::TextFormatting::Matchers
def render_group
if group = Group.find_by(id: oid)
content_tag(:span, group.name, class: 'user-mention')
content_tag :span,
group.name,
title: I18n.t(:label_group_named, name: group.name),
class: 'user-mention'
end
end
end

@ -75,7 +75,7 @@ module OpenProject::TextFormatting::Matchers
link_to("#{matcher.sep}#{work_package.id}",
work_package_path_or_url(id: work_package.id, only_path: context[:only_path]),
class: work_package_css_classes(work_package),
title: "#{truncate(work_package.subject, length: 100)} (#{work_package.status.try(:name)})")
title: "#{truncate(work_package.subject, escape: false, length: 100)} (#{work_package.status.try(:name)})")
end
end

@ -10,11 +10,20 @@ timestamp=$(date +"%Y%m%d%H%M%S")
echo -n "* Generating database backup..." >&2
tmpfile=$(mktemp)
dump_postgresql() {
dst="${TARGET}/postgresql-dump-${timestamp}.pgdump"
touch "$dst" && chmod 0640 "$dst"
pg_dump -Fc $DATABASE_URL > $dst
echo " done" >&2
echo "$dst"
}
database=$(ruby -ruri -e 'puts URI(ENV["DATABASE_URL"]).path[1..-1]')
dump_mysql() {
tmpfile=$(mktemp)
database=$(ruby -ruri -e 'puts URI(ENV["DATABASE_URL"]).path[1..-1]')
ruby -ruri -rcgi -e '
ruby -ruri -rcgi -e '
uri = URI(ENV["DATABASE_URL"])
params = CGI.parse(uri.query || "")
config=<<CONFIG
@ -29,12 +38,21 @@ CONFIG
config += %{ssl-ca="#{params["sslca"].first}"\n} if params.has_key?("sslca")
puts config' > ${tmpfile}
dst="${TARGET}/mysql-dump-${timestamp}.sql.gz"
touch "$dst" && chmod 0640 "$dst"
mysqldump --defaults-file=${tmpfile} --single-transaction "${database}" | gzip > "$dst"
echo " done" >&2
echo "$dst"
rm -f ${tmpfile}
dst="${TARGET}/mysql-dump-${timestamp}.sql.gz"
touch "$dst" && chmod 0640 "$dst"
mysqldump --defaults-file=${tmpfile} --single-transaction "${database}" | gzip > "$dst"
echo " done" >&2
echo "$dst"
rm -f ${tmpfile}
}
if [[ $DATABASE_URL == postgres* ]] ;
then
dump_postgresql
else
dump_mysql
fi
if [ -d "$SVN_REPOSITORIES" ]; then
dst="${TARGET}/svn-repositories-${timestamp}.tar.gz"

@ -257,7 +257,7 @@ describe WorkPackages::BaseContract do
end
end
describe 'due date' do
describe 'finish date' do
it_behaves_like 'a parent unwritable property', :due_date
it_behaves_like 'a date attribute', :due_date

@ -30,7 +30,7 @@ describe 'Inline editing milestones', js: true do
wp_table.expect_work_package_listed work_package
end
it 'mapping for start and due date in the table (regression #26044)' do
it 'mapping for start and finish date in the table (regression #26044)' do
start_date = wp_table.edit_field(work_package, :startDate)
due_date = wp_table.edit_field(work_package, :dueDate)

@ -119,7 +119,7 @@ describe 'filter work packages', js: true do
end
end
context 'by due date outside of a project' do
context 'by finish date outside of a project' do
let(:work_package_with_due_date) { FactoryBot.create :work_package, project: project, due_date: Date.today }
let(:work_package_without_due_date) { FactoryBot.create :work_package, project: project, due_date: Date.today + 5.days }
let(:wp_table) { ::Pages::WorkPackagesTable.new }
@ -134,7 +134,7 @@ describe 'filter work packages', js: true do
it 'allows filtering, saving and retrieving and altering the saved filter' do
filters.open
filters.add_filter_by('Due date',
filters.add_filter_by('Finish date',
'between',
[(Date.today - 1.day).strftime('%Y-%m-%d'), Date.today.strftime('%Y-%m-%d')],
'dueDate')
@ -160,12 +160,12 @@ describe 'filter work packages', js: true do
filters.open
filters.expect_filter_by('Due date',
filters.expect_filter_by('Finish date',
'between',
[(Date.today - 1.day).strftime('%Y-%m-%d'), Date.today.strftime('%Y-%m-%d')],
'dueDate')
filters.set_filter 'Due date', 'in more than', '1', 'dueDate'
filters.set_filter 'Finish date', 'in more than', '1', 'dueDate'
loading_indicator_saveguard
wp_table.expect_work_package_listed work_package_without_due_date

@ -163,7 +163,7 @@ RSpec.feature 'Work package timeline labels',
farRight: 'Status'
config_modal.update_labels left: 'Start date',
right: 'Due date',
right: 'Finish date',
farRight: 'Subject'
# Check overriden labels

@ -220,7 +220,7 @@ describe ::API::V3::WorkPackages::Schema::SpecificWorkPackageSchema do
end
end
context 'due date' do
context 'finish date' do
it 'is not writable when the work package is a parent' do
allow(work_package).to receive(:leaf?).and_return(false)
expect(subject.writable?(:due_date)).to be false

@ -64,7 +64,7 @@ describe ::API::V3::WorkPackages::Schema::TypedWorkPackageSchema do
expect(subject.writable?(:start_date)).to be true
end
it 'due date is writable' do
it 'finish date is writable' do
expect(subject.writable?(:due_date)).to be true
end
end

@ -198,7 +198,7 @@ describe ::API::V3::WorkPackages::WorkPackagePayloadRepresenter do
let(:json_path) { 'dueDate' }
end
context 'no due date' do
context 'no finish date' do
let(:work_package) { FactoryBot.build(:work_package, due_date: nil) }
it 'renders as null' do
@ -235,7 +235,7 @@ describe ::API::V3::WorkPackages::WorkPackagePayloadRepresenter do
let(:json_path) { 'date' }
end
context 'no due date' do
context 'no finish date' do
let(:work_package) do
FactoryBot.build_stubbed(:work_package,
type: FactoryBot.build_stubbed(:type),

@ -136,7 +136,7 @@ describe ::API::V3::WorkPackages::WorkPackageRepresenter do
let(:json_path) { 'dueDate' }
end
context 'no due date' do
context 'no finish date' do
let(:work_package) { FactoryBot.build(:work_package, id: 42, due_date: nil) }
it 'renders as null' do
@ -175,7 +175,7 @@ describe ::API::V3::WorkPackages::WorkPackageRepresenter do
let(:json_path) { 'date' }
end
context 'no due date' do
context 'no finish date' do
before do
work_package.due_date = nil
end

@ -121,7 +121,7 @@ describe OpenProject::TextFormatting::Formats::Markdown::Formatter do
context 'with path only' do
it 'outputs the reference' do
assert_html_output(
'Link to user:"foo@bar.com"' => %(Link to <a class="user-mention" href="/users/#{user.id}">Foo Barrit</a>)
'Link to user:"foo@bar.com"' => %(Link to <a class="user-mention" href="/users/#{user.id}" title="User Foo Barrit">Foo Barrit</a>)
)
end
end
@ -131,7 +131,7 @@ describe OpenProject::TextFormatting::Formats::Markdown::Formatter do
assert_html_output(
{
'Link to user:"foo@bar.com"' =>
%(Link to <a class="user-mention" href="http://openproject.org/users/#{user.id}">Foo Barrit</a>)
%(Link to <a class="user-mention" href="http://openproject.org/users/#{user.id}" title="User Foo Barrit">Foo Barrit</a>)
},
only_path: false
)

@ -249,6 +249,22 @@ describe OpenProject::TextFormatting,
it { is_expected.to be_html_eql("<p>##{issue.id}</p>") }
end
context 'WP subject with escapable chars' do
let(:work_package) do
FactoryBot.create :work_package, subject: "Title with \"quote\" and 'sòme 'chárs."
end
let(:issue_link) do
link_to("##{issue.id}",
work_package_path(issue),
class: 'issue work_package status-3 priority-1 created-by-me',
title: "#{issue.subject} (#{issue.status})")
end
subject { format_text("##{issue.id}") }
it { is_expected.to be_html_eql("<p>#{issue_link}</p>") }
end
context 'Cyclic Description Links' do
let(:issue2) do
FactoryBot.create :work_package,
@ -321,7 +337,7 @@ describe OpenProject::TextFormatting,
subject { format_text("user##{linked_project_member.id}") }
it {
is_expected.to be_html_eql("<p>#{link_to(linked_project_member.name, { controller: :users, action: :show, id: linked_project_member.id }, class: 'user-mention')}</p>")
is_expected.to be_html_eql("<p>#{link_to(linked_project_member.name, { controller: :users, action: :show, id: linked_project_member.id }, title: "User #{linked_project_member.name}", class: 'user-mention')}</p>")
}
end
@ -341,7 +357,7 @@ describe OpenProject::TextFormatting,
context 'with a common login name' do
subject { format_text("user:\"#{linked_project_member.login}\"") }
it { is_expected.to be_html_eql("<p>#{link_to(linked_project_member.name, { controller: :users, action: :show, id: linked_project_member.id }, class: 'user-mention')}</p>") }
it { is_expected.to be_html_eql("<p>#{link_to(linked_project_member.name, { controller: :users, action: :show, id: linked_project_member.id }, title: "User #{linked_project_member.name}", class: 'user-mention')}</p>") }
end
context "with an email address as login name" do
@ -353,7 +369,7 @@ describe OpenProject::TextFormatting,
end
subject { format_text("user:\"#{linked_project_member.login}\"") }
it { is_expected.to be_html_eql("<p>#{link_to(linked_project_member.name, { controller: :users, action: :show, id: linked_project_member.id }, class: 'user-mention')}</p>") }
it { is_expected.to be_html_eql("<p>#{link_to(linked_project_member.name, { controller: :users, action: :show, id: linked_project_member.id }, title: "User #{linked_project_member.name}", class: 'user-mention')}</p>") }
end
end
@ -388,7 +404,9 @@ describe OpenProject::TextFormatting,
subject { format_text("group##{linked_project_member_group.id}") }
it 'produces the expected html' do
is_expected.to be_html_eql("<p><span class='user-mention'>#{linked_project_member_group.name}</span></p>")
is_expected.to be_html_eql(
"<p><span class='user-mention' title='Group #{linked_project_member_group.name}'>#{linked_project_member_group.name}</span></p>"
)
end
end

@ -38,7 +38,7 @@ describe CustomActions::Actions::Date, type: :model do
describe '#apply' do
let(:work_package) { FactoryBot.build_stubbed(:stubbed_work_package) }
it 'sets both start and due date to the action\'s value' do
it 'sets both start and finish date to the action\'s value' do
instance.values = [Date.today]
instance.apply(work_package)

@ -33,7 +33,7 @@ describe Version, type: :model do
it { is_expected.to be_valid }
it 'rejects a due date that is smaller than the start date' do
it 'rejects a finish date that is smaller than the start date' do
version.start_date = '2013-05-01'
version.effective_date = '2012-01-01'

@ -51,7 +51,7 @@ describe WorkPackage, '#reschedule_after', type: :model do
login_as(user)
end
describe 'for a single node having start and due date' do
describe 'for a single node having start and finish date' do
before do
instance.start_date = Date.today
instance.due_date = Date.today + 7.days
@ -63,12 +63,12 @@ describe WorkPackage, '#reschedule_after', type: :model do
expect(instance.start_date).to eq(Date.today + 3.days)
end
it 'should set the set the due date plus the duration' do
it 'should set the set the finish date plus the duration' do
expect(instance.due_date).to eq(Date.today + 10.days)
end
end
describe 'for a single node having neither start nor due date' do
describe 'for a single node having neither start nor finish date' do
before do
instance.start_date = nil
instance.due_date = nil
@ -80,12 +80,12 @@ describe WorkPackage, '#reschedule_after', type: :model do
expect(instance.start_date).to eq(Date.today + 3.days)
end
it 'should set the set the due date plus the duration' do
it 'should set the set the finish date plus the duration' do
expect(instance.due_date).to eq(Date.today + 3.days)
end
end
describe 'for a single node having only a due date' do
describe 'for a single node having only a finish date' do
before do
instance.start_date = nil
instance.due_date = Date.today + 7.days
@ -97,7 +97,7 @@ describe WorkPackage, '#reschedule_after', type: :model do
expect(instance.start_date).to eq(Date.today + 3.days)
end
it 'should set the set the due date plus the duration' do
it 'should set the set the finish date plus the duration' do
expect(instance.due_date).to eq(Date.today + 3.days)
end
end
@ -117,7 +117,7 @@ describe WorkPackage, '#reschedule_after', type: :model do
expect(instance.start_date).to eq(Date.today + 3.days)
end
it "should set the set the due date to the provided date plus the child's duration" do
it "should set the set the finish date to the provided date plus the child's duration" do
instance.reload
expect(instance.due_date).to eq(Date.today + 10.days)
end
@ -127,14 +127,14 @@ describe WorkPackage, '#reschedule_after', type: :model do
expect(child.start_date).to eq(Date.today + 3.days)
end
it "should set the set child's due date to the provided date plus the child's duration" do
it "should set the set child's finish date to the provided date plus the child's duration" do
child.reload
expect(child.due_date).to eq(Date.today + 10.days)
end
end
describe "with a child
while the new date is set to be between the child's start and due date" do
while the new date is set to be between the child's start and finish date" do
before do
child.start_date = Date.today + 1.day
child.due_date = Date.today + 7.days
@ -153,7 +153,7 @@ describe WorkPackage, '#reschedule_after', type: :model do
expect(instance.start_date).to eq(Date.today + 3.days)
end
it "should set the set the due date to the provided date plus the child's duration" do
it "should set the set the finish date to the provided date plus the child's duration" do
instance.reload
expect(instance.due_date).to eq(Date.today + 9.days)
end
@ -163,7 +163,7 @@ describe WorkPackage, '#reschedule_after', type: :model do
expect(child.start_date).to eq(Date.today + 3.days)
end
it "should set the set child's due date to the provided date plus the child's duration" do
it "should set the set child's finish date to the provided date plus the child's duration" do
child.reload
expect(child.due_date).to eq(Date.today + 9.days)
end
@ -186,7 +186,7 @@ describe WorkPackage, '#reschedule_after', type: :model do
expect(instance.start_date).to eq(Date.today + 3.days)
end
it "should set the set the due date to the provided date plus the child's duration" do
it "should set the set the finish date to the provided date plus the child's duration" do
instance.reload
expect(instance.due_date).to eq(Date.today + 10.days)
end
@ -196,7 +196,7 @@ describe WorkPackage, '#reschedule_after', type: :model do
expect(child.start_date).to eq(Date.today + 3.days)
end
it "should set the set child's due date to the provided date plus the grandchild's duration" do
it "should set the set child's finish date to the provided date plus the grandchild's duration" do
child.reload
expect(child.due_date).to eq(Date.today + 10.days)
end
@ -206,7 +206,7 @@ describe WorkPackage, '#reschedule_after', type: :model do
expect(grandchild.start_date).to eq(Date.today + 3.days)
end
it "should set the set grandchild's due date to the provided date plus the grandchild's duration" do
it "should set the set grandchild's finish date to the provided date plus the grandchild's duration" do
grandchild.reload
expect(grandchild.due_date).to eq(Date.today + 10.days)
end

@ -65,7 +65,7 @@ describe WorkPackage, type: :model do
it_behaves_like 'on time'
end
context 'no due date' do
context 'no finish date' do
let(:due_date) { nil }
it_behaves_like 'on time'

@ -820,7 +820,7 @@ describe WorkPackage, type: :model do
let(:instance) { send(subclass) }
describe "w/ today as start date
w/ tomorrow as due date" do
w/ tomorrow as finish date" do
before do
work_package.start_date = Date.today
work_package.due_date = Date.today + 1.day
@ -832,7 +832,7 @@ describe WorkPackage, type: :model do
end
describe "w/ today as start date
w/ today as due date" do
w/ today as finish date" do
before do
work_package.start_date = Date.today
work_package.due_date = Date.today
@ -844,7 +844,7 @@ describe WorkPackage, type: :model do
end
describe "w/ today as start date
w/o a due date" do
w/o a finish date" do
before do
work_package.start_date = Date.today
work_package.due_date = nil
@ -856,7 +856,7 @@ describe WorkPackage, type: :model do
end
describe "w/o a start date
w today as due date" do
w today as finish date" do
before do
work_package.start_date = nil
work_package.due_date = Date.today

@ -366,7 +366,7 @@ describe 'API v3 Work package resource', type: :request, content_type: :json do
it_behaves_like 'lock version updated'
end
context 'due date' do
context 'finish date' do
let(:dateString) { Date.today.to_date.iso8601 }
let(:params) { valid_params.merge(dueDate: dateString) }
@ -374,7 +374,7 @@ describe 'API v3 Work package resource', type: :request, content_type: :json do
it { expect(response.status).to eq(200) }
it 'should respond with updated due date' do
it 'should respond with updated finish date' do
expect(subject.body).to be_json_eql(dateString.to_json).at_path('dueDate')
end

@ -279,7 +279,7 @@ describe 'API v3 Work package form resource', type: :request do
end
end
describe 'due date' do
describe 'finish date' do
include_context 'post request'
context 'valid date' do

@ -361,13 +361,13 @@ describe WorkPackages::UpdateService, 'integration tests', type: :model do
expect(subject)
.to be_success
# receives the provided start/due date
# receives the provided start/finish date
expect(work_package.start_date)
.to eql(attributes[:start_date])
expect(work_package.due_date)
.to eql(attributes[:due_date])
# receives the min/max of the children's start/due date
# receives the min/max of the children's start/finish date
[parent_work_package,
grandparent_work_package].each do |wp|
wp.reload
@ -651,7 +651,7 @@ describe WorkPackages::UpdateService, 'integration tests', type: :model do
due_date: Date.today + 10.days }
end
it 'propagates the changes to start/due date along' do
it 'propagates the changes to start/finish date along' do
expect(subject)
.to be_success
@ -821,7 +821,7 @@ describe WorkPackages::UpdateService, 'integration tests', type: :model do
due_date: Date.today }
end
it 'propagates the changes to start/due date along' do
it 'propagates the changes to start/finish date along' do
expect(subject)
.to be_success

@ -1027,7 +1027,7 @@ describe Project, type: :model do
assert_nil @project.due_date
end
it "should be the latest due date of it's issues" do
it "should be the latest finish date of it's issues" do
future = 7.days.from_now.to_date
FactoryBot.create(:work_package, project: @project, due_date: future)
FactoryBot.create(:work_package, project: @project, due_date: Date.today)
@ -1035,7 +1035,7 @@ describe Project, type: :model do
assert_equal future, @project.due_date
end
it "should be the latest due date of it's versions" do
it "should be the latest finish date of it's versions" do
future = 7.days.from_now.to_date
@project.versions << FactoryBot.create(:version, effective_date: future)
@project.versions << FactoryBot.create(:version, effective_date: Date.today)

Loading…
Cancel
Save