Added ability to view part relations on a part info page

This commit is contained in:
Jan Böhmer 2023-11-15 00:44:45 +01:00
parent cc2332a83a
commit 7f612bc371
7 changed files with 143 additions and 0 deletions

View file

@ -20,6 +20,7 @@ twig:
avatar_helper: '@App\Services\UserSystem\UserAvatarHelper'
available_themes: '%partdb.available_themes%'
saml_enabled: '%partdb.saml.enabled%'
part_preview_generator: '@App\Services\Attachments\PartPreviewGenerator'
when@test:
twig:

View file

@ -136,5 +136,17 @@ class PartAssociation extends AbstractDBElement
return $this;
}
/**
* Returns the translation key for the type of this association.
* If the type is set to OTHER, then the other_type field value is used.
* @return string
*/
public function getTypeTranslationKey(): string
{
if ($this->type === AssociationType::OTHER) {
return $this->other_type ?? 'Unknown';
}
return $this->type->getTranslationKey();
}
}

View file

@ -23,7 +23,9 @@ declare(strict_types=1);
namespace App\Entity\Parts\PartTraits;
use App\Entity\Parts\Part;
use App\Entity\Parts\PartAssociation;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Symfony\Component\Validator\Constraints\Valid;
use Doctrine\ORM\Mapping as ORM;
@ -89,4 +91,18 @@ trait AssociationTrait
{
return $this->associated_parts_as_other;
}
/**
* Returns all associations where this part is the owned or other part.
* @return Collection<PartAssociation>
*/
public function getAssociatedPartsAll(): Collection
{
return new ArrayCollection(
array_merge(
$this->associated_parts_as_owner->toArray(),
$this->associated_parts_as_other->toArray()
)
);
}
}

View file

@ -188,6 +188,15 @@
{% endif %}
{% endmacro %}
{% macro part_icon_link(part) %}
{% set preview_attach = part_preview_generator.tablePreviewAttachment(part) %}
{% if preview_attach %}
<img src="{{ attachment_thumbnail(preview_attach, 'thumbnail_xs') }}" class="entity-image-xs" alt="Part image"
{{ stimulus_controller('elements/hoverpic') }} data-thumbnail="{{ attachment_thumbnail(preview_attach) }}">
{% endif %}
<a href="{{ entity_url(part) }}">{{ part.name }}</a>
{% endmacro %}
{% macro entity_preview_sm(entity) %}
{# @var entity \App\Entity\Contracts\HasMasterAttachmentInterface #}
{% if entity.masterPictureAttachment and entity.masterPictureAttachment.picture and attachment_manager.fileExisting(entity.masterPictureAttachment) %}

View file

@ -0,0 +1,40 @@
{% import "helper.twig" as helper %}
{% macro assoc_row(assoc) %}
{# @var assoc \App\Entity\Parts\PartAssociation #}
<tr>
<td>{{ helper.part_icon_link(assoc.owner) }}</td>
<td>{{ assoc.typeTranslationKey | trans }}</td>
<td>{{ helper.part_icon_link(assoc.other) }}</td>
<td>{{ assoc.comment }}</td>
</tr>
{% endmacro %}
{% macro assoc_table(assocs, caption) %}
<div class="table-responsive">
<table class="table table-striped table-hover caption-top">
<caption>{{ caption | trans }}:</caption>
<thead>
<tr>
<th>{% trans %}part_association.table.from{% endtrans %}</th>
<th>{% trans %}part_association.table.type{% endtrans %}</th>
<th>{% trans %}part_association.table.to{% endtrans %}</th>
<th>{% trans %}part_association.edit.comment{% endtrans %}</th>
</tr>
</thead>
<tbody>
{% for assoc in assocs %}
{{ _self.assoc_row(assoc) }}
{% endfor %}
</tbody>
</table>
</div>
{% endmacro %}
{% if part.associatedPartsAsOwner is not empty %}
{{ _self.assoc_table(part.associatedPartsAsOwner, 'part_association.table.from_this_part') }}
{% endif %}
{% if part.associatedPartsAsOther is not empty %}
{{ _self.assoc_table(part.associatedPartsAsOther, 'part_association.table.to_this_part') }}
{% endif %}

View file

@ -88,6 +88,17 @@
</a>
</li>
{% endif %}
{% if part.associatedPartsAll is not empty %}
<li class="nav-item">
<a class="nav-link" id="associations-tab" data-bs-toggle="tab" href="#associations" role="tab">
<i class="fas fas fa-circle-nodes fa-fw fa-fw"></i>
{% trans %}part.edit.tab.associations{% endtrans %}
<span class="badge bg-secondary">{{ part.associatedPartsAll | length }}</span>
</a>
</li>
{% endif %}
<li class="nav-item {% if datatable is null %}not-allowed{% endif %}">
<a class="nav-link {% if datatable is null %}disabled{% endif %}" id="history-tab" data-bs-toggle="tab" href="#history" role="tab">
<i class="fas fa-history"></i>
@ -142,6 +153,12 @@
</div>
{% endif %}
{% if part.associatedPartsAll is not empty %}
<div class="tab-pane fade" id="associations" role="tabpanel" aria-labelledby="associations-tab">
{% include "parts/info/_associations.html.twig" %}
</div>
{% endif %}
<div class="tab-pane fade" id="projects" role="tabpanel" aria-labelledby="projects-tab">
{% include "parts/info/_projects.html.twig" %}
</div>

View file

@ -11867,5 +11867,53 @@ Please note, that you can not impersonate a disabled user. If you try you will g
<target>You can select here, how the chosen part is related to this part.</target>
</segment>
</unit>
<unit id="ulXO3uA" name="part_association.table.from_this_part">
<segment>
<source>part_association.table.from_this_part</source>
<target>Associations from this part to others</target>
</segment>
</unit>
<unit id="hDksqGC" name="part_association.table.from">
<segment>
<source>part_association.table.from</source>
<target>From</target>
</segment>
</unit>
<unit id="QyRxFA7" name="part_association.table.type">
<segment>
<source>part_association.table.type</source>
<target>Relation</target>
</segment>
</unit>
<unit id="6ZyXTCs" name="part_association.table.to">
<segment>
<source>part_association.table.to</source>
<target>To</target>
</segment>
</unit>
<unit id="Lwwff7k" name="part_association.type.compatible">
<segment>
<source>part_association.type.compatible</source>
<target>Is compatible with</target>
</segment>
</unit>
<unit id="tgOSN9E" name="part_association.table.to_this_part">
<segment>
<source>part_association.table.to_this_part</source>
<target>Associations to this part from others</target>
</segment>
</unit>
<unit id="J2hj9bY" name="part_association.type.other">
<segment>
<source>part_association.type.other</source>
<target>Other (custom value)</target>
</segment>
</unit>
<unit id="Sy57UAe" name="part_association.type.supersedes">
<segment>
<source>part_association.type.supersedes</source>
<target>Supersedes</target>
</segment>
</unit>
</file>
</xliff>