Merge branch 'release/9.1' into merge/release_9_1_into_dev

pull/7529/head
ulferts 5 years ago
commit 31d16d7948
No known key found for this signature in database
GPG Key ID: A205708DE1284017
  1. 4
      config/locales/crowdin/js-de.yml
  2. 55
      db/migrate/20190722082648_add_derived_estimated_hours_to_work_packages.rb
  3. 5
      frontend/src/app/components/wp-card-view/wp-card-view.component.html
  4. 10
      frontend/src/app/components/wp-card-view/wp-card-view.component.ts
  5. 3
      frontend/src/app/components/wp-grid/wp-grid.component.ts
  6. 5
      frontend/src/app/modules/common/no-results/no-results.component.html
  7. 4
      frontend/src/app/modules/common/no-results/no-results.component.ts
  8. 2
      modules/avatars/config/locales/crowdin/js-fr.yml

@ -295,7 +295,7 @@ de:
label_total_progress: "%{percent}% Gesamtfortschritt"
label_total_amount: "Gesamt: %{amount}"
label_updated_on: "aktualisiert am"
label_value_derived_from_children: "(value derived from children)"
label_value_derived_from_children: "(aggregierter Wert von Kindelementen)"
label_warning: "Warnung"
label_work_package: "Arbeitspaket"
label_work_package_plural: "Arbeitspakete"
@ -821,7 +821,7 @@ de:
one: "ein untergeordnetes Arbeitspaket"
other: "%{count} untergeordnete Arbeitspakete"
hour:
one: "1 h"
one: "%{count} h"
other: "%{count} h"
zen_mode:
button_activate: 'Zen-Modus aktivieren'

@ -29,18 +29,23 @@ class AddDerivedEstimatedHoursToWorkPackages < ActiveRecord::Migration[5.2]
# estimated hours set based on their children through the UpdateAncestorsService.
#
# We move this value to the derived_estimated_hours column and clear
# the estimated_hours column. In the future users can estimte the time
# for parent work pacages separately there while the UpdateAncestorsService
# the estimated_hours column. In the future users can estimate the time
# for parent work packages separately while the UpdateAncestorsService
# only touches the derived_estimated_hours column.
def migrate_to_derived_estimated_hours!
last_id = Journal.order(id: :desc).limit(1).pluck(:id).first || 0
wp_journals = "work_package_journals"
work_packages = WorkPackageWithRelations.with_children
work_packages = WorkPackageWithRelations.with_children.where("estimated_hours > ?", 0)
work_packages.update_all("derived_estimated_hours = estimated_hours, estimated_hours = NULL")
work_packages = WorkPackageWithRelations.with_children.where("derived_estimated_hours > ?", 0)
create_journals_for work_packages
create_work_package_journals last_id: last_id
create_customizable_journals last_id: last_id
create_attachable_journals last_id: last_id
work_packages.each(&:touch) # invalidate cache
end
##
@ -115,4 +120,48 @@ class AddDerivedEstimatedHoursToWorkPackages < ActiveRecord::Migration[5.2]
) AS results
")
end
def create_customizable_journals(last_id:)
journals = "journals"
customizable = "customizable_journals"
work_packages = "work_packages"
WorkPackage.connection.execute("
INSERT INTO #{customizable} (journal_id, custom_field_id, value)
SELECT #{journals}.id, #{customizable}.custom_field_id, #{customizable}.value
FROM #{journals} -- take the journal ID from here (ID of newly created journals from above)
LEFT JOIN #{work_packages}
ON #{work_packages}.id = #{journals}.journable_id AND #{journals}.journable_type = 'WorkPackage'
RIGHT JOIN #{customizable} -- keep everything else the same; there can be multiple customizable journals (custom fields)
ON #{customizable}.journal_id = (
SELECT MAX(id)
FROM #{journals}
WHERE #{journals}.journable_id = #{work_packages}.id AND journable_type = 'WorkPackage' AND #{journals}.id <= #{last_id}
-- we are selecting the latest previous (hence <= last_id) customizable journal here to copy its values
)
WHERE #{journals}.id > #{last_id} -- make sure to only create entries for the newly created journals
")
end
def create_attachable_journals(last_id:)
journals = "journals"
attachable = "attachable_journals"
work_packages = "work_packages"
WorkPackage.connection.execute("
INSERT INTO #{attachable} (journal_id, attachment_id, filename)
SELECT #{journals}.id, #{attachable}.attachment_id, #{attachable}.filename
FROM #{journals} -- take the journal ID from here (ID of newly created journals from above)
LEFT JOIN #{work_packages}
ON #{work_packages}.id = #{journals}.journable_id AND #{journals}.journable_type = 'WorkPackage'
RIGHT JOIN #{attachable} -- keep everything else the same; there can be multiple attachable journals (attachments)
ON #{attachable}.journal_id = (
SELECT MAX(id)
FROM #{journals}
WHERE #{journals}.journable_id = #{work_packages}.id AND journable_type = 'WorkPackage' AND #{journals}.id <= #{last_id}
-- we are selecting the latest previous (hence <= last_id) customizable journal here to copy its values
)
WHERE #{journals}.id > #{last_id} -- make sure to only create entries for the newly created journals
")
end
end

@ -71,3 +71,8 @@
</div>
</div>
<div *ngIf="showEmptyResultsBox && isResultEmpty">
<no-results [title]="text.noResults.title" [description]="text.noResults.description"></no-results>
</div>

@ -53,6 +53,8 @@ export class WorkPackageCardViewComponent implements OnInit {
@Input() public orientation:CardViewOrientation = 'vertical';
/** Whether cards are removable */
@Input() public cardsRemovable:boolean = false;
/** Whether a notification box shall be shown when there are no WP to display */
@Input() public showEmptyResultsBox:boolean = false;
/** Container reference */
@ViewChild('container', { static: true }) public container:ElementRef;
@ -61,11 +63,16 @@ export class WorkPackageCardViewComponent implements OnInit {
public trackByHref = AngularTrackingHelpers.trackByHrefAndProperty('lockVersion');
public query:QueryResource;
private _workPackages:WorkPackageResource[];
private _workPackages:WorkPackageResource[] = [];
public isResultEmpty:boolean = false;
public columns:QueryColumn[];
public text = {
removeCard: this.I18n.t('js.card.remove_from_list'),
addNewCard: this.I18n.t('js.card.add_new'),
noResults: {
title: this.I18n.t('js.work_packages.no_results.title'),
description: this.I18n.t('js.work_packages.no_results.description')
},
};
/** Inline create / reference properties */
@ -122,6 +129,7 @@ export class WorkPackageCardViewComponent implements OnInit {
).subscribe((query:QueryResource) => {
this.query = query;
this.workPackages = query.results.elements;
this.isResultEmpty = this.workPackages.length === 0;
this.cdRef.detectChanges();
});
}

@ -43,7 +43,8 @@ import {IsolatedQuerySpace} from "core-app/modules/work_packages/query-space/iso
[highlightingMode]="highlightingMode"
[showStatusButton]="false"
[orientation]="gridOrientation"
(onMoved)="switchToManualSorting()">
(onMoved)="switchToManualSorting()"
[showEmptyResultsBox]="true">
</wp-card-view>
`,
changeDetection: ChangeDetectionStrategy.OnPush,

@ -1,4 +1,5 @@
<i class="icon-info1" aria-hidden="true"></i>
<span class="generic-table--no-results-title"
[textContent]="title">
<span class="generic-table--no-results-title">
{{ title }}
<span *ngIf="description" [textContent]="description"></span>
</span>

@ -34,8 +34,8 @@ import {Component, Input, HostBinding} from '@angular/core';
})
export class NoResultsComponent {
@Input()
title:string;
@Input() title:string;
@Input() description:string;
@HostBinding('class.generic-table--no-results-container') setHostClass = true;
}

@ -3,7 +3,7 @@ fr:
label_preview: 'Aperçu'
button_update: 'Mettre à jour'
avatars:
label_choose_avatar: "Choose Avatar from file"
label_choose_avatar: "Choisir un avatar depuis un fichier"
uploading_avatar: "Uploading your avatar."
text_upload_instructions: |
Upload your own custom avatar of 128 by 128 pixels. Larger files will be resized and cropped to match.

Loading…
Cancel
Save