diff --git a/frontend/app/components/wp-fast-table/builders/relations/relation-row-builder.ts b/frontend/app/components/wp-fast-table/builders/relations/relation-row-builder.ts index ac36ef2d33..f6065267b2 100644 --- a/frontend/app/components/wp-fast-table/builders/relations/relation-row-builder.ts +++ b/frontend/app/components/wp-fast-table/builders/relations/relation-row-builder.ts @@ -11,6 +11,8 @@ import { import {UiStateLinkBuilder} from '../ui-state-link-builder'; import {QueryColumn} from '../../../wp-query/query-column'; import {$injectFields} from '../../../angular/angular-injector-bridge.functions'; +import {RelationColumnType} from '../../state/wp-table-relation-columns.service'; +import {States} from '../../../states.service'; export function relationGroupClass(workPackageId:string) { return `__relations-expanded-from-${workPackageId}`; @@ -22,19 +24,19 @@ export const internalDetailsColumn = { export class RelationRowBuilder extends SingleRowBuilder { public uiStateBuilder:UiStateLinkBuilder; + public states:States; public I18n:op.I18n; constructor(protected workPackageTable:WorkPackageTable) { super(workPackageTable); - this.uiStateBuilder = new UiStateLinkBuilder(); - $injectFields(this, 'I18n'); + $injectFields(this, 'I18n', 'states'); } /** * Build the columns on the given empty row */ - public buildEmptyRelationRow(from:WorkPackageResourceInterface, relation:RelationResource):[HTMLElement, boolean] { + public buildEmptyRelationRow(from:WorkPackageResourceInterface, relation:RelationResource, type:RelationColumnType):[HTMLElement, boolean] { const denormalized = relation.denormalized(from); const tr = this.createEmptyRelationRow(from, denormalized); const columns = this.wpTableColumns.getColumns(); @@ -45,7 +47,7 @@ export class RelationRowBuilder extends SingleRowBuilder { const td = document.createElement('td'); if (column.id === 'subject') { - this.buildRelationLabel(td, from, denormalized); + this.buildRelationLabel(td, from, denormalized, type); } if (column.id === 'id') { @@ -85,12 +87,22 @@ export class RelationRowBuilder extends SingleRowBuilder { return tr; } - private buildRelationLabel(cell:HTMLElement, from:WorkPackageResource, denormalized:DenormalizedRelationData) { - const type = this.I18n.t(`js.relation_labels.${denormalized.relationType}`); + private buildRelationLabel(cell:HTMLElement, from:WorkPackageResource, denormalized:DenormalizedRelationData, type:RelationColumnType) { + let typeLabel; + + // Add the relation label if this is a "Relations for " column + if (type === 'toType') { + typeLabel = this.I18n.t(`js.relation_labels.${denormalized.relationType}`); + } + // Add the WP type label if this is a " Relations" column + if (type === 'ofType') { + const wp = this.states.workPackages.get(denormalized.target.id).value!; + typeLabel = wp.type.name; + } const relationLabel = document.createElement('span'); relationLabel.classList.add('relation-row--type-label'); - relationLabel.textContent = type; + relationLabel.textContent = typeLabel; const textNode = document.createTextNode(denormalized.target.name); cell.appendChild(relationLabel); diff --git a/frontend/app/components/wp-fast-table/builders/relations/relations-render-pass.ts b/frontend/app/components/wp-fast-table/builders/relations/relations-render-pass.ts index 50ea8824db..343ed92282 100644 --- a/frontend/app/components/wp-fast-table/builders/relations/relations-render-pass.ts +++ b/frontend/app/components/wp-fast-table/builders/relations/relations-render-pass.ts @@ -42,10 +42,10 @@ export class RelationsRenderPass implements SecondaryRenderPass { return; } - _.each(this.wpTableRelationColumns.relationsToExtendFor(row.belongsTo, state.value!), (relation) => { + this.wpTableRelationColumns.relationsToExtendFor(row.belongsTo, state.value!, (relation, type) => { // Build each relation row (currently sorted by order defined in API) - const [relationRow,] = this.relationRowBuilder.buildEmptyRelationRow(row.belongsTo!, relation); + const [relationRow,] = this.relationRowBuilder.buildEmptyRelationRow(row.belongsTo!, relation, type); // Augment any data for the belonging work package row to it this.tablePass.augmentSecondaryElement(relationRow, row); diff --git a/frontend/app/components/wp-fast-table/state/wp-table-relation-columns.service.ts b/frontend/app/components/wp-fast-table/state/wp-table-relation-columns.service.ts index 53c13c1a37..7768e5f8e9 100644 --- a/frontend/app/components/wp-fast-table/state/wp-table-relation-columns.service.ts +++ b/frontend/app/components/wp-fast-table/state/wp-table-relation-columns.service.ts @@ -45,6 +45,8 @@ import {IQService} from 'angular'; import {HalRequestService} from '../../api/api-v3/hal-request/hal-request.service'; import {WorkPackageCacheService} from '../../work-packages/work-package-cache.service'; +export type RelationColumnType = 'toType' | 'ofType'; + export class WorkPackageTableRelationColumnsService extends WorkPackageTableBaseService { protected stateName = 'relationColumns' as TableStateStates; @@ -73,25 +75,31 @@ export class WorkPackageTableRelationColumnsService extends WorkPackageTableBase * @param workPackage * @param relation */ - public relationsToExtendFor(workPackage:WorkPackageResourceInterface, relations:RelationsStateValue|undefined):RelationResource[] { + public relationsToExtendFor(workPackage:WorkPackageResourceInterface, + relations:RelationsStateValue|undefined, + eachCallback:(relation:RelationResource, type:RelationColumnType) => void) { // Only if any relation columns or stored expansion state exist if (!this.wpTableColumns.hasRelationColumns() || this.state.isPristine()) { - return []; + return; } // Only if any relations exist for this work package if (_.isNil(relations)) { - return []; + return; } // Only if the work package has anything expanded const expanded = this.current.getExpandFor(workPackage.id); if (expanded === undefined) { - return []; + return; } const column = this.wpTableColumns.findById(expanded)!; - return this.relationsForColumn(workPackage, relations, column); + const type = this.relationColumnType(column); + + if (type !== null) { + _.each(relations, (relation) => eachCallback(relation as RelationResource, type)); + } } /** @@ -108,7 +116,8 @@ export class WorkPackageTableRelationColumnsService extends WorkPackageTableBase } // Get the type of TO work package - if (column._type === queryColumnTypes.RELATION_TO_TYPE) { + const type = this.relationColumnType(column); + if (type === 'toType') { const typeHref = (column as TypeRelationQueryColumn).type.href; return _.filter(relations, (relation:RelationResource) => { @@ -117,7 +126,7 @@ export class WorkPackageTableRelationColumnsService extends WorkPackageTableBase } // Get the relation types for OF relation columns - if (column._type === queryColumnTypes.RELATION_OF_TYPE) { + if (type === 'ofType') { const relationType = (column as RelationQueryColumn).relationType; return _.filter(relations, (relation:RelationResource) => { @@ -128,6 +137,17 @@ export class WorkPackageTableRelationColumnsService extends WorkPackageTableBase return []; } + public relationColumnType(column:QueryColumn):RelationColumnType|null { + switch(column._type) { + case queryColumnTypes.RELATION_TO_TYPE: + return 'toType'; + case queryColumnTypes.RELATION_OF_TYPE: + return 'ofType'; + default: + return null; + } + } + public getExpandFor(workPackageId:string):string | undefined { return this.current && this.current.getExpandFor(workPackageId); } diff --git a/spec/features/work_packages/table/relations_spec.rb b/spec/features/work_packages/table/relations_spec.rb index 251ccb12f4..03542288e7 100644 --- a/spec/features/work_packages/table/relations_spec.rb +++ b/spec/features/work_packages/table/relations_spec.rb @@ -80,7 +80,7 @@ describe 'Work Package table relations', js: true do wp_from_row.find(".#{type_column_follows} .wp-table--relation-indicator").click expect(page).to have_selector(".__relations-expanded-from-#{wp_from.id}", count: 2) related_row = page.first(".__relations-expanded-from-#{wp_from.id}") - expect(related_row).to have_selector('td', text: "Follows#{wp_to.subject}") + expect(related_row).to have_selector('td', text: "#{wp_to.type}#{wp_to.subject}") # Open Timeline # Should be initially closed