mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-21 01:25:55 +02:00
Added ability to view part relations on a part info page
This commit is contained in:
parent
cc2332a83a
commit
7f612bc371
7 changed files with 143 additions and 0 deletions
|
@ -20,6 +20,7 @@ twig:
|
||||||
avatar_helper: '@App\Services\UserSystem\UserAvatarHelper'
|
avatar_helper: '@App\Services\UserSystem\UserAvatarHelper'
|
||||||
available_themes: '%partdb.available_themes%'
|
available_themes: '%partdb.available_themes%'
|
||||||
saml_enabled: '%partdb.saml.enabled%'
|
saml_enabled: '%partdb.saml.enabled%'
|
||||||
|
part_preview_generator: '@App\Services\Attachments\PartPreviewGenerator'
|
||||||
|
|
||||||
when@test:
|
when@test:
|
||||||
twig:
|
twig:
|
||||||
|
|
|
@ -136,5 +136,17 @@ class PartAssociation extends AbstractDBElement
|
||||||
return $this;
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -23,7 +23,9 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Entity\Parts\PartTraits;
|
namespace App\Entity\Parts\PartTraits;
|
||||||
|
|
||||||
|
use App\Entity\Parts\Part;
|
||||||
use App\Entity\Parts\PartAssociation;
|
use App\Entity\Parts\PartAssociation;
|
||||||
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use Doctrine\Common\Collections\Collection;
|
use Doctrine\Common\Collections\Collection;
|
||||||
use Symfony\Component\Validator\Constraints\Valid;
|
use Symfony\Component\Validator\Constraints\Valid;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
@ -89,4 +91,18 @@ trait AssociationTrait
|
||||||
{
|
{
|
||||||
return $this->associated_parts_as_other;
|
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()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -188,6 +188,15 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% endmacro %}
|
{% 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) %}
|
{% macro entity_preview_sm(entity) %}
|
||||||
{# @var entity \App\Entity\Contracts\HasMasterAttachmentInterface #}
|
{# @var entity \App\Entity\Contracts\HasMasterAttachmentInterface #}
|
||||||
{% if entity.masterPictureAttachment and entity.masterPictureAttachment.picture and attachment_manager.fileExisting(entity.masterPictureAttachment) %}
|
{% if entity.masterPictureAttachment and entity.masterPictureAttachment.picture and attachment_manager.fileExisting(entity.masterPictureAttachment) %}
|
||||||
|
|
40
templates/parts/info/_associations.html.twig
Normal file
40
templates/parts/info/_associations.html.twig
Normal 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 %}
|
|
@ -88,6 +88,17 @@
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
{% endif %}
|
{% 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 %}">
|
<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">
|
<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>
|
<i class="fas fa-history"></i>
|
||||||
|
@ -142,6 +153,12 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% 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">
|
<div class="tab-pane fade" id="projects" role="tabpanel" aria-labelledby="projects-tab">
|
||||||
{% include "parts/info/_projects.html.twig" %}
|
{% include "parts/info/_projects.html.twig" %}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -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>
|
<target>You can select here, how the chosen part is related to this part.</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</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>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue