Füge Baugruppen hinzu

This commit is contained in:
Marcel Diegelmann 2025-10-17 12:25:10 +02:00
parent 98b8c5b788
commit 5bd0741fba
128 changed files with 23830 additions and 109 deletions

View file

@ -0,0 +1,91 @@
{% import "helper.twig" as helper %}
<table class="table table-striped table-sm table-hover table-responsive-sm">
<thead>
<tr>
<th></th>
<th>{% trans %}attachment.name{% endtrans %}</th>
<th>{% trans %}attachment.attachment_type{% endtrans %}</th>
<th>{% trans %}attachment.file_name{% endtrans %}</th>
<th>{% trans %}attachment.file_size{% endtrans %}</th>
<th></th>
</tr>
</thead>
<tbody>
{% for attachment in assembly.attachments %}
<tr>
<td>
{% import "components/attachments.macro.html.twig" as attachments %}
{{ attachments.attachment_icon(attachment, attachment_manager) }}
</td>
<td class="align-middle">{{ attachment.name }}</td>
<td class="align-middle">{{ attachment.attachmentType.fullPath }}</td>
<td class="align-middle">
{% if attachment.hasInternal() %}
{{ attachment.filename }}
{% endif %}
</td>
<td class="align-middle h6">
{% if not attachment.hasInternal() %}
<span class="badge bg-primary">
<i class="fas fa-fw fa-globe"></i> {% trans %}attachment.external_only{% endtrans %}
</span>
{% elseif attachment_manager.internalFileExisting(attachment) %}
<span class="badge bg-secondary">
<i class="fas fa-hdd fa-fw"></i> {{ attachment_manager.humanFileSize(attachment) }}
</span>
{% else %}
<span class="badge bg-warning">
<i class="fas fa-exclamation-circle fa-fw"></i> {% trans %}attachment.file_not_found{% endtrans %}
</span>
{% endif %}
{% if attachment.secure %}
<br><span class="badge bg-success">
<i class="fas fa-fw fa-shield-alt"></i> {% trans %}attachment.secure{% endtrans %}
</span>
{% endif %}
{% if attachment == assembly.masterPictureAttachment %}
<br>
<span class="badge bg-primary">
<i class="fas fa-id-card"></i> {% trans %}attachment.preview{% endtrans %}
</span>
{% endif %}
</td>
<td><div class="btn-group" role="group" aria-label="">
<a {% if attachment.hasExternal() %}href="{{ attachment.externalPath }}"{% endif %} target="_blank"
class="btn btn-secondary {% if not attachment.hasExternal() %}disabled{% endif %}"
data-turbo="false" title="{% trans with {"%host%": attachment.host} %}attachment.view_external.view_at{% endtrans %}" rel="noopener">
<i class="fas fa-globe fa-fw"></i>
</a>
<a {% if attachment_manager.isInternalFileExisting(attachment) %}href="{{ entity_url(attachment, 'file_view') }}"{% endif %} target="_blank"
class="btn btn-secondary {% if not attachment_manager.isInternalFileExisting(attachment) or (attachment.secure and not is_granted("show_private", attachment)) %}disabled{% endif %}"
data-turbo="false" title="{% trans %}attachment.view_local{% endtrans %}" rel="noopener">
<i class="fas fa-eye fa-fw"></i>
</a>
<a {% if attachment_manager.isInternalFileExisting(attachment) %}href="{{ entity_url(attachment, 'file_download') }}"{% endif %} data-turbo="false"
class="btn btn-secondary {% if not attachment_manager.isInternalFileExisting(attachment) or (attachment.secure and not is_granted("show_private", attachment)) %}disabled{% endif %}"
title="{% trans %}attachment.download_local{% endtrans %}">
<i class="fas fa-download fa-fw"></i>
</a>
<div class="btn-group" role="group">
<button id="btnGroupDrop1" type="button" class="btn btn-secondary dropdown-toggle" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false" data-boundary="window">
</button>
<div class="dropdown-menu" aria-labelledby="btnGroupDrop1">
<span class="text-muted dropdown-item-text" ><i class="fas fa-lightbulb fa-fw"></i> <b>ID:</b> {{ attachment.iD }}</span>
<span class="text-muted dropdown-item-text" ><i class="fas fa-history fa-fw"></i> <b>{% trans %}lastModified{% endtrans %}:</b> {{ helper.entity_last_modified(attachment) }}</span>
<span class="text-muted dropdown-item-text" ><i class="fas fa-calendar-plus fa-fw"></i> <b>{% trans %}createdAt{% endtrans %}:</b> {{ helper.entity_created_at(attachment) }}</span>
</div>
</div>
</div></td>
</tr>
{% endfor %}
</tbody>
</table>

View file

@ -0,0 +1,72 @@
{% import "helper.twig" as helper %}
<div class="row mt-2">
<div class="col-md-8">
<div class="row">
<div class="col-md-3 col-lg-4 col-4 mt-auto mb-auto">
{% if assembly.masterPictureAttachment %}
<a href="{{ entity_url(assembly.masterPictureAttachment, 'file_view') }}" data-turbo="false" target="_blank" rel="noopener">
<img class="d-block w-100 img-fluid img-thumbnail bg-body-tertiary part-info-image" src="{{ entity_url(assembly.masterPictureAttachment, 'file_view') }}" alt="">
</a>
{% else %}
<img src="{{ asset('img/part_placeholder.svg') }}" class="img-fluid img-thumbnail bg-body-tertiary mb-2 " alt="Part main image" height="300" width="300">
{% endif %}
</div>
<div class="col-md-9 col-lg-8 col-7">
<h3 class="w-fit" title="{% trans %}name.label{% endtrans %}">{{ assembly.name }}
{# You need edit permission to use the edit button #}
{% if is_granted('edit', assembly) %}
<a href="{{ entity_url(assembly, 'edit') }}"><i class="fas fa-fw fa-sm fa-edit"></i></a>
{% endif %}
</h3>
<h6 class="text-muted w-fit" title="{% trans %}description.label{% endtrans %}"><span>{{ assembly.description|format_markdown(true) }}</span></h6>
</div>
</div>
</div>
<div class="col-md-4"> {# Sidebar panel with infos about last creation date, etc. #}
<div class="mb-3">
<span class="text-muted" title="{% trans %}lastModified{% endtrans %}">
<i class="fas fa-history fa-fw"></i> {{ helper.date_user_combination(assembly, true) }}
</span>
<br>
<span class="text-muted mt-1" title="{% trans %}createdAt{% endtrans %}">
<i class="fas fa-calendar-plus fa-fw"></i> {{ helper.date_user_combination(assembly, false) }}
</span>
</div>
<div class="mt-1">
<h6>
{{ helper.assemblies_status_to_badge(assembly.status) }}
</h6>
</div>
<div class="mt-1">
<h6>
<span class="badge badge-primary bg-primary">
<i class="fa-solid fa-list-check fa-fw"></i>
{{ assembly.bomEntries | length }}
{% trans %}assembly.info.bom_entries_count{% endtrans %}
</span>
</h6>
</div>
{% if assembly.children is not empty %}
<div class="mt-1">
<h6>
<span class="badge badge-primary bg-secondary">
<i class="fa-solid fa-folder-tree fa-fw"></i>
{{ assembly.children | length }}
{% trans %}assembly.info.sub_assemblies_count{% endtrans %}
</span>
</h6>
</div>
{% endif %}
</div>
{% if assembly.comment is not empty %}
<p>
<h5>{% trans %}comment.label{% endtrans %}:</h5>
{{ assembly.comment|format_markdown }}
</p>
{% endif %}
</div>

View file

@ -0,0 +1,118 @@
{% import "helper.twig" as helper %}
{% import "label_system/dropdown_macro.html.twig" as dropdown %}
{{ helper.breadcrumb_entity_link(assembly) }}
<div class="accordion mb-4" id="listAccordion">
<div class="accordion-item">
<div class="accordion-header">
<button class="accordion-button collapsed py-2" data-bs-toggle="collapse" data-bs-target="#entityInfo" aria-expanded="true">
{% if assembly.masterPictureAttachment is not null and attachment_manager.isFileExisting(assembly.masterPictureAttachment) %}
<img class="hoverpic ms-0 me-1 d-inline" {{ stimulus_controller('elements/hoverpic') }} data-thumbnail="{{ entity_url(assembly.masterPictureAttachment, 'file_view') }}" src="{{ attachment_thumbnail(assembly.masterPictureAttachment, 'thumbnail_sm') }}">
{% else %}
{{ helper.entity_icon(assembly, "me-1") }}
{% endif %}
{% trans %}assembly.label{% endtrans %}:&nbsp;<b>{{ assembly.name }}</b>
</button>
</div>
<div id="entityInfo" class="accordion-collapse collapse show" data-bs-parent="#listAccordion">
<div class="accordion-body">
{% if assembly.description is not empty %}
{{ assembly.description|format_markdown }}
{% endif %}
<div class="row">
<div class="col-sm-2">
<div class="nav flex-column nav-pills" id="v-pills-tab" role="tablist" aria-orientation="vertical">
<a class="nav-link active" id="v-pills-home-tab" data-bs-toggle="pill" href="#v-pills-home" role="tab" aria-controls="v-pills-home" aria-selected="true">
<i class="fas fa-info-circle fa-fw"></i>
{% trans %}entity.info.common.tab{% endtrans %}
</a>
<a class="nav-link" id="v-pills-statistics-tab" data-bs-toggle="pill" href="#v-pills-statistics" role="tab" aria-controls="v-pills-profile" aria-selected="false">
<i class="fas fa-chart-pie fa-fw"></i>
{% trans %}entity.info.statistics.tab{% endtrans %}
</a>
{% if assembly.attachments is not empty %}
<a class="nav-link" id="v-pills-attachments-tab" data-bs-toggle="pill" href="#v-pills-attachments" role="tab" aria-controls="v-pills-attachments" aria-selected="false">
<i class="fas fa-paperclip fa-fw"></i>
{% trans %}entity.info.attachments.tab{% endtrans %}
</a>
{% endif %}
{% if assembly.comment is not empty %}
<a class="nav-link" id="v-pills-comment-tab" data-bs-toggle="pill" href="#v-pills-comment" role="tab">
<i class="fas fa-comment-alt fa-fw"></i>
{% trans %}comment.label{% endtrans %}
</a>
{% endif %}
</div>
</div>
<div class="col-sm-10">
<div class="tab-content" id="v-pills-tabContent">
<div class="tab-pane fade show active" id="v-pills-home" role="tabpanel" aria-labelledby="v-pills-home-tab">
<div class="row">
<div class="col-sm-9 form-horizontal">
<div class="form-group">
<label class="col-sm-4">{% trans %}entity.info.name{% endtrans %}:</label>
<span class="col-sm form-control-static">{{ assembly.name }}</span>
</div>
<div class="form-group">
<label class="col-sm-4">{% trans %}entity.info.parent{% endtrans %}:</label>
<span class="col-sm form-control-static">
{% if assembly.parent %}
{{ assembly.parent.fullPath }}
{% else %}
-
{% endif %}
</span>
</div>
</div>
<div class="col-sm-3">
{% block quick_links %}{% endblock %}
<a class="btn btn-secondary w-100 mb-2" href="{{ entity_url(assembly, 'edit') }}">
<i class="fas fa-edit"></i> {% trans %}entity.edit.btn{% endtrans %}
</a>
<div class="">
<span class="text-muted" title="{% trans %}lastModified{% endtrans %}">
<i class="fas fa-history fa-fw"></i> {{ assembly.lastModified | format_datetime("short") }}
</span>
<br>
<span class="text-muted mt-1" title="{% trans %}createdAt{% endtrans %}">
<i class="fas fa-calendar-plus fa-fw"></i> {{ assembly.addedDate | format_datetime("short") }}
</span>
</div>
</div>
</div>
</div>
<div class="tab-pane fade" id="v-pills-statistics" role="tabpanel" aria-labelledby="v-pills-statistics-tab">
<div class="form-horizontal">
<div class="form-group">
<label class="col-sm-4">{% trans %}entity.info.children_count{% endtrans %}:</label>
<span class="col-sm form-control-static">{{ assembly.children | length }}</span>
</div>
<div class="form-group">
<label class="col-sm-4">{% trans %}entity.info.parts_count{% endtrans %}:</label>
<span class="col-sm form-control-static">{{ assembly.bomEntries | length }}</span>
</div>
</div>
</div>
{% if assembly.attachments is not empty %}
<div class="tab-pane fade" id="v-pills-attachments" role="tabpanel" aria-labelledby="v-pills-attachments-tab">
{% include "parts/info/_attachments_info.html.twig" with {"part": assembly} %}
</div>
{% endif %}
{% if assembly.comment is not empty %}
<div class="tab-pane fade" id="v-pills-comment" role="tabpanel" aria-labelledby="home-tab">
<div class="container-fluid mt-2 latex" data-controller="common--latex">
{{ assembly.comment|format_markdown }}
</div>
</div>
{% endif %}
</div>
</div>
</div>
</div>
</div>
</div>
</div>

View file

@ -0,0 +1,5 @@
{% import "components/datatables.macro.html.twig" as datatables %}
<div class="mb-2 mt-2"></div>
{{ datatables.datatable(datatable, 'elements/datatables/datatables', 'assemblies') }}

View file

@ -0,0 +1,28 @@
<table class="table table-striped table-hover">
<thead>
<tr>
<th>{% trans %}name.label{% endtrans %}</th>
<th>{% trans %}description.label{% endtrans %}</th>
<th># {% trans %}assembly.info.bom_entries_count{% endtrans %}</th>
<th># {% trans %}assembly.info.sub_assemblies_count{% endtrans %}</th>
</tr>
</thead>
<tbody>
{% for assembly in assembly.children %}
<tr>
<td> {# Name #}
<a href="{{ entity_url(assembly, 'info') }}">{{ assembly.name }}</a>
</td>
<td> {# Description #}
{{ assembly.description | format_markdown }}
</td>
<td>
{{ assembly.bomEntries | length }}
</td>
<td>
{{ assembly.children | length }}
</td>
</tr>
{% endfor %}
</tbody>
</table>

View file

@ -0,0 +1,135 @@
{% extends "main_card.html.twig" %}
{% import "helper.twig" as helper %}
{% block title %}
{% trans %}assembly.info.title{% endtrans %}: {{ assembly.name }}
{% endblock %}
{% block before_card %}
<div class="row mb-3">
<div class="col d-flex align-items-center">
<a href="{{ path('assembly_new') }}"
class="btn btn-success me-2 {% if not is_granted('@assemblies.create') %}disabled{% endif %}">
<i class="fas fa-plus-square fa-fw"></i>
{% trans %}assembly.new{% endtrans %}
</a>
<div class="btn-group">
<a class="btn btn-success" {% if not is_granted('@assemblies.edit') %}disabled{% endif %}
href="{{ path('assembly_add_parts', {"id": assembly.id, "_redirect": uri_without_host(app.request)}) }}">
<i class="fa-solid fa-square-plus fa-fw"></i>
{% trans %}assembly.info.bom_add_parts{% endtrans %}
</a>
<button type="button" class="btn btn-success dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false">
<span class="visually-hidden">Toggle Dropdown</span>
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item" href="{{ path('assembly_import_bom', {'id': assembly.id}) }}" {% if not is_granted('edit', assembly) %}disabled="disabled"{% endif %}>
<i class="fa-solid fa-file-import fa-fw"></i>
{% trans %}assembly.edit.bom.import_bom{% endtrans %}
</a>
</li>
</ul>
</div>
<a class="btn btn-secondary ms-2" {% if not is_granted('@assemblies.edit') %}disabled{% endif %}
href="{{ path('assembly_edit', {"id": assembly.id}) }}#part">
<i class="fa-solid fa-square-plus fa-cog"></i>
{% trans %}assembly_bom_entry.label{% endtrans %}
</a>
<a class="btn btn-secondary ms-2" {% if not is_granted('@assemblies.edit') %}disabled{% endif %}
href="{{ path('assembly_edit', {"id": assembly.id}) }}">
<i class="fa-solid fa-pencil"></i>
</a>
</div>
</div>
{% endblock %}
{% block content %}
{{ helper.breadcrumb_entity_link(assembly) }}
{{ parent() }}
{% endblock %}
{% block card_title %}
{% if assembly.masterPictureAttachment is not null and attachment_manager.isFileExisting(assembly.masterPictureAttachment) %}
<img class="hoverpic ms-0 me-1 d-inline" {{ stimulus_controller('elements/hoverpic') }} data-thumbnail="{{ entity_url(assembly.masterPictureAttachment, 'file_view') }}" src="{{ attachment_thumbnail(assembly.masterPictureAttachment, 'thumbnail_sm') }}">
{% else %}
{{ helper.entity_icon(assembly, "me-1") }}
{% endif %}
{% trans %}assembly.info.title{% endtrans %}:&nbsp;<b>{{ assembly.name }}</b>
{% endblock %}
{% block card_content %}
<ul class="nav nav-tabs" role="tablist">
<li class="nav-item" role="presentation">
<button class="nav-link active" id="info-tab" data-bs-toggle="tab" data-bs-target="#info-tab-pane"
type="button" role="tab" aria-controls="info-tab-pane" aria-selected="true">
<i class="fa-solid fa-circle-info fa-fw"></i>
{% trans %}assembly.info.info.label{% endtrans %}
</button>
</li>
{% if assembly.children is not empty %}
<li class="nav-item" role="presentation">
<button class="nav-link" id="subassemblies-tab" data-bs-toggle="tab" data-bs-target="#subassemblies-tab-pane"
type="button" role="tab" aria-controls="subassemblies-tab-pane" aria-selected="false">
<i class="fa-solid fa-folder-tree fa-fw"></i>
{% trans %}assembly.info.sub_assemblies.label{% endtrans %}
<span class="badge bg-secondary">{{ assembly.children | length }}</span>
</button>
</li>
{% endif %}
<li class="nav-item" role="presentation">
<button class="nav-link" id="part-tab" data-bs-toggle="tab" data-bs-target="#part-tab-pane"
type="button" role="tab" aria-controls="part-tab-pane" aria-selected="false">
<i class="fa-solid fa-list-check fa-fw"></i>
{% trans %}assembly_bom_entry.label{% endtrans %}
<span class="badge bg-secondary">{{ assembly.bomEntries | length }}</span>
</button>
</li>
{% if assembly.attachments is not empty %}
<li class="nav-item">
<a class="nav-link" id="attachments-tab" data-bs-toggle="tab"
data-bs-target="#attachments-tab-pane" role="tab">
<i class="fas fa-paperclip fa-fw"></i>
{% trans %}attachment.labelp{% endtrans %}
<span class="badge bg-secondary">{{ assembly.attachments | length }}</span>
</a>
</li>
{% endif %}
{% if assembly.parameters is not empty %}
<li class="nav-item">
<a class="nav-link" id="parameters-tab" data-bs-toggle="tab"
data-bs-target="#parameters-tab-pane" role="tab">
<i class="fas fa-atlas fa-fw"></i>
{% trans %}entity.info.parameters.tab{% endtrans %}
<span class="badge bg-secondary">{{ assembly.parameters | length }}</span>
</a>
</li>
{% endif %}
</ul>
<div class="tab-content">
<div class="tab-pane fade show active" id="info-tab-pane" role="tabpanel" aria-labelledby="info-tab" tabindex="0">
{% include "assemblies/info/_info.html.twig" %}
</div>
{% if assembly.children is not empty %}
<div class="tab-pane fade" id="subassemblies-tab-pane" role="tabpanel" aria-labelledby="bom-tab" tabindex="0">
{% include "assemblies/info/_subassemblies.html.twig" %}
</div>
{% endif %}
<div class="tab-pane fade" id="part-tab-pane" role="tabpanel" aria-labelledby="part-tab" tabindex="0">
{% include "assemblies/info/_part.html.twig" %}
</div>
<div class="tab-pane fade" id="attachments-tab-pane" role="tabpanel" aria-labelledby="attachments-tab" tabindex="0">
{% include "assemblies/info/_attachments_info.html.twig" with {"assembly": assembly} %}
</div>
<div class="tab-pane fade" id="parameters-tab-pane" role="tabpanel" aria-labelledby="parameters-tab">
{% for name, parameters in assembly.groupedParameters %}
{% if name is not empty %}<h5 class="mt-1">{{ name }}</h5>{% endif %}
{{ helper.parameters_table(assembly.parameters) }}
{% endfor %}
</div>
</div>
{% endblock %}